Managing Docker Performance
1. Monitoring Resource Usage
| Resource | Command | Description |
|---|---|---|
| CPU Usage | docker stats |
Displays real-time CPU usage for running containers |
| Memory Usage | docker stats --format "table {{.Container}}\t{{.MemUsage}}" |
Shows memory consumption per container |
| Disk I/O | docker stats --format "table {{.Container}}\t{{.BlockIO}}" |
Displays block I/O statistics |
| Network I/O | docker stats --format "table {{.Container}}\t{{.NetIO}}" |
Shows network input/output statistics |
Example: Monitoring CPU and Memory Usage
docker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}" --no-stream
Note: The
--no-stream flag prevents continuous output, useful for scripting or one-time checks.
Example: Filtering Containers by Name
docker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}" --filter name=web
Warning:
docker stats can be resource-intensive when used with many containers. Use filters to limit output.
2. Optimizing Build Cache
| Instruction | Description | Best Practice |
|---|---|---|
| COPY --from | Copies files from another build stage or image | Use multi-stage builds to reduce layer size and improve cache efficiency |
| COPY . . | Copies all files from the host to the container | Use .dockerignore to exclude unnecessary files and directories |
| RUN apt-get update && apt-get install | Installs packages using the package manager | Combine RUN commands to reduce layers and avoid caching issues |
Example: Efficient Dockerfile with Cache Optimization
FROM node:18-alpine
# Copy package files first to leverage cache
COPY package*.json ./
RUN npm ci --only=production
# Copy application code after dependencies are installed
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Note: The order of instructions in a Dockerfile is crucial for effective caching. Changes to earlier instructions invalidate subsequent layers.
Warning: Avoid copying entire directories without
.dockerignore, as it can cause unnecessary rebuilds.
3. Using Volume Performance Options
| Option | Description | Notes |
|---|---|---|
| --volume-driver | Specifies the volume driver to use for creating volumes. | Defaults to local. Can be set to aws, gce, or custom drivers. |
| --mount | Mounts a volume or bind mount into the container. | More flexible than -v, supports additional options like bind-propagation. |
| --tmpfs | Mounts a temporary filesystem in memory. | Useful for ephemeral data, not persisted on disk. Ideal for cache or temporary files. |
Example: Mounting a volume with performance options
docker run --mount type=volume,source=myvol,target=/app/data,bind-propagation=rshared myapp
Note: Performance can be improved by using
--tmpfs for temporary data and --mount with bind-propagation for shared volumes.
Warning:
--tmpfs is not persisted across container restarts and uses memory.
4. Configuring Storage Driver Settings
| Driver | Description | Default | Notes |
|---|---|---|---|
| aufs | Union filesystem, older driver | Yes (on some systems) | DEPRECATED in Docker 20.10+ |
| overlay2 | Union filesystem, modern and preferred | Yes (on most systems) | Recommended for production |
| btrfs | Btrfs filesystem driver | No | Requires Btrfs filesystem |
| zfs | ZFS filesystem driver | No | Requires ZFS pool |
| devicemapper | Device mapper driver (legacy) | No | DEPRECATED in Docker 20.10+ |
Note: The storage driver must be set at Docker daemon startup and cannot be changed without reconfiguring the daemon.
Storage Driver Configuration Tips
- Use
overlay2for most modern Linux systems. - Ensure sufficient disk space and I/O performance for the storage backend.
- For production,
overlay2is recommended overaufsordevicemapper.
5. Implementing Resource Constraints
| Resource Type | Configuration Option | Description | Default Value |
|---|---|---|---|
| CPU | --cpus |
Limit the number of CPUs available to a container | Unlimited |
| Memory | --memory |
Set the maximum amount of memory a container can use | Unlimited |
| Memory Swap | --memory-swap |
Set the total memory plus swap a container can use | Unlimited |
| Memory Reservation | --memory-reservation |
Set the memory that is reserved for the container | Unlimited |
| CPU Shares | --cpu-shares |
Set relative CPU shares for a container | 1024 |
| CPU Period | --cpu-period |
Set the CPU period for CPU quota enforcement (microseconds) | 100,000 |
| CPU Quota | --cpu-quota |
Set the CPU time that a container can use in a period (microseconds) | -1 (unlimited) |
Note: Setting
--memory-swap to the same value as --memory disables swap.
Warning: If
--memory-swap is set to a value less than --memory, it will cause an error.
6. Optimizing Network Performance
| Option | Values | Description |
|---|---|---|
| --network | bridge, host, none |
Set container network mode. host offers best performance by sharing host network stack. |
| --network-alias | alias-name |
Assigns an alias to a container for easier service discovery in custom networks. |
| --add-host | hostname:ip |
Adds a custom entry to the container's /etc/hosts file for faster DNS resolution. |
Note: Using
--network host disables network isolation and should be used carefully in production environments.
Network Optimization Tips
- Use
--network hostfor high-performance, low-latency communication. - Use custom networks with
--network-aliasfor better service discovery. - Use
--add-hostto reduce DNS lookups in containers.
7. Using BuildKit for Faster Builds
| Feature | Description | Notes |
|---|---|---|
| DOCKER_BUILDKIT=1 | Enables BuildKit for docker build commands | Set as environment variable or in ~/.docker/config.json |
| buildkit | BuildKit driver option in docker config | Can be set to "enabled" or "disabled" |
Note: BuildKit is enabled by default in Docker 18.09 and later.
Key Benefits of BuildKit
- Parallel builds with better caching
- Improved layer caching
- Reduced image sizes through pruning
- Support for multi-platform builds
BuildKit Optimization Steps
- Enable BuildKit via environment variable or config
- Use
--no-cachefor clean builds - Optimize Dockerfile instructions for caching
- Utilize
--targetfor multi-stage builds
8. Parallel Container Execution
Example: Running Multiple Containers Concurrently
docker run -d --name app1 myapp:latest
docker run -d --name app2 myapp:latest
docker run -d --name app3 myapp:latest
| Option | Values | Description |
|---|---|---|
| --detach, -d | true |
Run containers in background |
| --name | container-name |
Assign a name to the container |
Note: Parallel execution is managed by the Docker daemon and OS-level resource allocation.
Warning: Ensure sufficient system resources (CPU, memory) to avoid performance degradation.
Best Practices for Parallel Execution
- Monitor resource usage with
docker stats - Use resource limits (
--memory,--cpus) to prevent overconsumption - Consider using Docker Compose for managing multi-container setups
9. Minimizing Image Pulls
| Option | Values | Notes |
|---|---|---|
| docker pull | image:tag |
Explicitly pull image to local registry |
| docker build | -t image:tag . |
Build and tag image locally without pulling |
| --no-cache | true |
Force rebuild without using cached layers |
Note: Using
--no-cache ensures that all layers are rebuilt, which can help avoid outdated dependencies but increases build time.
10. Using Local Registry for Caching
Example: Setting up a local registry with caching
docker run -d \
--name local-registry \
--restart=always \
-p 5000:5000 \
registry:2
| Configuration | Description | Default |
|---|---|---|
| registry.port | Port to run the local registry on | 5000 |
| registry.storage.path | Storage path for registry data | /var/lib/registry |
Note: The local registry must be configured to use a volume or bind mount for persistent storage.
Workflow: Pushing to local registry
- Tag image with local registry address:
docker tag myapp localhost:5000/myapp - Push image to local registry:
docker push localhost:5000/myapp - Use image from local registry in deployments:
docker run localhost:5000/myapp
11. Optimizing Layer Caching Strategy
| Instruction | Description | Best Practice |
|---|---|---|
| FROM | Base image for the Dockerfile | Use a specific tag (e.g., node:18-alpine) to ensure consistency and avoid pulling latest |
| COPY / ADD | Copy files from host to container | Order instructions to minimize cache invalidation; place less frequently changed files first |
| RUN | Execute commands in the container | Combine multiple RUN instructions with && to reduce layers and avoid unnecessary cleanup |
| WORKDIR | Set working directory | Use WORKDIR to avoid repeating paths in subsequent commands |
| ENV | Set environment variables | Use ENV for values that change infrequently to avoid rebuilding layers unnecessarily |
Example: Layer Caching Optimization
FROM node:18-alpine
# Copy package files first to leverage layer caching
COPY package*.json ./
# Install dependencies before copying app code
RUN npm ci --only=production
# Copy application code after installing dependencies
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Note: Docker uses a
content-based hash to determine if a layer has changed. Any change in the instruction order or content will invalidate the cache and force re-building of subsequent layers.Key Tips for Layer Caching
- Minimize file changes to keep layers cached
- Place stable instructions first (e.g., dependencies, base image)
- Use .dockerignore to exclude unnecessary files from being copied into the image
- Avoid
RUNcommands with frequent changes (e.g.,apt-get update)
12. Profiling Container Performance
| Metric | Description | Tools | Notes |
|---|---|---|---|
| CPU Usage | Percentage of CPU time consumed by the container | docker stats, top |
Can be normalized per core for comparison |
| Memory Usage | Amount of RAM used by the container | docker stats, ps |
Includes cache and buffers |
| Network I/O | Data sent and received by the container | docker stats, iftop |
Can be monitored per container or globally |
| Disk I/O | Read and write operations on storage devices | iostat, iotop |
Useful for identifying bottlenecks in storage-heavy apps |
Example: Collecting detailed stats using docker inspect
docker inspect {container_id} | grep -A 5 "Stats"
Note:
docker stats provides real-time metrics, while docker inspect offers more static details about container configuration and runtime state.