Series on Docker in Practice & Production - Dockerfile to create an image

Series on Docker in Practice & Production - Dockerfile to create an image

Daily short news for you
  • For over a week now, I haven't posted anything, not because I have nothing to write about, but because I'm looking for ways to distribute more valuable content in this rapidly exploding AI era.

    As I shared earlier this year, the number of visitors to my blog is gradually declining. When I looked at the statistics, the number of users in the first six months of 2025 has dropped by 30% compared to the same period last year, and by 15% compared to the last six months of 2024. This indicates a reality that users are gradually leaving. What is the reason for this?

    I think the biggest reason is that user habits have changed. They primarily discover the blog through search engines, with Google being the largest. Almost half of the users return to the blog without going through the search step. This is a positive signal, but it's still not enough to increase the number of new users. Not to mention that now, Google has launched the AI Search Labs feature, which means AI displays summarized content when users search, further reducing the likelihood of users accessing the website. Interestingly, when Search Labs was introduced, English articles have taken over the rankings for the most accessed content.

    My articles are usually very long, sometimes reaching up to 2000 words. Writing such an article takes a lot of time. It's normal for many articles to go unread. I know and accept this because not everyone encounters the issues being discussed. For me, writing is a way to cultivate patience and thoughtfulness. Being able to help someone through my writing is a wonderful thing.

    Therefore, I am thinking of focusing on shorter and medium-length content to be able to write more. Long content will only be used when I want to write in detail or delve deeply into a particular topic. So, I am looking for ways to redesign the blog. Everyone, please stay tuned! 😄

    » Read more
  • CloudFlare has introduced the pay per crawl feature to charge for each time AI "crawls" data from your website. What does that mean 🤔?

    The purpose of SEO is to help search engines see the website. When users search for relevant content, your website appears in the search results. This is almost a win-win situation where Google helps more people discover your site, and in return, Google gets more users.

    Now, the game with AI Agents is different. AI Agents have to actively seek out information sources and conveniently "crawl" your data, then mix it up or do something with it that we can't even know. So this is almost a game that benefits only one side 🤔!?

    CloudFlare's move is to make AI Agents pay for each time they retrieve data from your website. If they don’t pay, then I won’t let them read my data. Something like that. Let’s wait a bit longer and see 🤓.

    » Read more
  • Continuing to update on the lawsuit between the Deno group and Oracle over the name JavaScript: It seems that Deno is at a disadvantage as the court has dismissed the Deno group's complaint. However, in August, they (Oracle) must be held accountable for each reason, acknowledging or denying the allegations presented by the Deno group in the lawsuit.

    JavaScript™ Trademark Update

    » Read more

Image

As mentioned in the previous article, an image is a file used to create a container. It is also the file that needs to be built in order to run your application. To build an image, you use the following command:

docker build -t <image> <path>
  • -t is the flag used to tag the image.
  • path is the path to the directory containing the Dockerfile.

The name of the image usually consists of three parts: registry/name:tag.

Where registry is the resource to pull/push the image, name is the name of the image, and tag is usually a version. If the registry is not specified, Docker will pull from docker hub. If the tag is not specified, Docker will use the default tag "latest".

To pull an image, you use the docker pull command. To push an image, you use the docker push command. To tag an image that already exists in your machine, you use the docker tag command. To view the list of images in your machine, you use the docker image ls command. For example:

# pull nginx image version 2.1
docker pull nginx:2.1

# push nginx to the estacks registry
docker tag nginx:2.1 registry.estacks.icu/nginx:2.1
docker push registry.estacks.icu/nginx:2.1

# view the list of images in your machine
docker image ls

Refer to the docker build, docker image documentation for more commands.

Dockerfile

Most of the images we create are based on another image, usually starting with:

FROM node:12

Applications written or used on any platform usually have base images available on the Docker Hub. For example, for node.js, there is node, and for MySQL, there is mysql...

Docker Hub acts as a registry, and ordinary users can also upload their images to it. There is a way to identify official images (i.e., images provided by the official provider) by the prefix _ in their URLs.

You can also create your own base images if you have a good reason to do so (!?).

In summary, the idea to build an image that can run your app is to base it on a suitable base image for the platform your app is using.

Basic Dockerfile commands

FROM

FROM is the instruction to build an image from a base image. A Dockerfile must start with the FROM command, followed by the name of the image. The image name can be any valid name that Docker can pull from a registry or is available on the host.

For example:

FROM node:12

Refer to FROM for more information.

COPY

COPY is the command used to copy files/folders from the local system to the image. You usually need this command because your source code needs to be copied into the image in order to run it.

COPY <src> <dest>

## Example: copy the directory /User/hoaitx/src/my-app to the /src/my-app directory in the image
COPY /User/hoaitx/src/my-app /src/my-app

dest must be an absolute path, or if WORKDIR is specified, a relative path can be used.

WORKDIR /src

COPY /User/hoaitx/src/my-app my-app

Refer to COPY for more information.

WORKDIR

WORKDIR sets the working directory for any RUN, CMD, ENTRYPOINT, COPY, and ADD commands.

This means that setting WORKDIR to a directory will change the current directory for subsequent commands.

WORKDIR /src

RUN pwd

The result will be /src.

Refer to WORKDIR for more information.

VOLUME

VOLUME is the command to set up a mount point between the Docker host and the container.

When a container is created and runs successfully, any data it creates or stores will be inside the container. When the container is destroyed, all of that data will be lost.

Consider starting a MySQL container. If you accidentally destroy the container, all data will be lost. In this case, you can use VOLUME to map the data folder inside the container to a folder on the local system.

For example, for MySQL, the folder containing the data is /data. Before starting the container, map it to the /User/hoaitx/mysql/data directory on the local system.

VOLUME /User/hoaitx/mysql/data /data

Now, even if you destroy or restart the container, the data will still be safe in that local directory.

Refer to VOLUME for more information.

EXPOSE

EXPOSE is used to document which port the application in your image actually listens on, as opposed to leaving it to the user to guess. It helps in exposing a port when running the container.

# Assuming my-nginx app is configured to run on port 8080
EXPOSE 8080

In this case, I know that I need to map port 8080 to port 8081 on my Docker host:

docker run --name my-nginx -p 8081:8080 my-nginx

Refer to EXPOSE for more information.

ENTRYPOINT

ENTRYPOINT allows you to configure a command that will always be executed when starting a container.

ENTRYPOINT ["executable", "param1", "param2"]

Where executable is a command or a binary, such as bash or node...

For example, to run my Node.js application, I need to execute the node server.js command every time the container is started:

ENTRYPOINT ["node", "server.js"]

Refer to ENTRYPOINT for more information.

CMD

CMD provides default values for the command and parameters to be executed when running a container. In a Dockerfile, if there are multiple CMD instructions, the last one is used.

CMD ["executable", "param1", "param2"]

For example, when starting a container, I need to run the node server.js command to start the server:

CMD ["node", "server.js"]

Refer to CMD for more information.

So, if you have noticed, ENTRYPOINT and CMD seem to be similar in usage. Both are executed every time a container is created. They both have an executable and parameters.
The difference lies in the purpose of each command. "CMD provides default values," which means CMD may not have an executable, in which case ENTRYPOINT is required to specify the executable. On the other hand, ENTRYPOINT always requires an executable. Combining ENTRYPOINT and CMD creates an image that suits your purpose.

For example, to create an image specifically for a particular command, you would use ENTRYPOINT. Conversely, if you want to create a generic image, you can use CMD.

Apart from the basic commands I explained above, there are more commands you can refer to in the documentation.

Let's create our first image

Now, let's apply everything I shared above to analyze what I did in this Dockerfile :D

FROM node:12

ENV NODE_ENV=production

WORKDIR /app

COPY ["package.json", "package-lock.json*", "./"]

RUN npm install --production

COPY . .  

EXPOSE 3000

CMD [ "node", "server.js" ]

Build:

docker build -t registry.estacks.icu/my-node:1.0.0 .  

Run:

docker run -d -p 3000:3000 my-node:1.0.0

Summary

Most of the time, we create images based on another image. Images created with a Dockerfile contain instructions on how to build your application. The name of the image usually consists of three elements: <registry>/<name>:<tag>. If <registry> is not specified, Docker will pull from the Docker Hub by default. If <tag> is not specified, Docker will default to "latest".

Premium
Hello

The secret stack of Blog

As a developer, are you curious about the technology secrets or the technical debts of this blog? All secrets will be revealed in the article below. What are you waiting for, click now!

As a developer, are you curious about the technology secrets or the technical debts of this blog? All secrets will be revealed in the article below. What are you waiting for, click now!

View all

Subscribe to receive new article notifications

or
* The summary newsletter is sent every 1-2 weeks, cancel anytime.

Comments (1)

Leave a comment...
Avatar
Phan Tung4 years ago

bài viết rất bổ ích, cảm ơn tác giả

Reply
Avatar
Xuân Hoài Tống4 years ago

Cảm ơn bạn, nhớ ghé thăm blog thường xuyên nhé