- English
- English
Appearance
Appearance
So far, you have run images created by other people. In daily work, you will often build your own image so that your team's app can run with one command.
Instructions for building an image are written in a file named Dockerfile (with no file extension), usually in the project root. The project root is the main folder that contains the source code and project configuration files.
Create a practice folder so all example files stay in one place:
mkdir docker-essentials-demo
cd docker-essentials-demoindex.html:
<!DOCTYPE html>
<html lang="en">
<body>
<h1>Hello from a container</h1>
</body>
</html>Dockerfile:
FROM nginx:1.27-alpine
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80Line by line:
| Instruction | Purpose |
|---|---|
FROM | Sets the base image. Every Dockerfile starts here. |
COPY | Copies files from your laptop into the image. |
EXPOSE | Documents the port used by the app. It does not publish the port to your laptop. You still need to map it with -p when running the container. |
For an app you actually write, the Dockerfile is usually more complete:
FROM node:22-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "start"]| Instruction | Purpose |
|---|---|
WORKDIR | Sets the working folder inside the image. Later COPY and RUN commands use this folder as their relative location. |
RUN | Runs a command during the build, such as installing dependencies or compiling the app. The result becomes an image layer. |
CMD | Sets the default command when the container starts. |
RUN and CMD both look like commands in a Dockerfile, but they run at different times:
RUN runs when the image is built. For example, RUN npm install and RUN npm ci. The result is stored in an image layer.CMD runs when the container starts. For example, CMD ["npm", "start"]. It becomes the container's default command.In the example above, npm ci runs during the build. npm start runs each time the container starts.
CMD, Docker uses the CMD from the base image, if one exists.ENTRYPOINT is useful for an image that acts as a CLI. ENTRYPOINT is the main program, while CMD can provide default arguments for that program.
Example Dockerfile with ENTRYPOINT:
FROM alpine:3.20
ENTRYPOINT ["echo"]
CMD ["Hello from a container"]To see the difference between ENTRYPOINT and CMD, build the image and run several containers:
docker build -t echo-demo:1.0 .
docker run --rm echo-demo:1.0
docker run --rm echo-demo:1.0 "Another message"The first command outputs Hello from a container. In the second command, the CMD argument is replaced, so the output becomes Another message.
ENTRYPOINT and CMD can use the exec form, such as ["program", "argument"]. This form is recommended because it keeps the command and its arguments separate.
This file is similar to .gitignore. It lists files that do not need to be sent to Docker Engine as the build context.
.git
node_modules
*.md
.envWithout this file, COPY . . may include node_modules from the host, secret files, or the Git folder. The build becomes slower and the image becomes larger.
An image is made of several layers stacked on top of each other. Each relevant Dockerfile instruction usually adds a layer.
Think of an image like a sandwich. The base image is the bottom layer, and other layers are added above it. If several images use the same base image, Docker Engine can reuse the existing layer instead of downloading it again.
The cache makes rebuilds faster. If a layer has not changed, Docker Engine can use it from the cache instead of processing it again. The build only repeats the changed layer and the layers after it.
The order of instructions in a Dockerfile affects how much cache can be reused. Put steps that rarely change, such as installing dependencies, near the top. Put source code that changes often near the bottom.
In the Node example above, package.json is copied first, followed by npm ci, and then the source code is copied. If you only change index.js, the npm ci layer can come from the cache.
If COPY . . comes before npm ci, every source code change forces the installation to run again. The build becomes slower.
From the folder containing the Dockerfile, use this format to build an image:
docker build -t <image-name>:<tag> <build-context>Example:
docker build -t hello-web:1.0 .-t hello-web:1.0 sets the name and tag of the built image.. is the build context, the folder sent to Docker Engine for COPY to use.To run a container from the new image, use this format:
docker run -d --name <container-name> -p <local-port>:<container-port> <image-name>:<tag>Example:
docker run -d --name hello -p 8080:80 hello-web:1.0Open http://localhost:8080 in a browser.
You can share an image on your laptop through a registry. In this example, you will use Docker Hub.
Before pushing, create a Docker Hub account and a new repository, such as hello-web. Use your Docker Hub username as part of the image name. A repository is a place on Docker Hub that stores an image with its name and tags.
Log in to Docker Hub through Docker CLI so Docker Engine has permission to send the image:
Command format:
docker login -u <dockerhub-username>Example:
docker login -u bagusDocker will ask for your password. If your Docker Hub account uses two-factor authentication, use a personal access token as the password. Do not write a password or token directly in a command, and do not commit credentials to Git.
After logging in, add your Docker Hub name to the local image. Docker Hub expects the format <username>/<repository>:<tag> so it can send the image to the correct repository:
Command format:
docker tag <local-image>:<local-tag> <dockerhub-username>/<repository>:<tag>Example:
docker tag hello-web:1.0 bagus/hello-web:1.0Push the image to Docker Hub:
Command format:
docker push <dockerhub-username>/<repository>:<tag>Example:
docker push bagus/hello-web:1.0After the push finishes, another machine can pull the image:
docker pull <dockerhub-username>/<repository>:<tag>Example:
docker pull bagus/hello-web:1.0Replace bagus with your Docker Hub username. The repository name and tag must match the image you pushed.