When we build this file, we expect the index.html file to be copied to the /var/www/html directory within the container filesystem. Let’s have a look:
$ docker build -t <your_dockerhub_user>/nginx-hello-world .
[+] Building 1.6s (10/10) FINISHED
=> [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 211B 0.0s => [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/ubuntu:bionic 1.4s => [1/5] FROM docker.io/library/ubuntu:bionic@sha256:152dc042… 0.0s => [internal] load build context 0.0s => => transferring context: 81B 0.0s
=> CACHED [2/5] RUN apt update && apt install -y curl 0.0s => CACHED [3/5] RUN apt update && apt install -y nginx 0s => [4/5] WORKDIR /var/www/html/ 0.0s => [5/5] ADD index.html ./ 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:cb2e67bd… 0.0s
=> => naming to docker.io/<your_dockerhub_user>/nginx-hello-world
This time, the build was much faster! When we executed the Docker build, it used a lot of layers from
the cache. That is one of the advantages of layered architecture; you only build the changing part and use the existing one the way it is.
Tip
Always add source code after installing packages and dependencies. The source code changes frequently and the packages more or less remain the same. This will result in faster builds and save a lot of CI/CD time.
Let’s rerun the container and see what we get. Note that you need to remove the old container before doing so:
$ docker ps | ||||||
CONTAINER ID | IMAGE | COMMAND | CREATED | STATUS | PORTS | NAMES |
092374c45015 | <your_dockerhub | “nginx -g | 28 seconds | Up 27 | 0.0.0.0:80->80/ | loving_ |
_user>/nginx- | ‘daemon of…” | ago | seconds | tcp, :::80->80/tcp | noether | |
hello-world |
$ docker rm 092374c45015 -f
092374c45015
At this point, we can’t see the container anymore. Now, let’s rerun the container using the following command:
$ docker run -d -p 80:80 <your_dockerhub_user>/nginx-hello-world cc4fe116a433c505ead816fd64350cb5b25c5f3155bf5eda8cede5a4…
$ docker ps | ||||||
CONTAINER ID | IMAGE | COMMAND | CREATED | STATUS | PORTS | NAMES |
cc4fe116a433 | <your_dockerhub | “nginx -g | 52 seconds | Up 50 | 0.0.0.0:80->80/ | eager_ |
_user>/nginx- | ‘daemon of…” | ago | seconds | tcp, :::80->80/tcp | gates | |
hello-world |
Here, we can see that the container is up and running. Let’s use curl localhost to see what we get:
$ curl localhost
Hello World! This is my first docker image!
Here, we get a custom message instead of the default NGINX HTML response!
This looks goodenough for now, but I will discuss a few more directives to make this image more reliable. First, we haven’t explicitly documented what port this container should expose. This works perfectly fine, as we know that NGINX runs on port 80, but what if someone wants to use your image and doesn’t know the port? In that scenario, it is best practice to define the port explicitly. We will use the EXPOSE directive for that.
Tip
Always use the EXPOSE directive to give more clarity and meaning to your image.
We also need to define the action to the container process if someone sends a docker stop command. While most processes take the hint and kill the process, it makes sense to explicitly specify what STOPSIGNAL the container should send on a docker stop command. We will use the STOPSIGNAL directive for that.
Now, while Docker monitors the container process and keeps it running unless it receives a SIGTERM or a stop, what would happen if your container process hangs for some reason? While your application is in a hung state, Docker still thinks it is running as your process is still running. Therefore, monitoring the application through an explicit health check would make sense. We will use the HEALTHCHECK directive for this.
Let’s combine all these aspects and see what we get in the Dockerfile:
$ vim Dockerfile
FROM ubuntu:bionic
RUN apt update && apt install -y curl
RUN apt update && apt install -y nginx
WORKDIR /var/www/html/
ADD index.html ./
EXPOSE 80
CMD [“nginx”, “-g”, “daemon off;”]
STOPSIGNAL SIGTERM
HEALTHCHECK –interval=60s –timeout=10s –start-period=20s –retries=3 CMD curl -f localhost