3413 字
17 分钟
Docker 完全指南 2026:镜像 / 容器 / 网络 / Compose / 生产部署最佳实践
Docker 是现代应用部署的基础设施,无论是个人项目还是企业级服务,容器化都已成为标配。本文覆盖 Docker 从入门到生产部署的全链路知识,重点关注 2026 年实际使用中遇到的问题——尤其是国内镜像加速失效、多阶段构建优化、Compose 生产配置等实战场景。
一、安装与国内镜像加速
1.1 安装 Docker(Linux)
# 一键安装(Debian/Ubuntu,官方脚本)curl -fsSL https://get.docker.com | sh
# 安装完成后,将当前用户加入 docker 组(免 sudo)sudo usermod -aG docker $USERnewgrp docker # 立即生效(或重新登录)
# 验证docker --version # Docker version 26.x.xdocker compose version # Docker Compose version v2.x.x(注意:v2 是 compose 子命令,不再是独立的 docker-compose)1.2 国内镜像加速(2026 可用方案)
⚠️ 2024-2025 年,DaoCloud、网易云、USTC 等加速器陆续停止服务。以下是 2026 年仍可用的方案。
方案 A:通过本地代理软件(推荐,最稳定)
如果你的服务器或本机安装了代理软件(监听 7890 端口),配置 Docker 走代理:
# 创建 Docker 服务的 systemd 环境变量目录sudo mkdir -p /etc/systemd/system/docker.service.d
# 创建代理配置文件sudo cat > /etc/systemd/system/docker.service.d/http-proxy.conf << 'EOF'[Service]Environment="HTTP_PROXY=socks5://127.0.0.1:7890"Environment="HTTPS_PROXY=socks5://127.0.0.1:7890"Environment="NO_PROXY=localhost,127.0.0.1,registry.cn-hangzhou.aliyuncs.com"EOF
sudo systemctl daemon-reloadsudo systemctl restart docker
# 验证代理生效docker pull hello-world方案 B:daemon.json 配置镜像源(部分可用)
{ "registry-mirrors": [ "https://docker.m.daocloud.io", "https://hub-mirror.c.163.com" ], "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" }}sudo systemctl daemon-reload && sudo systemctl restart dockerdocker info | grep -A5 "Registry Mirrors"方案 C:使用阿里云容器镜像服务(自己搬运)
在阿里云 ACR 免费版中建立镜像同步仓库,将 DockerHub 镜像同步到阿里云,再从 registry.cn-hangzhou.aliyuncs.com 拉取。
二、Docker 基础命令速查
2.1 镜像操作
# ── 搜索与拉取 ────────────────────────────────────────────────docker search nginx # 搜索镜像docker pull nginx:1.27-alpine # 拉取指定版本(强烈建议指定 tag!)docker pull nginx:latest # 拉取最新版(生产环境慎用 latest)
# ── 查看与管理 ────────────────────────────────────────────────docker images # 查看本地镜像列表docker image ls --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" # 格式化显示docker image inspect nginx:1.27-alpine # 查看镜像详细信息docker image history nginx:1.27-alpine # 查看镜像构建层
# ── 导出与导入 ────────────────────────────────────────────────docker save nginx:1.27-alpine | gzip > nginx.tar.gz # 导出镜像到文件docker load < nginx.tar.gz # 从文件导入镜像
# ── 清理 ──────────────────────────────────────────────────────docker image rm nginx:latest # 删除指定镜像docker image prune # 删除所有悬空镜像(无 tag 的)docker image prune -a # 删除所有未被容器使用的镜像(⚠️ 谨慎)2.2 容器操作
# ── 运行容器 ──────────────────────────────────────────────────docker run nginx # 前台运行(Ctrl+C 停止)docker run -d nginx # 后台运行(detached)docker run -d --name my-nginx nginx # 指定容器名docker run -d -p 8080:80 nginx # 端口映射(宿主:容器)docker run -d -v /data/html:/usr/share/nginx/html nginx # 挂载目录docker run -d --restart unless-stopped nginx # 重启策略
# ── 进入容器 ──────────────────────────────────────────────────docker exec -it my-nginx /bin/sh # 进入运行中的容器(推荐 /bin/sh 更兼容)docker exec my-nginx ls /usr/share/nginx/html # 不交互,直接执行命令
# ── 查看容器状态 ──────────────────────────────────────────────docker ps # 查看运行中的容器docker ps -a # 查看所有容器(含已停止)docker logs my-nginx # 查看日志docker logs -f my-nginx # 实时跟踪日志(follow)docker logs --tail 100 my-nginx # 最后 100 行日志docker stats # 实时资源占用(CPU/内存/网络)docker inspect my-nginx # 容器详情
# ── 生命周期管理 ──────────────────────────────────────────────docker stop my-nginx # 优雅停止(发送 SIGTERM,等待 10 秒)docker kill my-nginx # 强制停止(发送 SIGKILL)docker start my-nginx # 启动已停止的容器docker restart my-nginx # 重启容器docker rm my-nginx # 删除已停止的容器docker rm -f my-nginx # 强制删除(运行中也删除)
# ── 清理 ──────────────────────────────────────────────────────docker container prune # 删除所有已停止的容器docker system prune # 清理所有未使用的资源(容器/镜像/网络/缓存)docker system prune -a --volumes # 同上 + 删除 volumes(⚠️ 会丢数据!)三、Dockerfile:构建自定义镜像
3.1 Dockerfile 核心指令
# ── 基础指令 ──────────────────────────────────────────────────
FROM node:20-alpine AS base# 基础镜像。使用 alpine 变体体积更小
WORKDIR /app# 设置工作目录(后续指令的默认路径,如不存在则自动创建)
COPY package*.json ./# 复制文件/目录(src dst)# 先复制 package.json,利用 Docker 层缓存——只有 package.json 变了才重新安装依赖
RUN npm ci --only=production# 执行命令(每个 RUN 创建一个新层)# npm ci 比 npm install 更适合 CI 环境:严格按 package-lock.json 安装
COPY . .# 复制其他源码(在安装依赖之后,利用缓存)
ENV NODE_ENV=production# 设置环境变量
EXPOSE 3000# 声明容器监听的端口(文档作用,不自动发布)
ENTRYPOINT ["node"]# 容器启动时执行的命令(不可被 docker run 参数覆盖)
CMD ["server.js"]# ENTRYPOINT 的默认参数,可被 docker run 后的参数覆盖3.2 多阶段构建(减小镜像体积的关键)
多阶段构建是生产级 Dockerfile 的核心技术,将”构建环境”和”运行环境”分离:
Python 项目示例:从 ~500MB 到 ~80MB
# ── 阶段1:构建(安装依赖、编译)────────────────────────────────FROM python:3.12-slim AS builder
WORKDIR /app
# 安装 uv(快速依赖管理)RUN pip install uv
# 复制依赖文件并安装到虚拟环境COPY pyproject.toml uv.lock ./RUN uv venv /opt/venv && \ uv sync --frozen --no-dev --python /opt/venv/bin/python
# 复制源码COPY src/ ./src/
# ── 阶段2:最终镜像(只包含运行所需文件)────────────────────────FROM python:3.12-slim AS final
# 安全:创建非 root 用户RUN useradd --no-create-home --shell /bin/false appuser
WORKDIR /app
# 从 builder 阶段复制虚拟环境COPY --from=builder /opt/venv /opt/venv# 复制源码COPY --from=builder /app/src ./src
# 设置 PATH 使用虚拟环境ENV PATH="/opt/venv/bin:$PATH"
# 使用非 root 用户运行USER appuser
EXPOSE 8000CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]Go 项目示例:从 ~1GB 到 ~10MB
# 阶段1:编译FROM golang:1.22-alpine AS builderWORKDIR /appCOPY go.mod go.sum ./RUN go mod downloadCOPY . .# 静态链接,无需任何运行时库RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o server ./cmd/server
# 阶段2:最小化运行镜像(甚至比 alpine 还小)FROM scratch AS final# scratch 是完全空的镜像!COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ # HTTPS 需要COPY --from=builder /app/server /serverEXPOSE 8080ENTRYPOINT ["/server"]3.3 .dockerignore 文件(必须配置)
.git.gitignore**/.DS_Store**/__pycache__**/*.pyc**/.pytest_cache**/.mypy_cache**/.ruff_cachenode_modulesdistbuild*.log.env.env.*docker-compose*.ymlDockerfile*README.mddocs/3.4 构建最佳实践总结
✅ 使用特定版本 tag,不用 latest✅ 多阶段构建分离构建环境和运行环境✅ 先复制 package.json/requirements.txt,再安装依赖(利用层缓存)✅ 合并相关 RUN 命令,减少层数✅ 配置 .dockerignore 排除不必要文件✅ 使用非 root 用户运行应用✅ 只安装运行时需要的依赖(--no-dev / --only=production)✅ 使用 alpine 或 slim 基础镜像四、Docker 网络与数据持久化
4.1 网络模式
# ── 查看网络 ──────────────────────────────────────────────────docker network ls# NETWORK ID NAME DRIVER SCOPE# abc123 bridge bridge local ← 默认网络# def456 host host local# ghi789 none null local
# ── 创建自定义网络 ────────────────────────────────────────────docker network create my-app-network
# 自定义网络中的容器可以通过容器名互相访问docker run -d --name db --network my-app-network postgresdocker run -d --name api --network my-app-network my-api# api 容器中可以用 "db" 作为主机名访问数据库:# postgresql://db:5432/mydb| 网络模式 | 特点 | 适用场景 |
|---|---|---|
bridge(默认) | 隔离网络,容器有独立 IP,通过端口映射访问宿主 | 常规单机部署 |
host | 容器直接使用宿主网络,性能最好,无需端口映射 | 对网络性能要求高的场景 |
none | 无网络,完全隔离 | 安全敏感场景 |
overlay | 跨主机网络(Docker Swarm / K8s) | 多机集群 |
| 自定义 bridge | 与默认 bridge 类似,但支持 DNS 名称解析 | 推荐用于多容器项目 |
4.2 数据持久化
# ── Volume(推荐方式)────────────────────────────────────────# 由 Docker 管理的存储卷,默认在 /var/lib/docker/volumes/docker volume create my-datadocker run -d -v my-data:/var/lib/postgresql/data postgres
# 查看 volumedocker volume lsdocker volume inspect my-data # 查看实际存储路径
# ── Bind Mount(直接挂载宿主目录)──────────────────────────────# 挂载宿主机目录到容器,开发环境常用(代码热更新)docker run -d -v /home/user/myapp:/app my-app
# ── 临时存储(tmpfs,数据不持久)──────────────────────────────docker run --tmpfs /tmp my-app # 存在内存中,容器停止即消失五、Docker Compose:多服务编排
5.1 完整的 compose.yml 模板(Web + DB + Redis + Nginx)
# compose.yml(Docker Compose v2 格式,无需 version 字段)
services:
# ── 数据库 ──────────────────────────────────────────────────── db: image: postgres:16-alpine container_name: app-db restart: unless-stopped environment: POSTGRES_DB: myapp POSTGRES_USER: appuser POSTGRES_PASSWORD: ${DB_PASSWORD} # 从 .env 文件读取(不要硬编码密码!) volumes: - db-data:/var/lib/postgresql/data # 数据持久化 - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro # 初始化 SQL networks: - backend healthcheck: test: ["CMD-SHELL", "pg_isready -U appuser -d myapp"] interval: 10s timeout: 5s retries: 5 start_period: 30s
# ── 缓存 ────────────────────────────────────────────────────── redis: image: redis:7-alpine container_name: app-redis restart: unless-stopped command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD} volumes: - redis-data:/data networks: - backend healthcheck: test: ["CMD", "redis-cli", "--no-auth-warning", "-a", "${REDIS_PASSWORD}", "ping"] interval: 10s timeout: 5s retries: 3
# ── 应用服务 ────────────────────────────────────────────────── api: build: context: . dockerfile: Dockerfile target: final # 多阶段构建:指定使用 final 阶段 container_name: app-api restart: unless-stopped environment: DATABASE_URL: postgresql://appuser:${DB_PASSWORD}@db:5432/myapp REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379/0 SECRET_KEY: ${SECRET_KEY} volumes: - ./logs:/app/logs # 日志持久化 networks: - frontend - backend depends_on: db: condition: service_healthy # 等待 db 健康检查通过再启动 redis: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 10s retries: 3
# ── 反向代理 ────────────────────────────────────────────────── nginx: image: nginx:1.27-alpine container_name: app-nginx restart: unless-stopped ports: - "80:80" - "443:443" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./nginx/conf.d:/etc/nginx/conf.d:ro - ./certbot/www:/var/www/certbot:ro # Let's Encrypt 验证文件 - ./certbot/conf:/etc/letsencrypt:ro # SSL 证书 networks: - frontend depends_on: api: condition: service_healthy
# ── 数据卷 ────────────────────────────────────────────────────volumes: db-data: redis-data:
# ── 网络 ──────────────────────────────────────────────────────networks: frontend: # nginx ↔ api 通信 driver: bridge backend: # api ↔ db, redis 通信(不对外暴露) driver: bridge internal: true # 标记为内部网络,容器无法访问外部网络5.2 环境变量管理(.env 文件)
# .env(放在 compose.yml 同级目录,不要提交到 git!)DB_PASSWORD=your-secure-db-password-hereREDIS_PASSWORD=your-secure-redis-passwordSECRET_KEY=your-app-secret-key-at-least-32-chars
# .env.example(提交到 git 的模板,不含实际值)DB_PASSWORD=change-meREDIS_PASSWORD=change-meSECRET_KEY=change-me# .gitignore 中添加.env.env.local.env.production5.3 常用 Compose 命令
# ── 启动与停止 ────────────────────────────────────────────────docker compose up -d # 后台启动所有服务docker compose up -d api # 只启动 api 服务(及其依赖)docker compose down # 停止并删除容器(保留 volumes)docker compose down -v # 停止并删除容器+volumes(⚠️ 会丢数据)docker compose restart api # 重启某个服务
# ── 构建 ──────────────────────────────────────────────────────docker compose build # 构建所有有 build 配置的服务docker compose build --no-cache api # 强制不用缓存重新构建docker compose up -d --build # 构建后启动
# ── 查看状态 ──────────────────────────────────────────────────docker compose ps # 查看服务状态docker compose logs -f api # 实时查看 api 日志docker compose logs -f --tail 200 # 所有服务最后200行日志
# ── 操作运行中的服务 ──────────────────────────────────────────docker compose exec api /bin/sh # 进入 api 容器的 shelldocker compose exec db psql -U appuser -d myapp # 进入数据库docker compose exec api python manage.py migrate # 运行 Django 迁移
# ── 扩缩容(多实例)────────────────────────────────────────────docker compose up -d --scale api=3 # 运行 3 个 api 实例5.4 Compose Watch(开发环境热更新)
Docker Compose 2.22+ 支持 watch 功能,实现代码变更自动同步到容器:
# compose.yml 中的 api 服务添加 develop.watchservices: api: build: . develop: watch: - action: sync # 同步:直接将文件复制到容器 path: ./src target: /app/src ignore: - __pycache__/ - "*.pyc" - action: rebuild # 重建:依赖文件变化时重新构建镜像 path: pyproject.toml - action: rebuild path: uv.lockdocker compose watch # 启动 watch 模式(保持前台运行)六、生产环境安全加固
6.1 以非 root 用户运行
# Dockerfile 中添加RUN useradd --uid 10001 --no-create-home --shell /bin/false appuserUSER appuser# 验证容器进程的运行用户docker exec my-app whoami # 应输出 appuser,不是 root6.2 只读文件系统
services: api: image: my-api read_only: true # 容器文件系统只读 tmpfs: - /tmp:size=50m # 需要写入的目录改用 tmpfs volumes: - ./logs:/app/logs # 需要持久化的日志单独挂载6.3 限制资源
services: api: image: my-api deploy: resources: limits: cpus: '1.0' # 最多使用 1 个 CPU 核心 memory: 512M # 最多使用 512MB 内存 reservations: memory: 256M # 保证 256MB 内存6.4 Secrets 管理(Docker Swarm 方式或文件挂载)
# 使用 Docker Secrets(Swarm 模式)services: db: environment: POSTGRES_PASSWORD_FILE: /run/secrets/db_password # 从文件读取密码 secrets: - db_password
secrets: db_password: file: ./secrets/db_password.txt # 本地文件(比 .env 更安全)七、健康检查与自动重启
7.1 健康检查配置详解
# Dockerfile 中的健康检查HEALTHCHECK --interval=30s \ # 检查间隔 --timeout=10s \ # 单次检查超时 --start-period=30s \# 容器启动后多少秒才开始检查 --retries=3 \ # 连续失败几次才标记为 unhealthy CMD curl -f http://localhost:8000/health || exit 1# 查看健康检查状态docker inspect my-app | grep -A10 '"Health"'7.2 重启策略选择
| 策略 | 说明 | 适用场景 |
|---|---|---|
no | 不自动重启(默认) | 开发测试 |
always | 总是重启,包括 Docker 守护进程重启后 | 核心业务服务 |
unless-stopped | 自动重启,但手动停止后不再重启 | 推荐大多数场景 |
on-failure[:N] | 只在退出码非 0 时重启,最多 N 次 | 批处理任务 |
八、实用技巧与命令
# ── 查看容器占用的实际磁盘空间 ────────────────────────────────docker system dfdocker system df -v # 详细信息(各 volume 大小)
# ── 复制文件到/从容器 ─────────────────────────────────────────docker cp my-app:/app/logs/error.log ./local-error.log # 从容器复制docker cp ./config.json my-app:/app/config.json # 复制到容器
# ── 查看容器内进程 ────────────────────────────────────────────docker top my-app
# ── 监控资源使用(实时)───────────────────────────────────────docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
# ── 事件监控 ──────────────────────────────────────────────────docker events --filter container=my-app # 实时查看容器事件(启动/停止/健康检查等)
# ── 一次性运行容器后自动删除 ──────────────────────────────────docker run --rm -it python:3.12-alpine python # 退出后容器自动删除相关文章:
- 飞牛NAS(fnOS)全平台远程访问:Tailscale + DDNS + frp 三方案
- 飞牛OS 通过 Docker 安装 OneDrive 备份文件
- mihomo(Clash Meta)完全配置指南:Docker 旁路由部署
- Cloudflare Workers 实战教程
- Python 项目工程化实战(一):pyproject.toml + uv + Ruff
本文基于 Docker Engine 26.x 和 Docker Compose v2.x 编写,旧版(docker-compose 独立命令)语法略有差异。请以
docker compose version确认版本。
Docker 完全指南 2026:镜像 / 容器 / 网络 / Compose / 生产部署最佳实践
https://971918.xyz/posts/docs/docker-complete-guide-2026/