Add Snap Docker support to install-docker-agent.sh
Snap-installed Docker does not automatically create a docker group, causing permission denied errors when the pulse-docker service user tries to access /var/run/docker.sock. Changes: - Auto-detect Snap Docker installations - Create docker group if missing when Snap Docker is detected - Restart Snap Docker after group creation to refresh socket ACLs - Add socket access validation before starting the service - Handle symlinked Docker sockets in systemd unit ReadWritePaths - Document troubleshooting steps in DOCKER_MONITORING.md
This commit is contained in:
parent
68049e0fb3
commit
92a5d74ba9
2 changed files with 176 additions and 1 deletions
|
|
@ -271,6 +271,21 @@ Need the alerts but at a different tone? The same Containers tab exposes global
|
||||||
|
|
||||||
**Fix:** Open **Settings → Docker → Removed Hosts**, locate the entry, and click **Allow re-enroll**. Then restart the agent or rerun the install script. If the install script runs with a token that includes the `docker:manage` scope it will automatically clear the removal block.
|
**Fix:** Open **Settings → Docker → Removed Hosts**, locate the entry, and click **Allow re-enroll**. Then restart the agent or rerun the install script. If the install script runs with a token that includes the `docker:manage` scope it will automatically clear the removal block.
|
||||||
|
|
||||||
|
### Snap-installed Docker permission issues
|
||||||
|
|
||||||
|
**Symptom:** Install script completes successfully but the agent service fails with `permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock`. The install script may have shown `[WARN] docker group not found`.
|
||||||
|
|
||||||
|
**Cause:** Docker installed via Snap does not automatically create a system `docker` group, preventing the `pulse-docker` service user from accessing `/var/run/docker.sock`.
|
||||||
|
|
||||||
|
**Fix:** The install script now automatically detects Snap Docker and creates the docker group when needed. If you previously installed with an older version of the script:
|
||||||
|
|
||||||
|
1. Create the docker group: `sudo addgroup --system docker`
|
||||||
|
2. Add the service user to the group: `sudo adduser pulse-docker docker`
|
||||||
|
3. Restart Snap Docker to refresh socket ACLs: `sudo snap restart docker`
|
||||||
|
4. Restart the agent service: `sudo systemctl restart pulse-docker-agent`
|
||||||
|
|
||||||
|
Verify socket access with: `sudo -u pulse-docker docker version`
|
||||||
|
|
||||||
## Removing the agent
|
## Removing the agent
|
||||||
|
|
||||||
Stop the systemd service or container and remove the binary. Pulse retains the last reported state until it ages out after a few minutes of inactivity.
|
Stop the systemd service or container and remove the binary. Pulse retains the last reported state until it ages out after a few minutes of inactivity.
|
||||||
|
|
|
||||||
|
|
@ -415,12 +415,54 @@ ensure_service_home() {
|
||||||
chmod 750 "$SERVICE_HOME" >/dev/null 2>&1 || true
|
chmod 750 "$SERVICE_HOME" >/dev/null 2>&1 || true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detect_snap_docker() {
|
||||||
|
SNAP_DOCKER_DETECTED="false"
|
||||||
|
|
||||||
|
# Check if the active docker binary resolves to a snap path
|
||||||
|
if command -v docker >/dev/null 2>&1; then
|
||||||
|
local docker_path
|
||||||
|
docker_path=$(readlink -f "$(command -v docker)" 2>/dev/null || echo "")
|
||||||
|
if [[ "$docker_path" == /snap/* ]] || [[ "$docker_path" == /var/lib/snapd/snap/* ]]; then
|
||||||
|
SNAP_DOCKER_DETECTED="true"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
ensure_docker_group_membership() {
|
ensure_docker_group_membership() {
|
||||||
SYSTEMD_SUPPLEMENTARY_GROUPS_LINE=""
|
SYSTEMD_SUPPLEMENTARY_GROUPS_LINE=""
|
||||||
if [[ "$SERVICE_USER_ACTUAL" == "root" ]]; then
|
if [[ "$SERVICE_USER_ACTUAL" == "root" ]]; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Detect Snap Docker installation
|
||||||
|
detect_snap_docker
|
||||||
|
|
||||||
|
# If docker group doesn't exist and Snap Docker is detected, create it
|
||||||
|
if ! getent group docker >/dev/null 2>&1; then
|
||||||
|
if [[ "$SNAP_DOCKER_DETECTED" == "true" ]]; then
|
||||||
|
log_info "Snap-installed Docker detected without docker group; creating system docker group"
|
||||||
|
if command -v addgroup >/dev/null 2>&1; then
|
||||||
|
if addgroup --system docker >/dev/null 2>&1; then
|
||||||
|
log_success "Created docker system group for Snap Docker"
|
||||||
|
SNAP_DOCKER_GROUP_CREATED="true"
|
||||||
|
else
|
||||||
|
log_warn "Failed to create docker group; socket access may fail"
|
||||||
|
fi
|
||||||
|
elif command -v groupadd >/dev/null 2>&1; then
|
||||||
|
if groupadd -r docker >/dev/null 2>&1; then
|
||||||
|
log_success "Created docker system group for Snap Docker"
|
||||||
|
SNAP_DOCKER_GROUP_CREATED="true"
|
||||||
|
else
|
||||||
|
log_warn "Failed to create docker group; socket access may fail"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_warn "Unable to create docker group; ensure $SERVICE_USER_ACTUAL can access /var/run/docker.sock"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_warn "docker group not found; ensure the agent user can access /var/run/docker.sock"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if getent group docker >/dev/null 2>&1; then
|
if getent group docker >/dev/null 2>&1; then
|
||||||
DOCKER_GROUP_PRESENT="true"
|
DOCKER_GROUP_PRESENT="true"
|
||||||
if ! id -nG "$SERVICE_USER_ACTUAL" 2>/dev/null | tr ' ' '\n' | grep -Fxq "docker"; then
|
if ! id -nG "$SERVICE_USER_ACTUAL" 2>/dev/null | tr ' ' '\n' | grep -Fxq "docker"; then
|
||||||
|
|
@ -431,11 +473,29 @@ ensure_docker_group_membership() {
|
||||||
else
|
else
|
||||||
log_warn "Unable to manage docker group membership; ensure $SERVICE_USER_ACTUAL can access /var/run/docker.sock"
|
log_warn "Unable to manage docker group membership; ensure $SERVICE_USER_ACTUAL can access /var/run/docker.sock"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Verify group membership was actually applied
|
||||||
|
if ! id -nG "$SERVICE_USER_ACTUAL" 2>/dev/null | tr ' ' '\n' | grep -Fxq "docker"; then
|
||||||
|
log_warn "Failed to verify docker group membership for $SERVICE_USER_ACTUAL"
|
||||||
|
log_warn "Group changes may not have taken effect; socket access validation will catch this"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if id -nG "$SERVICE_USER_ACTUAL" 2>/dev/null | tr ' ' '\n' | grep -Fxq "docker"; then
|
if id -nG "$SERVICE_USER_ACTUAL" 2>/dev/null | tr ' ' '\n' | grep -Fxq "docker"; then
|
||||||
SYSTEMD_SUPPLEMENTARY_GROUPS_LINE="SupplementaryGroups=docker"
|
SYSTEMD_SUPPLEMENTARY_GROUPS_LINE="SupplementaryGroups=docker"
|
||||||
log_success "Ensured docker group access for $SERVICE_USER_ACTUAL"
|
log_success "Ensured docker group access for $SERVICE_USER_ACTUAL"
|
||||||
|
|
||||||
|
# If we created the group for Snap Docker, restart the snap to refresh socket ACLs
|
||||||
|
if [[ "$SNAP_DOCKER_DETECTED" == "true" && "$SNAP_DOCKER_GROUP_CREATED" == "true" ]]; then
|
||||||
|
if command -v snap >/dev/null 2>&1; then
|
||||||
|
log_info "Restarting Snap Docker to apply group permissions"
|
||||||
|
if snap restart docker >/dev/null 2>&1; then
|
||||||
|
log_success "Snap Docker restarted successfully"
|
||||||
|
else
|
||||||
|
log_warn "Failed to restart Snap Docker; socket permissions may not apply until manual restart"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
log_warn "Service user $SERVICE_USER_ACTUAL is not in docker group; ensure the Docker socket ACL grants access."
|
log_warn "Service user $SERVICE_USER_ACTUAL is not in docker group; ensure the Docker socket ACL grants access."
|
||||||
fi
|
fi
|
||||||
|
|
@ -481,6 +541,19 @@ write_env_file() {
|
||||||
log_success "Wrote environment file: $target"
|
log_success "Wrote environment file: $target"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detect_docker_socket_paths() {
|
||||||
|
DOCKER_SOCKET_PATHS="/var/run/docker.sock"
|
||||||
|
|
||||||
|
# If /var/run/docker.sock is a symlink, include the real path too
|
||||||
|
if [[ -L /var/run/docker.sock ]]; then
|
||||||
|
local target
|
||||||
|
target=$(readlink -f /var/run/docker.sock 2>/dev/null || echo "")
|
||||||
|
if [[ -n "$target" && "$target" != "/var/run/docker.sock" ]]; then
|
||||||
|
DOCKER_SOCKET_PATHS="/var/run/docker.sock $target"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
configure_polkit_rule() {
|
configure_polkit_rule() {
|
||||||
if [[ "$SERVICE_USER_ACTUAL" == "root" ]]; then
|
if [[ "$SERVICE_USER_ACTUAL" == "root" ]]; then
|
||||||
return
|
return
|
||||||
|
|
@ -521,6 +594,76 @@ EOF
|
||||||
log_success "Configured polkit rule allowing $SERVICE_USER_ACTUAL to manage pulse-docker-agent service"
|
log_success "Configured polkit rule allowing $SERVICE_USER_ACTUAL to manage pulse-docker-agent service"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validate_docker_socket_access() {
|
||||||
|
if [[ "$SERVICE_USER_ACTUAL" == "root" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_header 'Validating Docker socket access'
|
||||||
|
|
||||||
|
# Source the env file to test with the exact configuration the service will use
|
||||||
|
if [[ -f "$ENV_FILE" ]]; then
|
||||||
|
set -a
|
||||||
|
source "$ENV_FILE" 2>/dev/null || true
|
||||||
|
set +a
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If we just restarted Snap Docker, give it a moment to come back up
|
||||||
|
if [[ "$SNAP_DOCKER_DETECTED" == "true" && "$SNAP_DOCKER_GROUP_CREATED" == "true" ]]; then
|
||||||
|
log_info "Waiting for Snap Docker to restart"
|
||||||
|
sleep 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build env prefix for sudo (portable across sudo variants)
|
||||||
|
local env_prefix=""
|
||||||
|
[[ -n "${DOCKER_HOST:-}" ]] && env_prefix+="DOCKER_HOST='$DOCKER_HOST' "
|
||||||
|
[[ -n "${PULSE_URL:-}" ]] && env_prefix+="PULSE_URL='$PULSE_URL' "
|
||||||
|
[[ -n "${PULSE_TOKEN:-}" ]] && env_prefix+="PULSE_TOKEN='$PULSE_TOKEN' "
|
||||||
|
[[ -n "${PULSE_TARGETS:-}" ]] && env_prefix+="PULSE_TARGETS='$PULSE_TARGETS' "
|
||||||
|
|
||||||
|
# Test socket access
|
||||||
|
local test_output
|
||||||
|
local test_exitcode
|
||||||
|
test_output=$(eval "env $env_prefix sudo -u $SERVICE_USER_ACTUAL docker version --format '{{.Server.Version}}'" 2>&1)
|
||||||
|
test_exitcode=$?
|
||||||
|
|
||||||
|
if [[ $test_exitcode -eq 0 ]]; then
|
||||||
|
log_success "Docker socket access confirmed for $SERVICE_USER_ACTUAL"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validation failed
|
||||||
|
log_warn "Docker socket access test failed for $SERVICE_USER_ACTUAL"
|
||||||
|
echo "" >&2
|
||||||
|
echo "Validation output:" >&2
|
||||||
|
echo "$test_output" >&2
|
||||||
|
echo "" >&2
|
||||||
|
|
||||||
|
if [[ "$SNAP_DOCKER_DETECTED" == "true" ]]; then
|
||||||
|
echo "Snap-installed Docker detected. Common solutions:" >&2
|
||||||
|
echo " 1. Ensure the docker group exists: getent group docker" >&2
|
||||||
|
echo " 2. Ensure $SERVICE_USER_ACTUAL is in the docker group: id -nG $SERVICE_USER_ACTUAL" >&2
|
||||||
|
echo " 3. Check if Snap Docker is running: snap services docker.dockerd" >&2
|
||||||
|
echo " 4. Restart Snap Docker to refresh permissions: snap restart docker" >&2
|
||||||
|
else
|
||||||
|
echo "Common solutions:" >&2
|
||||||
|
echo " 1. Ensure $SERVICE_USER_ACTUAL is in the docker group: id -nG $SERVICE_USER_ACTUAL" >&2
|
||||||
|
echo " 2. Check Docker socket permissions: ls -la /var/run/docker.sock" >&2
|
||||||
|
echo " 3. Verify Docker is running: docker ps" >&2
|
||||||
|
fi
|
||||||
|
echo "" >&2
|
||||||
|
|
||||||
|
read -p "Continue with installation anyway? (y/N) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
echo "Installation aborted. Fix socket access and re-run the installer." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_warn "Proceeding despite failed validation; service may not start correctly"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
remove_polkit_rule() {
|
remove_polkit_rule() {
|
||||||
local polkit_dir="/etc/polkit-1/rules.d"
|
local polkit_dir="/etc/polkit-1/rules.d"
|
||||||
local rule_path="${polkit_dir}/90-pulse-docker-agent.rules"
|
local rule_path="${polkit_dir}/90-pulse-docker-agent.rules"
|
||||||
|
|
@ -734,6 +877,9 @@ SERVICE_USER_CREATED="false"
|
||||||
SERVICE_USER_AVAILABLE="true"
|
SERVICE_USER_AVAILABLE="true"
|
||||||
DOCKER_GROUP_PRESENT="false"
|
DOCKER_GROUP_PRESENT="false"
|
||||||
SYSTEMD_SUPPLEMENTARY_GROUPS_LINE=""
|
SYSTEMD_SUPPLEMENTARY_GROUPS_LINE=""
|
||||||
|
SNAP_DOCKER_DETECTED="false"
|
||||||
|
SNAP_DOCKER_GROUP_CREATED="false"
|
||||||
|
DOCKER_SOCKET_PATHS="/var/run/docker.sock"
|
||||||
|
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
|
|
@ -1643,6 +1789,17 @@ ensure_service_home
|
||||||
ensure_docker_group_membership
|
ensure_docker_group_membership
|
||||||
write_env_file
|
write_env_file
|
||||||
configure_polkit_rule
|
configure_polkit_rule
|
||||||
|
detect_docker_socket_paths
|
||||||
|
|
||||||
|
# Build ReadWritePaths line for systemd unit
|
||||||
|
SYSTEMD_READ_WRITE_PATHS=""
|
||||||
|
for socket_path in $DOCKER_SOCKET_PATHS; do
|
||||||
|
if [[ -n "$SYSTEMD_READ_WRITE_PATHS" ]]; then
|
||||||
|
SYSTEMD_READ_WRITE_PATHS="$SYSTEMD_READ_WRITE_PATHS $socket_path"
|
||||||
|
else
|
||||||
|
SYSTEMD_READ_WRITE_PATHS="$socket_path"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# Create systemd service
|
# Create systemd service
|
||||||
log_header 'Configuring systemd service'
|
log_header 'Configuring systemd service'
|
||||||
|
|
@ -1677,7 +1834,7 @@ ProtectKernelLogs=yes
|
||||||
LockPersonality=yes
|
LockPersonality=yes
|
||||||
MemoryDenyWriteExecute=yes
|
MemoryDenyWriteExecute=yes
|
||||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
||||||
ReadWritePaths=/var/run/docker.sock
|
ReadWritePaths=$SYSTEMD_READ_WRITE_PATHS
|
||||||
ProtectHostname=yes
|
ProtectHostname=yes
|
||||||
ProtectClock=yes
|
ProtectClock=yes
|
||||||
|
|
||||||
|
|
@ -1687,6 +1844,9 @@ EOF
|
||||||
|
|
||||||
log_success "Wrote unit file: $SERVICE_PATH"
|
log_success "Wrote unit file: $SERVICE_PATH"
|
||||||
|
|
||||||
|
# Validate socket access before starting the service
|
||||||
|
validate_docker_socket_access
|
||||||
|
|
||||||
# Reload systemd and start service
|
# Reload systemd and start service
|
||||||
log_info 'Starting service'
|
log_info 'Starting service'
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue