Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ make build_scratch_multi

- `base.alpine/` - Alpine runtime image
- `Dockerfile` - image definition
- `files/init.sh` - entrypoint script, handles timezone and UID setup, drops to app user
- `files/init.sh` - entrypoint script, handles timezone, UID, and docker GID setup, drops to app user
- `files/init-root.sh` - alternative entrypoint for root execution
- `base.scratch/` - Scratch runtime image (builds /nop wait program from C)
- `build.go/` - Go build image
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,25 @@ The container can be customized in runtime by setting environment from docker's

- `TIME_ZONE` - set container's TZ, default "America/Chicago". For scratch-based `TZ` should be used instead
- `APP_UID` - UID of internal `app` user, default 1001
- `DOCKER_GID` - GID of the docker group, default 999. Useful when mounting docker socket with a different GID on the host

### Working with Docker from inside container

The `app` user is a member of the `docker` group. That allows it to interact with the Docker socket (`/var/run/docker.sock`) when it is explicitly mounted into the container. This is particularly useful for advanced use cases that require such functionality, such as monitoring other containers or accessing Docker APIs.

Under standard usage, the Docker socket is not mounted into the container. In such cases, the docker group membership does not grant the app user any elevated privileges. The container remains secure and operates with an unprivileged user.

When the host's docker group has a different GID than the container's default (999), set `DOCKER_GID` to match the host's GID:

```bash
# find your host docker GID
stat -c %g /var/run/docker.sock # Linux
stat -f %g /var/run/docker.sock # macOS

# run with matching GID
docker run -e DOCKER_GID=998 -v /var/run/docker.sock:/var/run/docker.sock <image>
```

Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GID collision handling (lines 27-33) adds the app user to an existing group with the requested GID rather than to the docker group. While this correctly achieves socket access through matching GIDs, this behavior might be unexpected to users who assume the app user will always be in the docker group. Consider adding a note to the README documentation explaining that in case of GID collisions, the app user will be added to the existing group with that GID instead of recreating the docker group.

Suggested change
**Note on GID collisions**: If a group with the requested `DOCKER_GID` already exists inside the container, the `app` user will be added to that existing group instead of creating or renaming a group explicitly called `docker`. Socket access is still granted via the matching GID, but the group name may differ from `docker`.

Copilot uses AI. Check for mistakes.
#### Security Implications

Mounting the Docker socket into a container can pose a security risk, as it effectively grants the container access to the Docker host and its containers. This is not specific to this image but is a general consideration when working with Docker.
Expand Down
29 changes: 29 additions & 0 deletions base.alpine/files/init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,35 @@ if [[ ${uid} -eq 0 ]]; then
else
echo "custom APP_UID not defined, using default uid=1001"
fi

# set GID for docker group
if [[ "${DOCKER_GID}" -ne "999" ]]; then
echo "set custom DOCKER_GID=${DOCKER_GID}"
# check if another group already uses this GID
existing_group=$(getent group "${DOCKER_GID}" | cut -d: -f1)
if [[ -n "${existing_group}" && "${existing_group}" != "docker" ]]; then
# reuse existing group - add app to it for socket access
echo "GID ${DOCKER_GID} used by '${existing_group}', adding app to it"
if ! addgroup app "${existing_group}"; then
echo "error: failed to add app user to group '${existing_group}'"
exit 1
fi
else
# no collision - create docker group with requested GID
delgroup docker 2>/dev/null || true
if ! addgroup -g "${DOCKER_GID}" docker; then
echo "error: failed to create docker group with GID=${DOCKER_GID}"
exit 1
fi
if ! addgroup app docker; then
echo "error: failed to add app user to docker group"
exit 1
fi
fi
else
echo "custom DOCKER_GID not defined, using default gid=999"
fi

chown -R app:app /srv /home/app
fi

Expand Down