正式开始接触项目开发的第一天就是把项目从公司内网的机器上迁移到阿里云的公网机器上,组长让我写 Dockerfile 和 Docker Compose 开始折腾 CI/CD Pipeline 了。
Dockerfile好写,毕竟上学的时候写过,但是我用 Docker 一般也是以调试为主,很少有需要编排的需求,也就没写过 Docker Compose,所以我就要开始折腾 Docker Compose 相关的内容了。
1. 为什么我们需要 Docker Compose?
在没有 Compose 之前,如果你想运行一个包含 Web 服务(如 Python Flask)和数据库(如 Redis)的应用,你需要手动执行以下操作:
- 创建一个 Docker 网络(以便容器通信)。
- 输入很长的命令启动 Redis 容器。
- 输入很长的命令启动 Web 容器,并手动指定环境变量、端口映射、挂载卷,还要链接到刚才的网络。
痛点:
- 命令太长,容易记错。
- 难以在团队间共享配置(“在我的机器上能跑”的问题)。
- 容器间的启动顺序和依赖关系难以管理。
Compose 的解决方案: 使用一个 YAML 文件(docker-compose.yml)把所有的配置写下来,然后通过一条命令 docker compose up 启动所有服务。
2. 核心概念
Docker Compose 有三个层级的概念:
- Project (项目): 默认情况下,存放
docker-compose.yml文件的目录名就是项目名。一个项目包含多个服务。 - Service (服务): 对应一个容器配置(例如:
web服务,db服务)。 - Container (容器): 服务启动后的具体实例。
3. docker-compose.yml 文件详解
这是 Compose 的核心。它使用 YAML 语法。以下是一个典型的结构解析:
version: "3.8" # (可选) 指定 Compose 文件版本,新版 Docker 可省略
services: # 定义服务列表
# --- 服务 1: Web 应用 ---
webapp:
build: . # 从当前目录的 Dockerfile 构建镜像
# image: nginx:latest # 或者直接使用现成的镜像,二选一
ports:
- "8080:80" # 端口映射: 宿主机端口:容器端口
volumes:
- ./code:/code # 数据卷挂载: 宿主机路径:容器路径
environment: # 环境变量
- DEBUG=True
- DB_HOST=database # 注意:这里直接用服务名作为域名
depends_on: # 依赖关系
- database # 确保 database 先启动
networks:
- my-net # 加入指定网络
# --- 服务 2: 数据库 ---
database:
image: postgres:13
environment:
POSTGRES_PASSWORD: secret
volumes:
- db-data:/var/lib/postgresql/data # 使用具名卷持久化数据
networks:
- my-net
# 定义网络 (可选,默认会自动创建一个)
networks:
my-net:
# 定义具名卷 (用于数据持久化)
volumes:
db-data:关键指令解析:
imagevsbuild:image直接拉取远程镜像;build则根据 Dockerfile 现场构建。ports: 暴露端口。格式为"宿主机:容器"。volumes:- 绑定挂载 (Bind Mount):
./host/path:/container/path,常用于开发环境,代码实时同步。 - 具名卷 (Named Volume):
vol_name:/data,常用于数据库数据持久化,由 Docker 管理存储位置。
- 绑定挂载 (Bind Mount):
environment: 设置容器内的环境变量(如数据库密码、API Key)。depends_on: 控制启动顺序。注意:它只保证启动顺序,不保证被依赖的服务已经“准备好”(例如数据库完全加载完毕)。- 服务发现 (Magic): 在同一个 Compose 网络中,服务名就是主机名 (Hostname)。比如 Web 服务想连接 Redis,代码里写
redis_host = "database"即可,Docker 会自动解析 IP。
4. 常用命令 (CLI)
命令 作用 常用参数 docker compose up启动所有服务 -d(后台运行)--build(强制重新构建镜像)docker compose down停止并删除容器、网络 -v(同时删除数据卷,慎用!)docker compose ps查看当前项目运行的容器 -a(查看所有)docker compose logs查看服务日志 -f(实时跟踪)web(只看 web 服务的日志)docker compose stop仅停止容器(不删除) docker compose start启动已停止的容器 docker compose restart重启服务 docker compose exec进入容器执行命令 docker compose exec web bashdocker compose config检查 YAML 文件语法
5. 进阶技巧
A. 使用 .env 文件管理敏感信息
不要把数据库密码直接写在 docker-compose.yml 里。 创建一个 .env 文件:
DB_PASSWORD=mysecretpassword123
DB_USER=admin在 docker-compose.yml 中引用:
services:
db:
image: postgres
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}Docker Compose 会自动读取同目录下的 .env 文件。
B. 重启策略 (Restart Policy)
在生产环境中,如果程序崩溃或服务器重启,你希望容器自动恢复。
services:
web:
# no: 默认值,不重启
# always: 总是重启
# on-failure: 只有非正常退出(错误码非0)才重启
# unless-stopped: 除非手动 stop,否则一直尝试重启 (推荐)
restart: unless-stoppedC. 扩展服务 (Scaling)
如果你想测试负载均衡,可以瞬间启动 5 个 web 容器(前提是代码里没写死端口绑定):
docker compose up -d --scale web=5(注意:如果使用了 host port 映射如 80:80,扩展会报错端口冲突,通常配合负载均衡器如 Nginx 使用)
D. 多文件覆盖 (Override)
你可以有 docker-compose.yml (基础配置) 和 docker-compose.prod.yml (生产环境配置)。 运行命令时:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d后者会覆盖前者的配置(例如修改端口、环境变量)。
6. 总结
Docker Compose 是单机容器编排的神器。
- 对于开发:它能让你一键拉起包含数据库、缓存、消息队列的完整开发环境。
- 对于测试:CI/CD 流水线中常用它来运行集成测试。
- 对于小型生产环境:配合
restart: always和挂载卷,足以支撑许多中小型应用。
文章评论