Skip to main content

Assignment 1: Containerize an app and push it to the registry

Goal: Take a small application, write a house-style Dockerfile for it, build a small and secure image, and push that image to the lab's private registry at 10.100.100.6 — then prove it runs from the registry copy.

Where: Any lab VM that has Docker installed (Docker was installed via get.docker.com). The private registry is registry:2 with htpasswd auth at 10.100.100.6. Get your registry username/password from your mentor.

Tasks

  1. Pick or write a tiny web app that listens on a port and serves an HTTP response (a "hello" web server in any language is fine — Node, Python, or Go). It must expose a /health endpoint returning HTTP 200.
  2. Initialise a git repo for it (git init) so you have a commit SHA to tag with.
  3. Write a .dockerignore that excludes at least .git, build artifacts/dependencies (e.g. node_modules), logs, and any .env.
  4. Write a multi-stage Dockerfile that follows every house convention:
    • a pinned base image (specific tag, ideally a digest),
    • a separate build stage and a slim runtime stage,
    • a non-root runtime USER,
    • an EXPOSE for the app port,
    • a HEALTHCHECK that curls /health,
    • a CMD to start the app.
  5. Build the image with a sha-based tag: 10.100.100.6/<yourname>/<app>:sha-<shortsha>.
  6. Run it locally and confirm: docker run -d -p 8080:<port> ..., then curl http://localhost:8080/health returns 200. Check docker logs.
  7. docker login 10.100.100.6, then docker push your tagged image.
  8. Remove the local image (docker rmi), docker pull it back from 10.100.100.6, run it again, and confirm /health still returns 200 — proving the registry copy works.

Deliverable

A short writeup (paste into your BookStack notes or a markdown file) containing: the app's Dockerfile, the .dockerignore, the exact build/login/push commands you ran with their tags, the docker images line showing your final image size, and the curl output from the registry-pulled container.

Acceptance criteria — you're done when:

  • The app exposes a working /health endpoint returning HTTP 200.
  • A .dockerignore exists and excludes .git, dependencies/build output, logs, and .env.
  • The Dockerfile uses a multi-stage build with a slim runtime stage.
  • The base image is pinned (specific tag or digest), not latest.
  • The container runs as a non-root USER (verify with docker exec <c> whoami — not root).
  • A HEALTHCHECK is present and docker ps shows the container as healthy.
  • The image is tagged 10.100.100.6/<yourname>/<app>:sha-<shortsha> (sha-based, no latest).
  • docker push to 10.100.100.6 succeeded.
  • After docker rmi + docker pull from the registry, the pulled container serves /health with HTTP 200.

Hints

  • Re-read Chapter 5 section 3 if rebuilds feel slow — order matters for caching.
  • docker exec <container> whoami is the quickest way to confirm you are non-root.
  • docker ps shows (healthy) next to the container once the HEALTHCHECK passes; if it is unhealthy, run the healthcheck command manually inside the container with docker exec to see the error.
  • If docker push is denied, you likely skipped docker login 10.100.100.6 or used the wrong namespace.
  • If docker login fails on TLS, ask your mentor whether the registry needs an insecure-registries entry in the Docker daemon config — do not guess.
  • Get the short SHA with git rev-parse --short HEAD.

Blocked for >~30 min after re-reading the lessons? Bring what you've tried to your mentor.