- Uses Node.js 26
- Reproducible npm installs from the committed lockfile
- Runs as a non-root user for enhanced security
- Multi-stage development, test, and production images
- Snyk dependency scanning and CodeQL security checks in CI
- Properly handles
SIGINTandSIGTERMevents with tini
With Node.js 26 installed:
npm ci
npm test
npm run lint
npm run devOr run the development container with live source mounts:
docker compose up --buildThis application is also available on Dockerhub.
To launch the container:
docker run -d -p 8080:8080 --name docker-node-app jonfairbanks/docker-node-app:latestTo verify its health:
curl --fail http://localhost:8080/healthzChanges merge into develop, then promote to the production branch master.
After the required checks pass, GitHub Actions publishes the production image
as jonfairbanks/docker-node-app:latest and an immutable commit tag.
The home cluster's Argo CD Image Updater follows latest, records its digest
in Git automatically, and Argo CD rolls the deployment. App-only releases need
no manual cluster-state edit or Helm chart version bump. The develop image
tag is kept separate from production.
You can find this app on Helm!
This application can also be helpful verifying Kubernetes:
- Scaling and Downtime Mitigation
- Cluster Load Balancing
- Request IP Passthrough
Validate or install the bundled chart with Helm 3:
helm lint chart
helm upgrade --install docker-node-app chartThe chart sets the pod timezone to America/Los_Angeles. Override it with an
IANA timezone name when deploying elsewhere:
helm upgrade --install docker-node-app chart --set timezone=Europe/LondonFor testing that pods are balancing correctly, you can make multiple requests to your app to verify.
To make 50 requests and write them to a file, you can run the following with your endpoint:
for run in {1..50}; do curl -sSL -D - docker-node-app.local -o /dev/null | grep X-Hostname; doneSIGTERM and SIGINT mark the app draining and stop accepting new connections
without waiting for a readiness probe. Active requests have up to
SHUTDOWN_TIMEOUT_MS (25000 milliseconds) to finish. Duplicate signals share
the same drain; exceeding the deadline forces connections closed and exits
with a nonzero status.
Readiness returns 503 while draining. Liveness continues to report the running process as healthy while active requests finish.
Allow enough pod termination time for any pre-stop hook, the drain deadline,
and a safety margin. A five-second pre-stop hook and 25-second drain fit within
a 40-second grace period. Configure the hook and grace period through the
chart's lifecycle and terminationGracePeriodSeconds values.
