忘机山人
> 一直想写一本容器小书,真好懒猫基本都做了容器化,所以把这部分分享出来。不同的是,懒猫微服中使用pg-docker来替代docker命令,使用dockge来执行docker-compose。以下讲解以标准docker为主,这样子既学会了docker知识,也能够在懒猫微服上启动Docker服务。
# 《多容器交响曲:Docker Compose 上场》讲的是使用 Docker Compose 统一编排多容器服务,理解 YAML 配置结构、服务依赖、网络、挂载、构建策略、变量管理、Compose vs K8s 初探等
------
### 🎼 开篇:服务之间的管弦乐团
随着项目日益复杂,小李的服务已经不再是一个容器就能承载的了。
前端、后端、数据库、缓存、日志系统……像一个交响乐团,需要统一调度、和谐配合。
老周递给他一个新的工具:“**Docker Compose**——它是你的指挥棒。”
------
## 🎻 第一节:什么是 Docker Compose?
老周解释:
> “Docker Compose 是 Docker 的多容器编排工具,用一份 `docker-compose.yml` 文件,就能同时启动、停止、构建多个服务。”
Compose 帮你解决:
- 多个服务启动顺序
- 多容器共享网络
- 统一管理环境变量
- 配置简洁、开发者友好
- 跨平台部署一致
------
## 📄 第二节:写出你的第一个 `docker-compose.yml`
小李的项目结构如下:
```
myapp/
├── backend/ # Flask 应用
│ ├── app.py
│ └── Dockerfile
├── frontend/ # 静态页面
│ ├── index.html
│ └── Dockerfile
└── docker-compose.yml
```
### `docker-compose.yml` 示例:
```yaml
version: '3.9'
services:
backend:
build: ./backend
ports:
- "5000:5000"
volumes:
- ./backend:/app
environment:
- DB_HOST=db
depends_on:
- db
frontend:
build: ./frontend
ports:
- "3000:80"
db:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=123456
- MYSQL_DATABASE=mydb
volumes:
- dbdata:/var/lib/mysql
volumes:
dbdata:
```
> 🔧 每个 `service` 就是一个容器定义,Compose 会为它们创建默认网络,自动 DNS 互通。
------
## 🧪 第三节:Compose 命令实战速查
小李在项目目录下运行:
```bash
docker-compose up -d
```
后台启动所有服务!
其他常用命令:
| 操作 | 命令 |
| ------------------- | --------------------------------- |
| 构建镜像 | `docker-compose build` |
| 后台启动 | `docker-compose up -d` |
| 前台启动 + 日志输出 | `docker-compose up` |
| 停止服务 | `docker-compose down` |
| 查看容器日志 | `docker-compose logs [服务名]` |
| 重启某个服务 | `docker-compose restart 服务名` |
| 进入某个容器 | `docker-compose exec 服务名 bash` |
------
## 📦 第四节:Compose 的网络与数据共享机制
老周介绍:
> “Compose 默认创建一个网络,**所有服务能通过服务名互相访问**。”
在上面的例子中:
- `backend` 容器可以用 `db:3306` 连接 MySQL
- `frontend` 可通过 `backend:5000` 访问后端 API
> 小李不再需要手动 `docker network create` 和 `--network` 参数,Compose 一切自动打通。
### Volume 的挂载:
Compose 中的 volume 显式声明(如 `dbdata:`)会自动创建、管理。
支持:
```yaml
volumes:
- ./data:/data # Bind mount
- myvolume:/data # Named volume
- /custom/path:/data:ro # 带权限控制
```
------
## 🌐 第五节:使用 `.env` 管理配置变量
Compose 支持使用 `.env` 文件集中管理变量:
`.env` 文件:
```env
DB_PASSWORD=123456
DB_NAME=mydb
```
Compose 文件中使用方式:
```yaml
environment:
- MYSQL_ROOT_PASSWORD=${DB_PASSWORD}
- MYSQL_DATABASE=${DB_NAME}
```
> 🚀 配合 CI/CD 时 `.env` 可由流水线动态生成,便于多环境切换(dev/stage/prod)。
------
## 🧬 第六节:高级配置技巧
### 1. 统一重启策略:
```yaml
restart: unless-stopped
```
确保服务宕机时能自动重启。
------
### 2. 多阶段构建支持:
```yaml
build:
context: ./backend
dockerfile: Dockerfile.prod
```
可指定构建路径、Dockerfile 文件、构建参数等。
------
### 3. Healthcheck 健康检查:
```yaml
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
interval: 30s
timeout: 10s
retries: 3
```
------
## 🆚 第七节:Docker Compose vs Kubernetes 简析
| 特性 | Compose | Kubernetes |
| ------------- | ---------------- | ----------------- |
| 启动容器 | 简单 | 标准化 |
| 配置语言 | YAML | YAML |
| 网络 | 自动共享 | 需显式配置 |
| 存储 | Volume | PVC + SC |
| 服务发现 | 服务名互通 | DNS/ClusterIP |
| 用途 | 本地开发 / CI | 集群部署 / 云原生 |
| 高可用 / 伸缩 | ❌ | ✅ 内建 |
| 社区生态 | 中小项目广泛使用 | 大型平台标准方案 |
> 小李理解了:Compose 是“轻量乐队指挥”,K8s 是“交响级 AI 指挥系统”。
------
## 🔁 第八节:Compose + CI/CD 集成发布
小李将 Compose 整合进 GitLab CI 流程:
`.gitlab-ci.yml` 示例:
```yaml
services:
- docker:dind
stages:
- build
- deploy
build:
stage: build
script:
- docker-compose build
deploy:
stage: deploy
script:
- docker-compose up -d
```
CI 构建完镜像后,直接用 Compose 部署,既省事又稳定。
------
## 🧠 小李 Compose 使用技巧总结
| 目标 | 技巧 |
| ---------- | ------------------------------------- |
| 服务隔离 | 每个项目单独一个 Compose 文件 |
| 共享网络 | 不用写 `network`,服务名即 DNS |
| 跨环境配置 | 使用 `.env` 动态切换变量 |
| 状态排查 | `docker-compose logs` / `ps` / `exec` |
| 多环境文件 | 使用 `docker-compose.override.yml` |
| CI/CD 联动 | 编排命令嵌入流水线任务中 |
------
## 🎬 尾声:指挥容器交响曲的时刻
当小李敲下 `docker-compose up` 的回车键,前端、后端、数据库同时启动,日志齐鸣,服务稳定运行。
> “这就是我梦想的微服务协奏曲啊。”
老周拍了拍他肩膀:
> “你已经能用 Compose 驾驭服务之海,下一步,是把它们部署上云、扩展弹性、自动滚动升级。”
小李点头,望向远方的集群编排系统——Kubernetes,眼中闪着新的渴望。
好!那我们就在**第五章《多容器交响曲》**中,继续深入补充这四大实战技能:
------
## 🧩 补充一:Compose 的多环境部署实践(开发、测试、生产)
小李希望同一套服务,在开发、测试、生产环境下分别使用不同的配置,比如:
- 数据库密码不同
- 是否挂载本地代码
- 是否启用调试模式
老周教他使用 Compose 的**多文件配置机制**:
------
### ✅ 方案一:使用 `docker-compose.override.yml`
Docker Compose 默认会**自动加载 `docker-compose.override.yml`** 并与主文件合并。
#### 文件结构:
```
docker-compose.yml
docker-compose.override.yml
.env.dev
.env.prod
```
#### 主配置(docker-compose.yml):
```yaml
services:
web:
build: .
ports:
- "8000:8000"
environment:
- ENV_MODE=${MODE}
```
#### 开发环境覆盖文件(docker-compose.override.yml):
```yaml
services:
web:
volumes:
- ./src:/app/src
environment:
- DEBUG=true
```
运行:
```bash
MODE=development docker-compose up
```
------
### ✅ 方案二:按环境拆分多个 Compose 文件
适合 CI/CD 或部署多个 stage。
#### 示例:
- `docker-compose.dev.yml`
- `docker-compose.prod.yml`
运行:
```bash
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d
```
多个 `-f` 会按顺序合并,后面覆盖前面。
> 📦 建议主文件写“公共配置”,子文件按环境细化。
------
## 🎯 补充二:优化服务依赖启动顺序
小李发现,即使写了 `depends_on`,后端有时候也连不上数据库。
老周摇头说:
> “`depends_on` 只是控制启动**顺序**,**不是等服务就绪**。数据库可能还没监听端口就已被标记为 'up'。”
------
### ✅ 正确姿势:服务内设置“等待就绪”
比如 Flask 等数据库:
```bash
#!/bin/bash
until nc -z db 3306; do
echo "Waiting for db..."
sleep 1
done
python app.py
```
或者使用工具包如 [`wait-for-it.sh`](https://github.com/vishnubob/wait-for-it):
```dockerfile
COPY wait-for-it.sh /wait-for-it.sh
ENTRYPOINT ["/wait-for-it.sh", "db:3306", "--", "python", "app.py"]
```
> 🩺 推荐结合容器健康检查,判断服务是否真正 ready。
------
## 🛠 补充三:Docker Compose V1 ➜ V2 迁移技巧
小李的 CI 工具用的是 Compose v1,项目准备升级。
老周提醒:
> “Docker Compose v2 使用的是 `docker compose`(空格),而非 `docker-compose`(短横线)。”
------
### ✅ 主要变化:
| 项目 | v1 (`docker-compose`) | v2 (`docker compose`) |
| -------- | --------------------- | --------------------- |
| 命令格式 | `docker-compose up` | `docker compose up` |
| 安装方式 | 独立二进制 | 集成于 Docker CLI |
| 文件格式 | `v2`, `v3` | 推荐统一 `v3.9` |
------
### ✅ 迁移建议:
- 删除旧的 `docker-compose` 二进制
- 使用 `docker compose` CLI
- 更新脚本、CI 工具调用方式
- 移除 legacy 字段(如 `links`)
- 检查 `.env` 是否兼容(v2 更严格)
------
## ☸️ 补充四:Compose 与 Helm 的映射关系对照
当小李进入 Kubernetes 世界,他问老周:
> “Compose 文件和 K8s 的 YAML 有啥对应关系?”
老周说:“很好理解,Compose 是开发者的 K8s 简化版本。”
------
### 对照表:
| Compose | Kubernetes |
| -------------------- | ------------------------------------ |
| `services:` | `Deployment + Pod` |
| `volumes:` | `PersistentVolumeClaim` |
| `ports:` | `Service`(NodePort / ClusterIP) |
| `depends_on:` | `initContainers` 或 readinessProbe |
| `.env` | ConfigMap / Secret |
| `docker-compose.yml` | Helm Chart (values.yaml + templates) |
------
### 示例:Compose 转 Helm 构思
#### Compose 配置:
```yaml
services:
web:
image: myapp:latest
ports:
- "8080:80"
environment:
- DEBUG=true
```
#### Helm `values.yaml`:
```yaml
image:
repository: myapp
tag: latest
env:
- name: DEBUG
value: "true"
service:
port: 8080
targetPort: 80
```
#### Helm `deployment.yaml`(模板):
```yaml
containers:
- name: web
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
env:
{{- range .Values.env }}
- name: {{ .name }}
value: {{ .value }}
{{- end }}
```
> ✅ 小李意识到,Helm 是“模板化 + 分层管理”的 Compose 超集,是云原生部署的标准组件管理器。
------
## 🎬 尾声:Compose 是微服务上云的跳板
小李已经用 Docker Compose 实现了:
- 开发环境热更新
- 测试环境集成数据库
- 生产环境独立配置
- CI/CD 自动部署服务
- 为 Kubernetes 迁移打下基础
他明白了:
> “Compose 就像舞台排练,Kubernetes 才是真正的大型音乐厅。但有了排练,登台才不会慌。”
评论
0暂无评论