Source: Canva Team

Beyond Names & Labels: Dockerfile

Ananya

--

“I learned very early the difference between knowing the name of something and knowing something.”
Richard P. Feynman

These blog series capture the essence of Feynman’s quote, emphasizing the distinction between superficial knowledge (knowing the name of something) and deep understanding (knowing something). If you want to learn beyond the name of Dockerfile then read away 😊

Pre-read

In the previous article, I showed you some basic docker commands on ready-made image of redis.

In this article, I will show you how you can create your own docker images.

Dockerfile

A Dockerfile is a text file specifying the instructions that should be run to create a Docker image. A typical dockerfile contains these 3 things:

  1. Instruction to specify a base image
  2. Instruction to install required packages
  3. Instruction to specify a default command to run when a container is created out of this image

Let’s create a custom image of redis using dockerfile:

# Use an existing docker image as base
FROM alpine
# Install the packages
RUN apk add --update redis
# Command to run when this image runs as a container
CMD ["redis-server"]

This is a sample Dockerfile for creating a redis image.

  1. FROM: The FROM statement tells the docker server about the base image. In our case, we want to use alpine as a base image. Generally, a base image comes with some libraries that you are going to need in your image creation.
  2. RUN: The RUN specifies that the following statement should be run as a normal Linux command while building the docker image. Observe the apk — this is an Alpine package keeper that helps install the redis package. This apk package manager came as part of the base image.
  3. CMD: The CMD statement specifies the start command that should be run when the image is run as a container.

Building a Dockerfile

To create an image out of the Dockerfile, run the following command:

docker build .
Sample docker build output

The docker build command creates the docker image. The image id is printed in the last line.

Understanding Image Build

If you look closely at the logs of the docker build, you will observe the following points:

  1. The base image mentioned with the FROM instruction is downloaded from the registry.
  2. The RUN instruction was executed on some intermediate container. This intermediate container was created using the image available in the last step — the alpine image. Once the container is created, the RUN instruction (install redis) is executed within this container. A file system snapshot is taken for this intermediate container before removing it.
  3. The CMD instruction was executed on some intermediate container. This intermediate container was created using the image available in the last step — the filesystem snapshot of the base image with redis installed. Once the container is created, the CMD instruction ([“redis-server”]) is executed within this container. A file system snapshot is taken for this intermediate container before removing it.
  4. The file system snapshot of this last step was your final image.
Step-by-step image build process

Caching in Image Building

Docker build uses caching for faster image building. If you run the docker build command again, this time you will see cache in action.

Caching in the docker build

Caching Criteria:

  1. Caching can be used if the instructions in the Dockerfile are unchanged.
  2. If the order of instruction is changed, then caching will not happen.

For example: let me modify the above Dockerfile.

# Use an existing docker image as base
FROM alpine
# Install the packages
RUN apk add --update redis

#New step added in Dockerfile
#The Expose command exposes a particular port inside the docker conatiner
EXPOSE 80

# Command to run when this image runs as a container
CMD ["redis-server"]

Now, if we run the docker build command, we get the following logs:

Docker build with new instruction

Since the Dockerfile did not change till Step 2, the cache could be used only up to Step 2.

Tagging a Docker Image

To view the image run the below command:

docker images
Sample docker images output

The above image shows that the image has no repository or tag and looks like an unnamed image. To get an image with tag & repository information, run the below command to build an image:

docker build -t ananya/my-redis:v1 .
Sample docker images command with tagging

Food for Thought 💡

Can you spot a way to optimize this Dockerfile:

#Specify Base Image
FROM node:16-alpine

#Specify the working directory in container
WORKDIR '/app'

#Copy the code from current location to working directory in container
COPY . .

# Install dependencies by reading the package.json file
RUN npm install

# Command to run when this image runs as a container
CMD ["npm", "run", "start"]

Using the above Dockerfile, every time you change some code, the npm install command will be executed. We only need to run npm install when there is some change in dependency (package.json) and not the whole code.

You can leverage the cache while rebuilding if you re-write the Dockerfile in this way:

#Specify Base Image
FROM node:16-alpine

#Specify the working directory in container
WORKDIR '/app'

#Copy only the package.json to working directory
COPY package.json .

# Install dependencies by reading the package.json file
RUN npm install

#Copy the code from current location to working directory in container
COPY . .

# Command to run when this image runs as a container
CMD ["npm", "run", "start"]

This way, only when there is any change in project dependency, the npm install will execute thereby saving unnecessary rebuilds on simple code changes.

Thank you for giving me the gift of your precious time 😇 Happy Reading!!

References

--

--

Ananya
Ananya

Written by Ananya

Software Developer | Technical Writer | Technology Enthusiast

No responses yet