Docker 是现代软件开发和运维的基础设施。本指南从核心概念出发,系统覆盖镜像管理、容器生命周期、网络配置、数据持久化、多容器编排、生产环境最佳实践及安全基线,旨在为技术团队提供一份可落地、可查阅的完整参考手册。
Docker 是一个开源的容器化平台,它允许开发者将应用及其依赖打包到一个轻量级、可移植的容器中,从而在任何环境中都能一致地运行。与传统虚拟机相比,Docker 容器共享宿主机的操作系统内核,无需启动完整的操作系统,因此具有启动速度快、资源占用少、性能开销低等显著优势。
镜像是 Docker 容器的只读模板,包含了运行应用所需的所有内容:代码、运行时环境、系统工具、系统库和配置文件。镜像采用分层存储机制,每一层都是前一层的增量修改,这种设计使得镜像可以高效地复用和共享。
理解镜像的关键点:
容器是镜像的运行实例。它是一个独立、隔离的运行环境,拥有自己独立的文件系统、网络接口和进程空间。容器与镜像的关系类似于面向对象编程中对象与类的关系。
容器的核心特征:
Docker Registry 是存储和分发镜像的服务。Docker Hub 是官方提供的公共仓库,企业通常会搭建私有 Registry(如 Harbor)来管理内部镜像。
主要 Registry 类型:
Docker 采用客户端-服务器架构,主要组件包括:
| 组件 | 职责 |
|---|---|
| Docker Daemon | 后台服务进程,负责管理容器生命周期、镜像存储和网络 |
| Docker Client | 命令行工具,通过 REST API 与 Daemon 通信 |
| Containerd | 容器运行时,负责实际的容器创建和管理 |
| Runc | 低层容器运行时,遵循 OCI 标准 |
| Docker Compose | 多容器编排工具,通过 YAML 文件定义应用栈 |
# Debian/Ubuntu
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# 将当前用户加入 docker 组(免 sudo 使用)
sudo usermod -aG docker $(whoami)
newgrp docker
# 验证安装
docker --version
docker run hello-world
推荐使用 Docker Desktop for Mac,它包含完整的 Docker 引擎和 Kubernetes 支持。
# 通过 Homebrew 安装
brew install --cask docker
# 启动后验证
docker --version
Windows 10/11 专业版或企业版支持 Docker Desktop,依赖 WSL2 后端。
国内网络环境下,配置镜像加速器可以显著提升镜像拉取速度。
# 编辑 /etc/docker/daemon.json
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
{
"storage-driver": "overlay2",
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
},
"live-restore": true,
"userland-proxy": false,
"no-new-privileges": true
}
# 在 Docker Hub 搜索镜像
docker search nginx
# 拉取官方镜像(默认 latest 标签)
docker pull nginx
# 拉取指定版本
docker pull nginx:1.24.0-alpine
# 从私有仓库拉取
docker pull myregistry.com:5000/myapp:v2.1
# 列出本地镜像
docker images
docker image ls
# 查看镜像详情
docker inspect nginx:alpine
# 查看镜像历史(构建层)
docker history nginx:alpine
# 删除镜像
docker rmi nginx:alpine
# 清理悬空镜像(无标签、无引用的层)
docker image prune
# 清理所有未使用的镜像
docker image prune -a
# 给镜像打标签
docker tag nginx:alpine myregistry.com:5000/nginx:alpine
# 推送镜像到仓库
docker push myregistry.com:5000/nginx:alpine
# 将镜像保存为 tar 文件
docker save -o nginx-alpine.tar nginx:alpine
# 从 tar 文件加载镜像
docker load -i nginx-alpine.tar
# 导出运行中容器的文件系统(不包含历史和元数据)
docker export -o container-fs.tar container_name
# 基本运行(前台运行,Ctrl+C 停止)
docker run nginx:alpine
# 后台运行(detached 模式)
docker run -d --name my-nginx nginx:alpine
# 交互式运行(带 TTY)
docker run -it --rm ubuntu:22.04 bash
# 常用选项说明
# -d, --detach 后台运行
# -it 交互式 + TTY
# --rm 停止后自动删除容器
# --name 指定容器名称
# -p, --publish 端口映射(主机端口:容器端口)
# -v, --volume 挂载卷
# -e, --env 设置环境变量
# --network 指定网络
# --restart 重启策略
# --memory 内存限制
# --cpus CPU 限制
# 列出运行中的容器
docker ps
# 列出所有容器(包括停止的)
docker ps -a
# 启动已停止的容器
docker start container_name
# 停止容器(发送 SIGTERM,超时后 SIGKILL)
docker stop container_name
# 强制停止(发送 SIGKILL)
docker kill container_name
# 重启容器
docker restart container_name
# 暂停容器(冻结进程)
docker pause container_name
# 恢复暂停的容器
docker unpause container_name
# 删除容器
docker rm container_name
# 强制删除运行中的容器
docker rm -f container_name
# 清理所有停止的容器
docker container prune
# 查看容器日志
docker logs container_name
docker logs -f container_name # 实时跟踪
docker logs --tail 100 container_name # 最后 100 行
# 查看容器进程
docker top container_name
# 查看容器资源使用
docker stats container_name
# 查看容器详细信息
docker inspect container_name
# 查看容器文件系统变更
docker diff container_name
# 使用 exec 执行新进程(推荐)
docker exec -it container_name bash
docker exec -it container_name sh
# 使用 attach 附加到主进程(不推荐,exit 会停止容器)
docker attach container_name
# 从容器复制文件到主机
docker cp container_name:/etc/nginx/nginx.conf ./nginx.conf
# 从主机复制文件到容器
docker cp ./app.js container_name:/app/
# 注意:cp 的目标路径一般是 Volume,否则容器重建后数据丢失
Volume 是 Docker 管理的持久化存储,独立于容器生命周期。
# 创建卷
docker volume create my-data
# 列出卷
docker volume ls
# 查看卷详情
docker volume inspect my-data
# 使用卷运行容器
docker run -d -v my-data:/data nginx:alpine
# 删除卷
docker volume rm my-data
# 清理未使用的卷
docker volume prune
将主机的特定目录挂载到容器中。
# 基本绑定挂载
docker run -d -v /host/path:/container/path nginx:alpine
# 只读挂载
docker run -d -v /host/path:/container/path:ro nginx:alpine
# 使用 --mount 语法(更明确)
docker run -d --mount type=bind,source=/host/path,target=/container/path,readonly nginx:alpine
将数据存储在内存中,适合敏感数据或临时缓存。
docker run -d --tmpfs /app/cache:rw,noexec,nosuid,size=100m nginx:alpine
| 场景 | 推荐方案 | 说明 |
|---|---|---|
| 数据库数据 | Volume | Docker 管理,易于备份和迁移 |
| 应用配置 | Bind Mount | 便于直接编辑和版本控制 |
| 日志文件 | Bind Mount 或 Volume | 需要长期保留和分析 |
| 临时缓存 | tmpfs | 内存存储,重启后清空 |
| 静态资源 | Bind Mount(开发)/ COPY(生产) | 开发时便于实时更新 |
| 模式 | 说明 | 适用场景 |
|---|---|---|
| bridge | 默认桥接网络 | 单机容器间通信 |
| host | 共享主机网络栈 | 需要直接访问主机网络 |
| none | 无网络 | 完全隔离 |
| container | 共享另一个容器的网络 | Sidecar 模式 |
# 基本端口映射
docker run -d -p 8080:80 nginx:alpine
# 指定主机 IP
docker run -d -p 127.0.0.1:8080:80 nginx:alpine
# 随机分配主机端口
docker run -d -p 80 nginx:alpine
# UDP 端口映射
docker run -d -p 53:53/udp nginx:alpine
# 查看端口映射
docker port container_name
# 创建桥接网络
docker network create my-network
# 创建指定子网的网络
docker network create --subnet=172.20.0.0/16 my-network
# 列出网络
docker network ls
# 查看网络详情
docker network inspect my-network
# 运行容器并加入网络
docker run -d --network my-network --name app1 nginx:alpine
docker run -d --network my-network --name app2 nginx:alpine
# 容器间可以通过容器名互相访问
# app1 中可以直接 ping app2
# 连接容器到网络
docker network connect my-network container_name
# 断开容器网络
docker network disconnect my-network container_name
# 删除网络
docker network rm my-network
同一自定义网络中的容器可以通过容器名进行 DNS 解析和通信,无需显式端口映射。
# 创建应用网络
docker network create app-net
# 启动数据库
docker run -d --name db --network app-net -e POSTGRES_PASSWORD=secret postgres:15
# 启动应用(可以通过 http://db:5432 访问数据库)
docker run -d --name app --network app-net myapp:latest
# 基础镜像
FROM node:18-alpine
# 维护者信息(已废弃,推荐使用 LABEL)
# MAINTAINER name@example.com
# 元数据标签
LABEL maintainer="name@example.com"
LABEL version="1.0"
LABEL description="My application"
# 环境变量
ENV NODE_ENV=production
ENV PORT=3000
# 工作目录
WORKDIR /app
# 先复制依赖定义(利用缓存层)
COPY package*.json ./
# 安装依赖
RUN npm ci --only=production
# 复制应用代码
COPY . .
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 CMD curl -f http://localhost:3000/health || exit 1
# 暴露端口(仅声明,不实际映射)
EXPOSE 3000
# 非 root 用户运行
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
USER nodejs
# 启动命令
CMD ["node", "server.js"]
# 或入口点(可被覆盖)
ENTRYPOINT ["node"]
CMD ["server.js"]
# 基本构建
docker build -t myapp:1.0 .
# 指定 Dockerfile
docker build -f Dockerfile.prod -t myapp:prod .
# 不使用缓存(强制重新构建)
docker build --no-cache -t myapp:1.0 .
# 构建参数
DOCKER_BUILDKIT=1 docker build --build-arg NODE_ENV=production -t myapp:1.0 .
# 多平台构建
DOCKER_BUILDKIT=1 docker build --platform linux/amd64,linux/arm64 -t myapp:1.0 .
多阶段构建可以显著减小最终镜像体积,只保留编译产物。
# 构建阶段
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 生产阶段(仅包含运行所需文件)
FROM node:18-alpine AS production
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
USER node
CMD ["node", "dist/main.js"]
# .dockerignore
node_modules
.git
.env
*.md
dist
.vscode
version: "3.9"
services:
web:
build:
context: ./web
dockerfile: Dockerfile
image: myapp-web:1.0
container_name: myapp-web
restart: unless-stopped
ports:
- "8080:80"
environment:
- NODE_ENV=production
- API_URL=http://api:3000
env_file:
- .env
volumes:
- web-data:/var/www/html
- ./config/nginx.conf:/etc/nginx/nginx.conf:ro
networks:
- frontend
- backend
depends_on:
- api
- db
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
api:
build: ./api
container_name: myapp-api
restart: unless-stopped
environment:
- DB_HOST=db
- DB_PORT=5432
- REDIS_HOST=redis
volumes:
- api-logs:/app/logs
networks:
- backend
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
db:
image: postgres:15-alpine
container_name: myapp-db
restart: unless-stopped
environment:
POSTGRES_USER: myapp
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: myapp
volumes:
- db-data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U myapp"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: myapp-redis
restart: unless-stopped
volumes:
- redis-data:/data
networks:
- backend
command: redis-server --appendonly yes --maxmemory 256mb
volumes:
web-data:
api-logs:
driver: local
db-data:
redis-data:
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 无外部访问
# 启动所有服务(后台)
docker-compose up -d
# 启动并重建镜像
docker-compose up -d --build
# 停止服务
docker-compose down
# 停止并删除卷
docker-compose down -v
# 查看服务状态
docker-compose ps
# 查看服务日志
docker-compose logs -f
# 查看特定服务日志
docker-compose logs -f api
# 重启服务
docker-compose restart api
# 扩展服务实例数
docker-compose up -d --scale api=3
# 执行服务命令
docker-compose exec db psql -U myapp
# 拉取最新镜像
docker-compose pull
# 验证配置文件
docker-compose config
# 1. 非 root 运行
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
USER appuser
# 2. 只读根文件系统
docker run --read-only -v /tmp:/tmp:rw myapp
# 3. 禁用权限提升
docker run --security-opt no-new-privileges:true myapp
# 4. 丢弃 capabilities
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE myapp
# 5. 资源限制
docker run --memory=512m --memory-swap=512m --cpus=1.0 myapp
# 6. 重启策略
docker run --restart=unless-stopped myapp
# 配置日志驱动
# daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3",
"labels": "production_status",
"env": "OS,CUSTOMER"
}
}
# 或使用 syslog
docker run --log-driver=syslog --log-opt syslog-address=tcp://logs.example.com:514 myapp
# Dockerfile 中定义健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 CMD curl -fsS http://localhost:3000/health > /dev/null || exit 1
# 查看健康状态
docker inspect --format='{{.State.Health.Status}}' container_name
# 查看健康检查历史
docker inspect --format='{{json .State.Health}}' container_name | jq
# 备份数据卷
docker run --rm -v my-data:/data -v $(pwd):/backup alpine tar czf /backup/my-data-backup.tar.gz -C /data .
# 恢复数据卷
docker run --rm -v my-data:/data -v $(pwd):/backup alpine tar xzf /backup/my-data-backup.tar.gz -C /data
# 备份数据库
docker exec myapp-db pg_dump -U myapp myapp > backup.sql
# 恢复数据库
docker exec -i myapp-db psql -U myapp myapp < backup.sql
docker run -d --name local-postgres --restart unless-stopped -p 5432:5432 -e POSTGRES_DB=myapp -e POSTGRES_USER=myapp -e POSTGRES_PASSWORD=mysecretpassword -v postgres-data:/var/lib/postgresql/data postgres:15-alpine
docker run -d --name local-redis --restart unless-stopped -p 6379:6379 -v redis-data:/data redis:7-alpine redis-server --appendonly yes --requirepass mypassword
docker run -d --name nginx-proxy --restart unless-stopped -p 80:80 -p 443:443 -v /host/nginx.conf:/etc/nginx/nginx.conf:ro -v /host/ssl:/etc/nginx/ssl:ro -v /host/html:/usr/share/nginx/html:ro nginx:alpine
# 从镜像运行一个临时 Bash(用后即弃)
docker run --rm -it --entrypoint bash httpd:2.4.52
# 进入运行中的容器
docker exec -it container-name bash
# 容器无法启动
docker logs container_name # 查看启动日志
docker inspect container_name # 查看配置详情
# 网络问题
docker network inspect network_name # 查看网络配置
docker exec container_name ping target # 测试连通性
# 存储问题
docker volume inspect volume_name # 查看卷详情
docker exec container_name df -h # 查看磁盘使用
# 性能问题
docker stats # 实时资源使用
docker top container_name # 查看容器进程
# 清理停止的容器
docker container prune
# 清理未使用的镜像
docker image prune -a
# 清理未使用的卷
docker volume prune
# 清理未使用的网络
docker network prune
# 一键清理所有未使用资源
docker system prune -a --volumes
# 查看磁盘使用
docker system df -v
# 覆盖入口点进行调试
docker run --rm -it --entrypoint sh myapp:latest
# 复制容器内文件出来分析
docker cp container_name:/app/logs ./logs
# 导出容器文件系统
docker export container_name -o container-fs.tar
# 查看容器环境变量
docker exec container_name env
# 查看容器网络接口
docker exec container_name ip addr
| 命令 | 说明 |
|---|---|
| docker pull image:tag | 拉取镜像 |
| docker push image:tag | 推送镜像 |
| docker build -t name:tag . | 构建镜像 |
| docker images | 列出镜像 |
| docker rmi image | 删除镜像 |
| docker tag source target | 打标签 |
| docker save -o file.tar image | 导出镜像 |
| docker load -i file.tar | 导入镜像 |
| docker image prune | 清理悬空镜像 |
| 命令 | 说明 |
|---|---|
| docker run [opts] image | 创建并启动容器 |
| docker start container | 启动容器 |
| docker stop container | 停止容器 |
| docker restart container | 重启容器 |
| docker rm container | 删除容器 |
| docker ps -a | 列出所有容器 |
| docker logs container | 查看日志 |
| docker exec -it container sh | 进入容器 |
| docker cp src dest | 复制文件 |
| docker inspect container | 查看详情 |
| docker stats | 资源使用 |
| 命令 | 说明 |
|---|---|
| docker volume create name | 创建卷 |
| docker volume ls | 列出卷 |
| docker volume rm name | 删除卷 |
| docker network create name | 创建网络 |
| docker network ls | 列出网络 |
| docker network connect net container | 连接网络 |
| 命令 | 说明 |
|---|---|
| docker-compose up -d | 后台启动 |
| docker-compose down | 停止并移除 |
| docker-compose ps | 查看状态 |
| docker-compose logs -f | 跟踪日志 |
| docker-compose build | 构建镜像 |
| docker-compose pull | 拉取镜像 |
| docker-compose exec service cmd | 执行命令 |
| docker-compose restart | 重启服务 |
本文档持续更新,建议结合官方文档 https://docs.docker.com 使用。