Write a Dockerfile with Sensible Runtime Defaults
In this challenge, you will write a Dockerfile for a simple web service and learn how Docker images can improve the application startup UX by defining sensible runtime defaults.
In Docker, many runtime parameters can be provided when starting (or stopping) a container:
environment variables, the runtime user, and even the signal sent to the application to stop it.
However, one of the biggest UX improvements Docker brought was the ability to bake sensible defaults into the image itself.
That way, a simple docker run <image> is often enough to start the application correctly,
and an argumentless docker stop <container> is enough to shut it down gracefully.
Explore the application
The application you need to package is located in the ~/service/ directory.
It's a Node.js HTTP service that uses only built-in modules - no external dependencies needed.
Take a moment to explore the code and see how it works:
cd ~/service
cat index.js
The service starts an HTTP server on the port defined by the PORT env var and uses
a couple of runtime parameters to control its behavior - LOG_LEVEL and ENVIRONMENT.
The task
Your job is to package the service into a container image so that these parameters have sensible defaults baked into the image itself.
The image should define:
- Default environment variables for the application configuration:
PORT=8080LOG_LEVEL=debugENVIRONMENT=development
- A non-root user for running the service
- A stop signal that allows the application to shut down gracefully
Create a Dockerfile in the ~/service/ directory and build a container image named service:v1.0.0.
Dockerizing Node.js applications
For a refresher on how to Dockerize a Node.js application, check out the Write Your First Dockerfile challenge.
The final image should be prepared in such a way that a plain docker run command
is enough to start a fully configured service:
docker run -p 8080:8080 service:v1.0.0
Once the container is running, you should be able to inspect the service with:
curl localhost:8080
The response should reflect the default configuration baked into the image and show that the application is running under a non-root user.
Setting default environment variables
The ENV instruction sets environment variables that persist in the image
and are available to the running container:
ENV MY_VAR=my_value
Note that these defaults can still be overridden at runtime with docker run -e flag(s).
Running as a non-root user
The typical way to run a container as a non-root user is to create a system user and switch to it.
Use a RUN instruction to create a system user and then the USER instruction to switch to it:
RUN addgroup --system mygroup && \
adduser --system --ingroup mygroup myuser
USER myuser
However, some base images can already have a non-root user.
For instance, the node:24-slim image has a node user, which you can use a shortcut instead of creating a new one:
USER node
When the container is stopped with the usual docker stop command,
the application should be able to shut down gracefully.
What signal does docker stop send?
By default, docker stop sends SIGTERM to the container's main process.
However, some applications handle a different signal for graceful shutdown.
The STOPSIGNAL instruction in a Dockerfile lets you change which signal
docker stop sends:
STOPSIGNAL <signal>
Check the application code to see which signal it handles for shutdown.