Docker 容器化实战:从 Dockerfile 到 Compose 编排的完整指南

小小卒子2026-10-20docker⏱ 5min

Docker 容器化实战:从 Dockerfile 到 Compose 编排的完整指南

Docker 已经成为现代应用交付的事实标准。从"在我机器上能跑"到"在任何机器上都能跑",容器化解决了环境一致性这一根本痛点。本文从镜像构建、容器运行到 Compose 编排,给出生产可用的实战方法。

一、理解镜像与容器的关系

镜像(Image) 是只读的模板,包含应用代码、运行时、依赖和配置;容器(Container) 是镜像的运行实例,可启动、停止、删除。二者关系类似"类"与"对象"。

镜像采用分层存储:每一层只记录与上一层的差异。分层带来的两个直接结论:

  1. 镜像复用层时只需拉取差异,传输速度快;
  2. 每一条 RUN 指令都会产生新层,指令越多镜像越大——这就是合并指令、使用多阶段构建的原因。

二、写出规范的 Dockerfile

2.1 多阶段构建:把"构建环境"和"运行环境"分离

以 Go 应用为例,构建阶段需要编译器,运行阶段只需要可执行文件:

# 阶段一:构建
FROM golang:1.24-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o server ./cmd/server

# 阶段二:运行(更小的最终镜像)
FROM alpine:3.20
RUN adduser -D appuser
COPY --from=builder /app/server /usr/local/bin/server
USER appuser
EXPOSE 8080
ENTRYPOINT ["server"]

收益:最终镜像从几百 MB 瘦身到几十 MB,同时不携带源码和构建工具,攻击面更小。

2.2 指令顺序的艺术

Docker 构建会缓存每一层,把不易变化的指令放前面,易变化的放后面:

# 先拷贝依赖清单(变化频率低)→ 命中缓存
COPY go.mod go.sum ./
RUN go mod download
# 最后拷贝源码(每次构建都变化)
COPY . .

2.3 安全基线

  • 使用官方镜像并锁定版本标签(alpine:3.20 而非 alpine:latest);
  • 尽量以非 root 用户运行(USER appuser);
  • 不把密钥写进镜像:用 --secret 或运行时环境变量注入;
  • 定期扫描镜像漏洞(docker scout / Trivy)。

三、容器网络与数据持久化

3.1 三种网络模式

| 模式 | 特点 | 适用场景 | |------|------|----------| | bridge(默认) | 容器间通过自定义网桥互相访问 | 单机多容器互联 | | host | 直接使用宿主机网络 | 性能敏感、端口映射复杂时 | | none | 无网络 | 离线计算任务 |

自定义 bridge 网络让容器可用服务名互相访问,这是 Compose 服务发现的基石:

docker network create app-net
docker run --network app-net --name api myapp
docker run --network app-net --name nginx nginx   # nginx 里可以直接 ping api

3.2 数据持久化的三种方式

  1. Volume(推荐):docker volume create data,由 Docker 管理,跨容器共享,备份方便;
  2. Bind Mount:-v /host/path:/container/path,直接映射宿主机目录,适合开发热更新;
  3. tmpfs:内存文件系统,适合存放敏感临时数据。
# 数据库容器使用 volume 持久化
docker run -d --name mysql8 \
  -v mysql-data:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=secret \
  mysql:8.0

四、Compose 编排:一套命令拉起整个栈

docker-compose.yml 用声明式配置描述多容器应用。一个典型的后端栈:

version: "3.8"

services:
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: "${DB_ROOT_PASSWORD}"
      MYSQL_DATABASE: app
    volumes:
      - mysql-data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 5s
      retries: 10

  redis:
    image: redis:7-alpine
    volumes:
      - redis-data:/data

  api:
    build: .
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_started
    environment:
      DB_DSN: "root:${DB_ROOT_PASSWORD}@tcp(mysql:3306)/app"
      REDIS_ADDR: "redis:6379"
    ports:
      - "8080:8080"

  nginx:
    image: nginx:1.26-alpine
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    ports:
      - "80:80"
    depends_on:
      - api

volumes:
  mysql-data:
  redis-data:

几个值得注意的点:

  • depends_on 配合 healthcheck:condition: service_healthy 确保数据库就绪后再启动 API;
  • 环境变量用 ${VAR} 引用 .env 文件:敏感配置不写死在 yaml 里;
  • 服务名即 DNS 名:API 容器内直接连 mysql:3306。

常用命令:

docker compose up -d          # 后台启动整套栈
docker compose logs -f api    # 跟踪某个服务日志
docker compose down -v        # 停止并删除数据卷(慎用!)
docker compose exec api sh    # 进入容器调试

五、镜像仓库与 CI/CD 集成

5.1 命名与推送

docker tag myapp registry.example.com/team/myapp:v1.2.0
docker push registry.example.com/team/myapp:v1.2.0

5.2 流水线中的镜像策略

  • 不可变标签:v1.2.0、<sha> 用于生产部署,不用 latest 做生产发布;
  • 构建缓存复用:CI 中开启 BuildKit(DOCKER_BUILDKIT=1),多阶段缓存能大幅提速;
  • 制品签名:生产环境启用 Notary/cosign 校验镜像签名,防供应链攻击。

六、容器化常见坑

  1. 时区问题:基础镜像多为 UTC,ENV TZ=Asia/Shanghai 并在需要时安装 tzdata;
  2. PID 1 与僵尸进程:容器内 PID 1 需要处理信号与回收子进程,Go 应用直接作 PID 1 通常没问题,脚本类应用建议用 tini;
  3. 日志不能写文件:容器日志应输出到 stdout/stderr,由 Docker 收集(docker logs、日志驱动);
  4. 健康检查缺失:没有 healthcheck 的容器无法被编排系统准确判断就绪状态;
  5. 磁盘爆满:定期清理 <none> 悬空镜像与构建缓存:docker system prune -af。

结语

Docker 的核心价值不是"跑起来",而是把交付物变成标准化的、可审计的制品。写好 Dockerfile、用好 Compose、接入可靠的镜像仓库,你的应用就获得了"一次构建,处处运行"的能力。建议从把现有服务容器化开始,逐步建立镜像规范与 CI 流水线。

读完了?给作者一点支持

本文采用 CC BY 4.0 协议转载 · © 小卒子

评论区加载中…

🔗 相关文章

常见错误及解决方案

Docker 在开发和生产环境中广泛应用,它为开发人员提供了快速构建、测试、部署和扩展应用程序的能力。然而,在使用 Docker 的过程中,可能会遇到各种各样的问题,如容器启动失败、镜像构建失败等。了解这些常见错误及其解决方案对于提高开发效率、减少故障恢复时间至关重要。 本文将列出 Docker 中常见的错误及其解决方案,并提供详细的示例和方法,帮助开发者更好地调试和解决问题。 1. 容器启动失败

12/1/2024👍 0

调试与日志分析

Docker 是一个强大的容器化平台,能够帮助开发者构建、发布和运行应用程序。然而,在实际使用过程中,容器可能会遇到一些问题,导致容器无法正常启动或运行。为了快速定位并解决问题,Docker 提供了多个调试与日志分析工具,如 docker logs、docker inspect 等命令。通过合理使用这些工具,我们能够高效地进行容器的故障排除。 本文将详细介绍 Docker 中常用的调试与日志分析工

12/1/2024👍 0

容器与虚拟机的区别

随着云计算和微服务架构的兴起,容器化技术越来越受到开发者和运维工程师的青睐。Docker是当前最流行的容器平台,它提供了一种轻量级、高效且灵活的方式来部署、运行和管理应用程序。然而,在理解Docker的优势之前,我们需要先了解容器与传统虚拟机(VM)的根本区别。本文将深入对比容器和虚拟机,帮助你了解容器如何在性能、效率、资源利用等方面展现其优势。 一、虚拟机(VM)的基本概念 虚拟机(VM)是通

11/15/2024👍 0