3413 字
17 分钟

Docker 完全指南 2026:镜像 / 容器 / 网络 / Compose / 生产部署最佳实践

Docker 是现代应用部署的基础设施,无论是个人项目还是企业级服务,容器化都已成为标配。本文覆盖 Docker 从入门到生产部署的全链路知识,重点关注 2026 年实际使用中遇到的问题——尤其是国内镜像加速失效、多阶段构建优化、Compose 生产配置等实战场景。


一、安装与国内镜像加速#

1.1 安装 Docker(Linux)#

Terminal window
# 一键安装(Debian/Ubuntu,官方脚本)
curl -fsSL https://get.docker.com | sh
# 安装完成后,将当前用户加入 docker 组(免 sudo)
sudo usermod -aG docker $USER
newgrp docker # 立即生效(或重新登录)
# 验证
docker --version # Docker version 26.x.x
docker compose version # Docker Compose version v2.x.x(注意:v2 是 compose 子命令,不再是独立的 docker-compose)

1.2 国内镜像加速(2026 可用方案)#

⚠️ 2024-2025 年,DaoCloud、网易云、USTC 等加速器陆续停止服务。以下是 2026 年仍可用的方案。

方案 A:通过本地代理软件(推荐,最稳定)

如果你的服务器或本机安装了代理软件(监听 7890 端口),配置 Docker 走代理:

Terminal window
# 创建 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-reload
sudo systemctl restart docker
# 验证代理生效
docker pull hello-world

方案 B:daemon.json 配置镜像源(部分可用)

/etc/docker/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"
}
}
Terminal window
sudo systemctl daemon-reload && sudo systemctl restart docker
docker info | grep -A5 "Registry Mirrors"

方案 C:使用阿里云容器镜像服务(自己搬运)

在阿里云 ACR 免费版中建立镜像同步仓库,将 DockerHub 镜像同步到阿里云,再从 registry.cn-hangzhou.aliyuncs.com 拉取。


二、Docker 基础命令速查#

2.1 镜像操作#

Terminal window
# ── 搜索与拉取 ────────────────────────────────────────────────
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 容器操作#

Terminal window
# ── 运行容器 ──────────────────────────────────────────────────
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 8000
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]

Go 项目示例:从 ~1GB 到 ~10MB

# 阶段1:编译
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# 静态链接,无需任何运行时库
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 /server
EXPOSE 8080
ENTRYPOINT ["/server"]

3.3 .dockerignore 文件(必须配置)#

.dockerignore
.git
.gitignore
**/.DS_Store
**/__pycache__
**/*.pyc
**/.pytest_cache
**/.mypy_cache
**/.ruff_cache
node_modules
dist
build
*.log
.env
.env.*
docker-compose*.yml
Dockerfile*
README.md
docs/

3.4 构建最佳实践总结#

✅ 使用特定版本 tag,不用 latest
✅ 多阶段构建分离构建环境和运行环境
✅ 先复制 package.json/requirements.txt,再安装依赖(利用层缓存)
✅ 合并相关 RUN 命令,减少层数
✅ 配置 .dockerignore 排除不必要文件
✅ 使用非 root 用户运行应用
✅ 只安装运行时需要的依赖(--no-dev / --only=production)
✅ 使用 alpine 或 slim 基础镜像

四、Docker 网络与数据持久化#

4.1 网络模式#

Terminal window
# ── 查看网络 ──────────────────────────────────────────────────
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 postgres
docker 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 数据持久化#

Terminal window
# ── Volume(推荐方式)────────────────────────────────────────
# 由 Docker 管理的存储卷,默认在 /var/lib/docker/volumes/
docker volume create my-data
docker run -d -v my-data:/var/lib/postgresql/data postgres
# 查看 volume
docker volume ls
docker 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 文件)#

Terminal window
# .env(放在 compose.yml 同级目录,不要提交到 git!)
DB_PASSWORD=your-secure-db-password-here
REDIS_PASSWORD=your-secure-redis-password
SECRET_KEY=your-app-secret-key-at-least-32-chars
# .env.example(提交到 git 的模板,不含实际值)
DB_PASSWORD=change-me
REDIS_PASSWORD=change-me
SECRET_KEY=change-me
Terminal window
# .gitignore 中添加
.env
.env.local
.env.production

5.3 常用 Compose 命令#

Terminal window
# ── 启动与停止 ────────────────────────────────────────────────
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 容器的 shell
docker 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.watch
services:
api:
build: .
develop:
watch:
- action: sync # 同步:直接将文件复制到容器
path: ./src
target: /app/src
ignore:
- __pycache__/
- "*.pyc"
- action: rebuild # 重建:依赖文件变化时重新构建镜像
path: pyproject.toml
- action: rebuild
path: uv.lock
Terminal window
docker compose watch # 启动 watch 模式(保持前台运行)

六、生产环境安全加固#

6.1 以非 root 用户运行#

# Dockerfile 中添加
RUN useradd --uid 10001 --no-create-home --shell /bin/false appuser
USER appuser
Terminal window
# 验证容器进程的运行用户
docker exec my-app whoami # 应输出 appuser,不是 root

6.2 只读文件系统#

compose.yml
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
Terminal window
# 查看健康检查状态
docker inspect my-app | grep -A10 '"Health"'

7.2 重启策略选择#

策略说明适用场景
no不自动重启(默认)开发测试
always总是重启,包括 Docker 守护进程重启后核心业务服务
unless-stopped自动重启,但手动停止后不再重启推荐大多数场景
on-failure[:N]只在退出码非 0 时重启,最多 N 次批处理任务

八、实用技巧与命令#

Terminal window
# ── 查看容器占用的实际磁盘空间 ────────────────────────────────
docker system df
docker 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 # 退出后容器自动删除

相关文章

本文基于 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/
作者
九所长
发布于
2026-07-16
许可协议
CC BY-NC-SA 4.0