Skip to content
Back to blog

Docker

An overview of Docker image and container operations, Dockerfile instructions, and CPU, memory, and disk I/O resource limits.

Updated

Image Operations

Pulling Images

# Pull the latest image (the default tag is latest)
docker pull nginx

# Pull a specific version (e.g. Python 3.8)
docker pull python:3.8

# Pull images of all tags (e.g. every busybox version)
docker pull -a busybox

Building Images

# Build an image from a Dockerfile (the current directory must contain a Dockerfile)
docker build -t myapp:1.0 .

# Commit a new image from a container (save a running container as an image)
docker commit container_id myapp:snapshot

Deleting Images

# Delete by name
docker rmi nginx:latest

# Delete by image ID (short or long ID)
docker rmi 501ad78535f0

# Force delete (even if containers depend on it)
docker rmi -f myapp:old

# Delete all unused images
docker image prune -a

# Delete all local images
docker rmi -f $(docker images -aq)

Listing Images

# Show all images (including intermediate layers)
docker images -a

# Filter by name (e.g. all nginx-related images)
docker images nginx*

# Show image IDs only
docker images -q

Searching Images

# Search images on Docker Hub
docker search redis

# Filter for official images with at least 1000 stars
docker search --filter "is-official=true" --filter "stars=1000" mysql

Viewing Image Details

# Show image metadata (such as layer info, environment variables)
docker image inspect nginx:latest

# View the image build history
docker history myapp:1.0

Importing and Exporting Images

# Export an image to a .tar file (for offline transfer)
docker save -o nginx.tar nginx:latest

# Load an image from a .tar file
docker load -i nginx.tar

Publishing Images

# Log in to Docker Hub or a private registry
docker login -u username -p password registry.example.com

# Push an image (tag it first)
docker push registry.example.com/myapp:prod

Container Operations

Creating Containers

# Basic run (enters an interactive terminal after starting)
docker run -it --name my_ubuntu ubuntu:22.04 /bin/bash

# Run in background + port mapping + volume mount
docker run -d --name my_nginx -p 8080:80 -v /data:/usr/share/nginx/html nginx:latest

# Create without starting
docker create --name pending_container redis:alpine

Deleting Containers

# Stop a container
docker stop my_nginx

# Force-delete a running container
docker rm -f my_nginx

# Batch-delete all stopped containers
docker container prune

# Delete all containers
docker rm -f $(docker ps -aq)

Updating Container Configuration

# Dynamically adjust a container's memory limit (the container must be running or stopped)
docker update --memory 512m my_container

# Change a container's restart policy (e.g. auto-restart after a crash)
docker update --restart=always my_container

# Enter a container, modify files, and commit as a new image
docker commit my_container my_image:v2
docker run -d --name new_container my_image:v2

Viewing Container Status

# View running containers
docker ps

# View all containers (including stopped ones)
docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}"

# View a container's resource usage
docker stats my_container

Viewing Container Internals

# Follow logs in real time (like tail -f)
docker logs -f --tail 100 my_container

# View container metadata (such as IP, mount points)
docker inspect my_container | grep -E "IPAddress|Mounts"

# View the container's process list
docker top my_container

Entering a Container

# Enter a running container interactively
docker exec -it my_container /bin/bash

# Run a one-off command inside a container
docker exec my_container ls /var/log

Hot-Updating Containers

# Rolling update (in Swarm mode)
docker service update --image nginx:v2 --update-parallelism 2 web_service

File Transfer Between Host and Container

# Copy a file from a container to the host
docker cp my_container:/app/config.yaml /backup/

# Upload a file from the host to a container
docker cp /data/update.patch my_container:/tmp/

Dockerfile

Common Dockerfile instructions are as follows; building the image is done with docker build -t image-name:tag Dockerfile-directory.

# ========== Base image configuration ==========
# Use the official Alpine base image (lightweight, only 5MB)
# Multi-stage build example: the first stage is named builder, used as the compile environment
FROM alpine:3.18 AS builder
# Maintainer info (replaces the deprecated MAINTAINER)
LABEL maintainer="yourname@example.com"

# ========== Environment variables and arguments ==========
# Set the application path inside the container
ENV APP_HOME=/app
# Build-time argument, can be overridden with --build-arg
ARG BUILD_VERSION=1.0.0

# ========== System configuration ==========
# Update the system and install dependencies (combine RUN commands to reduce image layers)
RUN apk update && apk add --no-cache \
    python3 \
    py3-pip \
    curl \
    nginx \
    && rm -rf /var/cache/apk/*

# ========== File operations ==========
# Set the working directory
WORKDIR $APP_HOME
# Copy local files into the image (prefer COPY)
COPY requirements.txt .
# Automatically extracts remote files (use ADD with caution)
ADD https://example.com/static-assets.tar.gz /tmp

# ========== Application build ==========
# Install Python dependencies
RUN pip3 install --no-cache-dir -r requirements.txt
# Copy the application source code
COPY src/ .

# ========== Network and storage ==========
# Declare the listening port (needs docker run -p mapping)
EXPOSE 8080
# Declare a persistent data volume
VOLUME ["/data"]

# ========== Security configuration ==========
# Create a non-root user
RUN adduser -D appuser && chown -R appuser:appuser $APP_HOME
# Switch the runtime user
USER appuser

# ========== Health check ==========
HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:8080/health || exit 1

# ========== Multi-stage build ==========
# Second stage: the production image
FROM alpine:3.18 AS production
# Copy the build result from the builder stage
COPY --from=builder /app /app
WORKDIR /app

# ========== Startup command ==========
# Prefer the exec form to avoid shell parsing issues
# Fixed entrypoint; when multiple entrypoints exist, only the last one takes effect
ENTRYPOINT ["python3"]
# Default arguments passed to the entrypoint (can be overridden by docker run)
# e.g. `docker run image-name:tag main.py`
# then the container no longer runs `python3 app.py` on startup, but runs `python3 main.py`
CMD ["app.py"]

# ========== Metadata ==========
# Triggered automatically when a child image is built
ONBUILD COPY . /app

Resource Management

Docker resource management matters: it protects other containers from being affected by coding problems such as memory leaks, infinite loops, and large file reads/writes (uploads/downloads), so that a single memory leak does not freeze and stop every container together.

CPU Shares

CPU share numbers only matter when resources are contended.

The proportion of CPU time slices a container occupies is its own share divided by the total shares of all contending containers.

If running on multiple CPUs, or when there is no contention, even a share of 1 can occupy an entire CPU.

docker run -itd \
  # Declare the name of the container to create
  --name test-cpu-1 \
  # Specify the container's CPU weight
  --cpu-shares 50 \
  # The image to use
  centos

Pinning a Container to Specific CPU Cores

docker run -itd \
  # Declare the name of the container to create
  --name test-cpu-2 \
  # Restrict the container to CPU 0 and CPU 1
  --cpuset-cpus 0,1 \
  # Specify the container's CPU weight
  --cpu-shares 512 \
  # The image to use
  centos

Limiting a Container's Memory

docker run -itd \
  # Declare the name of the container to create
  --name test-memory \
  # Use at most 0.5G of memory
  --memory 512m \
  # The image to use
  centos

Limiting a Container's I/O Resources

docker run -itd \
  # Declare the name of the container to create
  --name test-io \
  # Specify a partition rather than a whole disk
  --device=/dev/sda1 \
  # Grant device operation permissions
  --cap-add=SYS_RAWIO \
  # Mount a volume; mounted volumes go through file reads and writes, not the low-level API, and may bypass the read/write limits
  # When mounting with -v, if the external directory is deleted, even creating a same-named directory later will not sync it into docker
  # because the corresponding inode can no longer be found
  -v /var/www/html:/var/www/html \
  # Limit read speed to 10mbps/s
  --device-read-bps /dev/sda1:10mb \
  # Limit write speed to 1mbps/s
  --device-write-bps /dev/sda1:1mb \
  # The image to use
  centos

Automatic Resource Release

docker run -itd \
  # Declare the name of the container to create
  --name test-auto-free \
  # Automatically release after execution finishes, for scenarios where the container acts as a job runner
  # such as the build stage in a build scenario, a stress-test runtime environment, and so on
  --rm \
  # The image to use
  centos \
  # The command to run
  sleep 8