This document summarizes the Docker experiments done for this repo and converts them into a repeatable workflow for debugging local image builds and GHCR images.
- Build and test the app image from local source.
- Compare behavior with the published image from GHCR.
- Quickly diagnose common failures (container startup, shell access, port exposure, env setup).
- The image is Alpine-based, so use /bin/sh, not /bin/bash.
- Use docker rm (or docker container rm) to remove containers. Commands like docker delete, docker destroy, or docker remove do not exist.
- To pass host binding correctly, use HOST=0.0.0.0 (equal sign), not HOST:0.0.0.0.
- Port mapping is required for host access: -p 3000:3000.
- Supplying .env values is required for realistic startup testing.
- Testing both local and GHCR images with the same runtime flags makes behavior comparisons easier.
- Docker is installed and running.
- A valid .env file exists at repo root.
- You are in repo root.
Build the local image:
docker build -t safe-settings:local .Run container in foreground with explicit runtime env and port mapping:
docker run --name safe-settings-local \
--env-file ./.env \
--env NODE_ENV=development \
--env HOST=0.0.0.0 \
-p 3000:3000 \
-it safe-settings:localIf startup fails, inspect logs:
docker logs safe-settings-localShell into running container for investigation:
docker exec -it safe-settings-local /bin/shClean up:
docker rm -f safe-settings-localPull published image:
docker pull ghcr.io/github/safe-settings:2.1.19Run with the same env and port flags used for local testing:
docker run --name safe-settings-ghcr \
--env-file ./.env \
--env NODE_ENV=development \
--env HOST=0.0.0.0 \
-p 3000:3000 \
-it ghcr.io/github/safe-settings:2.1.19Inspect logs:
docker logs safe-settings-ghcrDebug inside container:
docker exec -it safe-settings-ghcr /bin/shClean up:
docker rm -f safe-settings-ghcrUse this when one image works and the other does not.
- Run both images with identical flags (env, HOST, port mapping).
- Compare startup logs side-by-side.
- Compare environment inside each container:
docker exec -it safe-settings-local /bin/sh -c 'env | sort'
docker exec -it safe-settings-ghcr /bin/sh -c 'env | sort'- Confirm app process is listening on expected port inside container:
docker exec -it safe-settings-local /bin/sh -c 'netstat -lntp 2>/dev/null || ss -lntp'
docker exec -it safe-settings-ghcr /bin/sh -c 'netstat -lntp 2>/dev/null || ss -lntp'- Validate host reachability:
curl -i http://localhost:3000/Symptom: container exits immediately. Likely causes:
- Missing required variables in .env.
- Invalid app credentials. Checks:
- docker logs
- Confirm .env has required app settings.
Symptom: cannot connect from host to localhost:3000. Likely causes:
- Missing -p 3000:3000.
- App not binding to all interfaces. Checks:
- Ensure HOST=0.0.0.0 is set.
- Ensure port mapping is present.
Symptom: cannot shell into container with bash. Likely cause:
- Alpine image does not include bash. Fix:
- Use /bin/sh.
Symptom: name conflict when re-running tests. Likely cause:
- Old container still exists. Fix:
- docker rm -f
Local:
docker build -t safe-settings:local . && \
docker run --rm --name safe-settings-local \
--env-file ./.env \
--env NODE_ENV=development \
--env HOST=0.0.0.0 \
-p 3000:3000 \
-it safe-settings:localGHCR:
docker pull ghcr.io/github/safe-settings:2.1.19 && \
docker run --rm --name safe-settings-ghcr \
--env-file ./.env \
--env NODE_ENV=development \
--env HOST=0.0.0.0 \
-p 3000:3000 \
-it ghcr.io/github/safe-settings:2.1.19