Docker Images
- To launch a container, we must either download a public image or create your own.
- The docker image can be considered as a single asset that mainly represents the filesystem for the container.
- Docker images are built up from individual layers. Each layer puts a special demands on the Linux kernel
Anatomy of a Dockerfile
A typical Docker image running the node application looks like the following.
FROM alpine:3.18
USER root
ENV EASIFEM_BUILD_DIR /easifem/build
ENV EASIFEM_SOURCE_DIR /easifem/src
ENV EASIFEM_INSTALL_DIR /easifem/install
ENV EASIFEM_TEST_DIR /easifem/tests
RUN apk update && apk add --no-cache gfortran musl-dev
COPY ./tests/* $EASIFEM_TEST_DIR/
WORKDIR $EASIFEM_TEST_DIR
RUN gfortran -o main.out main.F90 && ./main.out
ARG email="vickysharma0812@gmail.com"
LABEL "maintainer"=$email
Let understand the above file line by line.
FROM alpine:3.18
This line indicates the base image for our image. In this case it is Alpine linux version3.18. You can read about this project here.
Alpine Linux is a Linux distribution built around musl libc and BusyBox. The image is only 5 MB in size and has access to a package repository that is much more complete than other BusyBox based images. This makes Alpine Linux a great image base for utilities and even production applications. Read more about Alpine Linux here and you can see how their mantra fits in right at home with Docker images.
ARG email="vickysharma0812@gmail.com"
This line defines an argument (a variable) in the Dockerfile. This variable can be specified by the user while running the container.
LABEL "maintainer"=$email
This line defines a label for the image that we are building.
Applying labels to images and containers allows us to add metadata via key/value pairs that can later be used to search for and identify Docker images and containers.
USER root
By default, Docker runs all processes as root within the container, the above line describes the USER.
Even though containers provide some isolation from the underlying operating system, they still run on the host kernel. Due to potential security risks, production containers should almost always be run in the context of an unprivileged user.
ENV EASIFEM_BUILD_DIR /easifem/build
ENV EASIFEM_SOURCE_DIR /easifem/src
ENV EASIFEM_INSTALL_DIR /easifem/install
ENV EASIFEM_TEST_DIR /easifem/tests
The above lines define the shell environment variables.
RUN apk update && apk add --no-cache gfortran musl-dev
The above lines run the commands. Here, it is worth remembering that every instruction creates a new Docker image layer, so it often makes sense to combine a few logically grouped commands onto a single line.
COPY ./tests/* $EASIFEM_TEST_DIR/
This command moves the file from the tests
directory of host to /easifem/tests/
directory of the image.
WORKDIR $EASIFEM_TEST_DIR
With the WORKDIR instruction, we can change the working directory in the image for the remaining build instructions.
The order of commands in a Dockerfile can have a very significant impact on ongoing build times. You should try to order commands so that things that change between every single build are closer to the bottom. This means that adding your code and similar steps should be held off until the end. When you rebuild an image, every single layer after the first introduced change will need to be rebuilt.
Building an image
Before we build the image, we need to add .dockerignore
file to the same location as Dockerfile
. Add following entries to it.
.git
*.out
*.o
build
*/build/*
To build the image run the following command:
docker image build -t vickysharma0812/fortran-hello-world-alpine:latest
Using
docker image build
is functionally the same as usingdocker build
.
To improve the speed of builds, Docker will use a local cache when it thinks it is safe. This can sometimes lead to unexpected issues because it doesn’t always notice that something changed in a lower layer. You can disable the cache for a build by using the --no-cache
argument to the docker image build command.
Each step identified in the following output maps directly to a line in the Dockerfile, and each step creates a new image layer based on the previous step. The first build that you run will take a few minutes because you have to download the base node image. Subsequent builds should be much faster unless a new version of our base image tag has been released.
Running Image
We run the above image by using following command.
docker container run --rm -d vickysharma0812/fortran-hello-world-alpine:latest
Setting environment variables
While running the container, we can set the environment variables by using --env
or -e
flag.
docker container run --rm -d \
--env EASIFEM_SOURCE_DIR=/easifem/source/ \
vickysharma0812/fortran-hello-world-alpine:latest
Storing images on Dockerhub
Create account at Docker hub.
- The first step required to push the image is to ensure that you are logged in to the Docker repository you intend to use.
First we need to change the tag of the image that we have build. We need to add the host name docker.io
.
docker image tag vickysharma0812/fortran-hello-world-alpine:latest \
docker.io/vickysharma0812/fortran-hello-world-alpine:latest
Here vickysharma0812
is my account name on hub.docker.com
.
Now we push this image to docker cloud.
docker image push vickysharma0812/fortran-hello-world-alpine:latest
After that anyone who has access to internet can pull out image and run the containers.
docker image pull vickysharma0812/fortran-hello-world-alpine:latest
Getting info on build images
We can dive into the build images by using dive and using following command.
dive vickysharma0812/fortran-hello-world-alpine:latest
┃ ● Layers ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Cmp Size Command
7.7 MB FROM de8b86e33ae69ac
172 MB RUN |1 email=vickysharma0812@gmail.com /bin/sh -c apk update && apk add --no-cache gfor
71 B COPY ./tests/* /easifem/tests/ # buildkit
0 B WORKDIR /easifem/tests
73 kB RUN |1 email=vickysharma0812@gmail.com /bin/sh -c gfortran -o main.out main.F90 && ./ma
Image name: vickysharma0812/fortran-hello-world-alpine:latest
Total Image size: 179 MB
Potential wasted space: 1.5 MB
Image efficiency score: 99 %
Count Total Space Path
2 1.3 MB /lib/ld-musl-aarch64.so.1
2 94 kB /lib/apk/db/installed
2 68 kB /usr/bin/strings
2 22 kB /lib/apk/db/scripts.tar
2 152 B /lib/apk/db/triggers
As you can see, most of the space in our image is taken by gfortran
and gcc
compilers.