Docker's Common Use
In this post, I will cover Docker’s common use based on my experience.
I. Docker
1. Writing Dockerfile
The basic structure of Dockerfile
FROM <base_image_name>:<version> |
Common used instructions
Instructions for build
- FROM
- ARG
- WORKDIR
- COPY/ADD
- RUN
FROM
Create a new build stage from a base image. For example,
FROM alpine:latest |
FROM node:22-alpine |
ARG
Create build-time variables. For example,
# define variable |
WORKDIR
Change the working directory. Like the cd
command on Linux. For example,
WORKDIR /app |
COPY
Copy files and directories from a source location on the host machine into the filesystem of the Docker image at a specified destination. You can add .dockerignore
to ignore files. For example,
COPY . . |
ADD
Copy local files and download the file from that URL. When you copy local files, it’s best to use COPY
.
RUN
Run commands. It’s better to run multiple commands at once via && concatenation. For example,
RUN npm install |
Instructions for container
- ENV
- EXPOSE
- USER
- ENTRYPOINT/CMD
ENV
Set environment variables for the container. For example,
ENV TZ=Asia/Shanghai |
EXPOSE
Describe which ports your application is listening on. It is used in a Dockerfile to indicate which port(s) the container will listen on at runtime. While it does not actually publish the ports, it serves as documentation for anyone who uses the image and helps improve the clarity of how to run the container. For example,
EXPOSE 80 |
USER
Set user and group ID. For example,
# create user and group |
ENTRYPOINT
Specify the default executable. Specifies the command that should always run; not overridden by runtime arguments. For example,
ENTRYPOINT ["java","-jar","/app.jar"] |
- Only can run
java
command.
CMD
Specify default commands. Specifies default arguments for ENTRYPOINT
or acts as the command to run when no command is provided; can be overridden by runtime arguments. For example,
CMD ["java","-jar","/app.jar"] |
- By default, it runs
java
command. It can also run another command by overriding runtime arguments, for example,docker run my_container echo 'Hello World'
.
More Dockerfile instructions to see: Dockerfile reference
Common used base images
Avoid Using the latest
Tag. Specify exact versions of images for predictability and security. Using latest
can lead to unexpected changes.
Linux
alpine:3
(3MB). A security-oriented, lightweight, and minimal Docker image based on Alpine Linux. It’s a popular choice for many applications due to its small size and package management system (apk).
FROM alpine:3 |
ubuntu:25.04
(30MB)
FROM ubuntu:25.04 |
debian:12-slim
(27MB)
FROM debian:12-slim |
Java
- 21
amazoncorretto:21-alpine
(155MB)eclipse-temurin:21-alpine
(173MB),eclipse-temurin:21-jre-alpine
(69MB)
- 8
openjdk:8-jdk-slim
,openjdk:8-jre-slim
,openjdk:8-jdk-alpine
,openjdk:8-jre-alpine
Note openjdk docker images are deprecated.
Node.js
node:22-alpine
(52MB)
Nginx
nginx:stable-alpine
(16MB)
Python
python:3-alpine
(15MB)
Middleware
mysql/mysql-server:8.0
(160MB)redis:7-alpine
(15MB)postgres:17-alpine
(111MB)
Other
scratch
. 0 bytes (it’s an empty image). Thescratch
image is the ultimate minimal image. It is used to build completely statically compiled binaries (like Go applications). It is important to note that you can’t install any packages onscratch
since it’s literally an empty image.busybox:stable
(1MB). BusyBox combines tiny versions of many common UNIX utilities into a single small executable. It’s often used for simple tasks and scripts. Tools that busybox provided: sh, file operations (ls, cp, mv, rm, mkdir, touch, etc), text processing (cat, echo, grep, etc), networking utilities (ifconfig, ping, wget, telnet, etc), system utilities (ps, kill, top, free), and so on.
Search Docker images
To get the size of a Docker image before a pull
# for an official image the namespace is called library |
Differences between ENTRYPOINT
and CMD
?
ENTRYPOINT
: Specifies the command that should always run; not overridden by runtime arguments.CMD
: Specifies default arguments forENTRYPOINT
or acts as the command to run when no command is provided; can be overridden by runtime arguments.
For example:
Dockerfile
FROM ubuntu:20.04 |
docker build -t my-python-image . |
If you run the container without any command:
docker run my-python-image |
It runs: python3 app.py
.
If you want to run a different script instead:
docker run my-python-image another_script.py |
It runs: python3 another_script.py
.
Set timezone
ENV TZ=Asia/Shanghai |
To run the application as a non-root user
# Change permissions of some directories and files in the mapping volume before changing to a non-root user. |
Multi-stage Dockerfile
You can define multiple build stages, and copy files from the previous stage. For example,
# Build Stage |
2. Building Docker Image
docker build -t <image_name> . |
Commonly used options of docker build
-t, --tag
: Specify image name.--no-cache
: Do not use cache when building the image. Automatically update to use the latest base image according to the version of the base image.-f, --file
: Dockerfile file path relative to docker context root path. By default, it’s<container_content_root_path>/Dockerfile
. For example,./Dockerfile
.--platform
: Set target platform for build. For example,linux/amd64
(Linux),linux/arm64
(macOS).
For more options reference: Docker build documentation.
Note: Docker can’t translate the hostname of Docker containers during the build stage.
3. Running Docker Container
docker run -d --name <my_container> [,more_options] <image_name> |
Common used options of docker run
- Basic
-d, --detach
: Run the container in the background.--name
: Set container name.
- Environment
-e, --env
: Set environment variables. For example,-e "SPRING_PROFILES_ACTIVE=prod"
. You can also specify multiple-e
options to set multiple environment variables.--env-file
: Read in a file of environment variables. For example,--env-file .env
- Disk
--mount
: Attach a filesystem mount to the container. For detailed usage, see the content below.-v, --volume
: Bind mount a volume. For detailed usage, see the content below.--read-only
: Mount the container’s root filesystem as read only.
- Network
--net, --network
: Connect a container to a network. Syntax:--network <network_name>
. For example:--network my_app
. You can also specify multiple--network
options to connect multiple networks. Docker compose network:<project_directory_name>_default
.-p, --publish
: Publish a container’s port(s) to the host. Syntax:-p host_port:container_port
. For example,-p 8080:8080
. You can also specify multiple-p
options to publish multiple ports.
- Interactive
-i, --interactive
: Keep STDIN open even if not attached.-t, --tty
: Allocate a pseudo-TTY.
- Others
--platform
: Set platform if server is multi-platform capable.--restart
: Restart policy to apply when a container exits.--rm
: It is used to automatically remove a container after it has stopped running. This is particularly useful for running temporary containers that are only needed for a short period of time and helps keep your system clean by avoiding the accumulation of stopped containers.--pull
: Pull image before running (always, missing, never). The default value ismissing
.-m, --memory
: Memory limit. For example,-m 2GB
.
For more options of docker run
reference: docker container run documentation
–restart policies
The most commonly used restart policy is unless-stopped
.
Flag | Description |
---|---|
no |
Don’t automatically restart the container. (Default) |
on-failure[:max-retries] |
Restart the container if it exits due to an error, which manifests as a non-zero exit code. Optionally, limit the number of times the Docker daemon attempts to restart the container using the :max-retries option. The on-failure policy only prompts a restart if the container exits with a failure. It doesn’t restart the container if the daemon restarts. |
always |
Always restart the container if it stops. If it’s manually stopped, it’s restarted only when Docker daemon restarts or the container itself is manually restarted. |
unless-stopped |
Similar to always , except that when the container is stopped (manually or otherwise), it isn’t restarted even after Docker daemon restarts. |
docker run -v
1. Using a named volume
Named volumes are managed by Docker, and volumes created this way can be shared among multiple containers.
docker run -v my-volume:/app/data myimage |
2. Using a bind mount
A bind mount allows you to mount a specific directory or file from the host file system into the container.
docker run -v /path/on/host:/app/data myimage |
/path/on/host
is a file or directory on the host system./app/data
is the directory inside the container where the host directory will be mounted.
3. Read-Only Mount
You can make a volume or bind mount read-only by appending :ro
to the volume or bind mount specification.
docker run -v my-volume:/app/data:ro myimage |
4. Multiple Mounts
You can also specify multiple -v
options to mount multiple volumes or bind mounts into the same container.
docker run -v my-volume:/app/data -v /path/on/host:/app/config myimage |
docker run –mount
Syntax
docker run --mount type=<type>,source=<source>,target=<target>[,readonly] <image> |
type=<type>
: The type of mount. Possible values are:volume
: For a Docker-managed volume.bind
: For a bind mount to a specific host path.tmpfs
: For a temporary filesystem mount in memory.
source=<source>
: The source for the mount. This can be the name of a Docker volume (fortype=volume
) or a path on the host (fortype=bind
).target=<target>
: The path inside the container where the mount will be accessible.readonly
: Optional flag. If specified, the mount will be read-only for the container (i.e., no write operations will be allowed).<image>
: The name of the Docker image from which to create the container.
1. Using a Named Volume
docker run --mount type=volume,source=my-volume,target=/app/data myimage |
2. Using a Bind Mount
docker run --mount type=bind,source=/path/on/host,target=/app/data myimage |
3. Using a Tmpfs Mount
A tmpfs mount allows you to create a mount that resides in memory. This is useful for data that needs to be temporary.
docker run --mount type=tmpfs,target=/app/temp myimage |
/app/temp
is the directory inside the container where the temporary filesystem will be created.
4. Using Read-Only Mount
You can make any of the mounts read-only by adding the ,readonly
option.
docker run --mount type=volume,source=my-volume,target=/app/data,readonly myimage |
5. Multiple Mounts
You can specify multiple --mount
options when starting a container to use multiple mounts.
docker run --mount type=volume,source=my-volume,target=/app/data \ |
Run amd64 Docker image on arm64 (macOS)
Warning message
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested |
Solutions
docker run --platform linux/amd64 ... |
Run Docker container in interactive mode
docker run -it ... |
-i, --interactive
: Keep STDIN open even if not attached-t, --tty
: Allocate a pseudo-TTY
For example:
# connect to local postgres server container |
Restart one or more containers
docker restart [, options] <container> |
4. View logs of the Docker container
docker logs -f <container_name> |
5. Stop and remove a Docker container
docker stop <container_name> || true && docker rm <container_name> || true |
6. Execute a command in a running container
Execute a command in a running container
docker exec <container_name> <command> |
7. More Docker commands
Copy files/folders between a container and the local filesystem
# Copy a local file into container |
Display detailed information on one or more containers
docker inspect [,options] <container> |
Display a live stream of container(s) resource usage statistics
docker stats [,options] <container> |
List port mappings or a specific mapping for the container
docker port [,options] <container> |
Display the running processes of a container
docker top [,options] <container> |
List containers
docker ls |
Remove all stopped containers
docker prune |
For more Docker commands reference: docker container documentation
II. Docker Compose
1. Writing Docker compose.yaml
The basic structure of compose.yaml
name: <project_name> |
Commonly used attributes/properties of docker-compose.yaml
name
: Project name. By default, it’s project directory name.services
:image
: Image name and tag. For example,image: redis:7-alpine
build
: specifies the build configuration for creating a container image from sourcecontainer_name
: Set custom container name. For example,container_name: my-app
.ports
: Define the port mappings between the host machine and the containers. Syntax:Ports: "<host_port>:<container_port>"
. For example,ports: "8080:8080"
env_file
: Specify one or more files that contain environment variables to be passed to the containers. For example,env_file: .env
environment
: Defines environment variables set in the container. For example,environment: TZ=Asia/Shanghai
volumes
: define mount host paths or named volumes that are accessible by service containers.networks
: networks that service containers are attached to. For example:networks: my-network
- Some more
depends_on
: Define dependencies between services. It specifies the order in which services should be started and can also define the order of shutdown behavior.platform
: The target platform the containers for the service run on. For example,linux/amd64
(Linux),linux/arm64
(macOS).read_only
: Configures the service container to be created with a read-only filesystem.restart
: Defines the policy that the platform applies on container termination.
For more properties reference: Compose file reference
Note
- Port mapping must not be used with
network_mode: host
. Doing so causes a runtime error becausenetwork_mode: host
already exposes container ports directly to the host network, so port mapping isn’t needed.
Docker Compose Options
--env-file
: Specify an alternate environment file-f, --file
: Compose configuration files--project-directory
: Specify an alternate working directory (default: the path of the, first specified, Compose file)-p, --project-name
: Project name
For example:
docker compose -f xxx up -d |
2. Starting Docker Compose containers
docker compose up [, options...] |
Commonly used options of docker compose up
-d, --detach
: Detached mode: Run containers in the background.--build
: Build images before starting containers. If containers in docker-compose.yaml has been created, docker will not build image even there are some changes. Running with--build
ensures that the latest code or dependencies are included in the new image.--force-recreate
: Recreate containers even if their configuration and image haven’t changed.--pull
: Pull image before running (“always”|”missing”|”never”). For example,--pull always
-w, --watch
: Watch source code and rebuild/refresh containers when files are updated. Monitor changes in your files (like source code or configuration files) and automatically rebuild and restart the defined services when changes are detected.--remove-orphans
: Remove containers for services not defined in the Compose file.
For more options reference: docker compose up documentation
Restart service containers
docker compose restart |
View output from containers
docker compose logs |
3. Build Docker Compose image (Optional)
docker compose up
can build image automatically if images doesn’t exist.
docker compose build [, options...] |
docker compose build
will read your docker-compose.yml
, look for all services containing the build:
statement and run a docker build
for each one.
Commonly used options of docker compose build
--build-arg
: Set build-time variables for services.--no-cache
: Do not use cache when building the image.--pull
: Always attempt to pull a newer version of the image.
For more options reference: docker compose build documentation
4. Stop and remove Docker Compose containers
Stop services
docker compose stop |
Force stop service containers
docker compose kill |
Stop and remove containers, networks
docker compose down |
Removes stopped service containers
docker compose rm [OPTIONS] [SERVICE...] |
5. Execute a command in a running container
Execute a command in a running container
docker compose exec [, options] <service> <command> |
Run a one-off command on a service
docker compose run [OPTIONS] SERVICE [COMMAND] [ARGS...] |
For examples:
docker compose run web bash |
6. More Docker Compose Commands
Copy files/folders between a service container and the local filesystem
# Copy a local file into container |
Pull service images
docker compose pull |
List images used by the created containers
docker compose images |
List running compose projects
docker compose ls |
List containers
docker compose ps |
Display the running processes
docker compose top |
More Docker Compose commands reference: docker compose documentation
III. Storage
Volumes
Volumes are persistent data stores for containers, created and managed by Docker. You can create a volume explicitly using the docker volume create command, or Docker can create a volume during container or service creation.
Volumes are the preferred mechanism for persisting data generated by and used by Docker containers. While bind mounts are dependent on the directory structure and OS of the host machine, volumes are completely managed by Docker. Volumes are a good choice for the following use cases:
- Volumes are easier to back up or migrate than bind mounts.
- You can manage volumes using Docker CLI commands or the Docker API.
- Volumes work on both Linux and Windows containers.
- Volumes can be more safely shared among multiple containers.
- New volumes can have their content pre-populated by a container or build.
- When your application requires high-performance I/O.
Volumes are not a good choice if you need to access the files from the host, as the volume is completely managed by Docker. Use bind mounts if you need to access files or directories from both containers and the host.
Mount a Docker volume into a container when starting a container
docker run -v <volume-name>:<container-path> |
Mount a Docker volume in compose.yaml
services: |
Bind mounts
When you use a bind mount, a file or directory on the host machine is mounted from the host into a container.
Bind mounts are appropriate for the following types of use case:
- Sharing source code or build artifacts between a development environment on the Docker host and a container.
- When you want to create or generate files in a container and persist the files onto the host’s filesystem.
- Sharing configuration files from the host machine to containers. This is how Docker provides DNS resolution to containers by default, by mounting
/etc/resolv.conf
from the host machine into each container.
Bind-mounting over existing data
If you bind mount file or directory into a directory in the container in which files or directories exist, the pre-existing files are obscured by the mount.
Bind mount when starting a container
docker run --volume <host-path>:<container-path>:[,ACCESS_MODE] |
For example:
docker run -v /data:/data |
Bind mount in compose.yaml
services: |
Access mode
rw
: Read and write access. This is the default if none is specified.ro
: Read-only access.z
: SELinux option indicating that the bind mount host content is shared among multiple containers.Z
: SELinux option indicating that the bind mount host content is private and unshared for other containers.
tmpfs mounts
If you’re running Docker on Linux, you have a third option: tmpfs mounts. When you create a container with a tmpfs mount, the container can create files outside the container’s writable layer.
As opposed to volumes and bind mounts, a tmpfs mount is temporary, and only persisted in the host memory. When the container stops, the tmpfs mount is removed, and files written there won’t be persisted.
tmpfs mounts are best used for cases when you do not want the data to persist either on the host machine or within the container. This may be for security reasons or to protect the performance of the container when your application needs to write a large volume of non-persistent state data.
Mounting over existing data
If you create a tmpfs mount into a directory in the container in which files or directories exist, the pre-existing files are obscured by the mount.
Limitations of tmpfs mounts
- Unlike volumes and bind mounts, you can’t share tmpfs mounts between containers.
- This functionality is only available if you’re running Docker on Linux.
- Setting permissions on tmpfs may cause them to reset after container restart. In some cases setting the uid/gid can serve as a workaround.
Bind tmpfs mount when starting a container
# bind tmpfs mount mount to /app in the container |
Bind tmpfs mount in compose.yaml
services: |
For more about Docker storage reference: Storage - Docker documentation
IV. Networking
User-defined networks
You can create custom, user-defined networks, and connect multiple containers to the same network. Once connected to a user-defined network, containers can communicate with each other using container IP addresses or container names.
Network driver types
Driver | Description |
---|---|
bridge |
The default network driver. |
host |
Remove network isolation between the container and the Docker host. |
none |
Completely isolate a container from the host and other containers. |
overlay |
Overlay networks connect multiple Docker daemons together. |
ipvlan |
IPvlan networks provide full control over both IPv4 and IPv6 addressing. |
macvlan |
Assign a MAC address to a container. |
Connect to networks when starting a container
docker run --network=my-network <image_name> |
Set networks in compose.yaml
services: |
Host network driver
If you use the host
network mode for a container, that container’s network stack isn’t isolated from the Docker host (the container shares the host’s networking namespace), and the container doesn’t get its own IP-address allocated. For instance, if you run a container which binds to port 80 and you use host
networking, the container’s application is available on port 80 on the host’s IP address.
Host mode networking can be useful for the following use cases:
- To optimize performance
- In situations where a container needs to handle a large range of ports
Using the host
network mode when starting a container
docker run --net=host <image_name> |
Using the host
network mode in compose.yaml
services: |
For more about Docker network reference: Networking - Docker documentation