一套微服务系统不只有业务服务,还包括数据库、缓存、注册中心、对象存储、消息队列和监控组件。手工逐个启动容易遗漏配置,也很难保证其他环境按照同样方式复现。
在 HAOVP 的开发和单机部署中,我使用 Docker Compose 描述服务、网络、数据卷、环境变量和启动依赖。Compose 的价值是让一组容器可以统一启动和管理,但单机编排本身不等于高可用集群。
Compose 文件描述什么
一个 Compose 文件通常包含:
services
networks
volumes
configs 或 secrets(按实际环境)services 定义容器;networks 定义容器间通信;volumes 保存持久化数据;配置和秘密则需要通过受控方式提供。
一个简化示例:
services:
gateway:
image: example/gateway:latest
env_file:
- .env
networks:
- app-network
depends_on:
registry:
condition: service_healthy
networks:
app-network:
driver: bridge镜像名、文件名和服务名均为通用示例,不对应真实部署配置。
先区分基础设施和业务服务
我会把服务按职责整理:
- 数据库和缓存;
- 注册中心与配置中心;
- 对象存储和消息队列;
- 网关;
- 认证、用户、内容、评论、推荐和管理服务;
- 用户端与管理端;
- 监控和日志组件。
分组不一定要拆成多个文件,但需要看清依赖关系。基础设施没有就绪时,业务服务即使进程启动,也可能立即连接失败。
depends_on 不保证业务可用
Compose 的 depends_on 可以控制启动顺序,配合健康检查等待依赖达到健康状态。
healthcheck:
test: ["CMD", "sh", "-c", "check-command"]
interval: 10s
timeout: 5s
retries: 10这是结构示例。健康检查命令应针对实际组件设计,不公开真实账号和地址。
容器状态为 running 不等于服务可用;健康检查通过也不等于完整业务链路可用。业务服务仍需要重试、超时和明确的启动失败日志。
容器间通过服务名通信
同一 Compose 网络中的服务可以使用服务名访问彼此,不需要写死容器 IP。
业务服务 -> mysql-service
业务服务 -> redis-service
Gateway -> registry-service容器 IP 可能随重建变化,服务名更稳定。对外暴露端口与容器内部端口也要区分:容器间通信通常使用内部端口,只有真正需要从宿主机访问的服务才映射端口。
公开文档不应包含真实宿主机地址、内部域名和生产端口表。
环境变量和秘密分开处理
Compose 文件可以引用环境变量,但不能把密码和密钥直接提交到仓库。
environment:
DB_HOST: ${DB_HOST}
DB_NAME: ${DB_NAME}
DB_PASSWORD: ${DB_PASSWORD}变量名称可以进入文档,真实值不能进入公开文件、镜像层和启动日志。
我会检查:
.env是否被版本控制忽略;- 示例文件是否只包含占位值;
- 容器日志是否打印完整环境;
- 默认密码是否已替换;
- 不同环境是否使用独立配置;
- Secret 更新后如何重启和验证。
数据卷决定数据是否保留
数据库、Redis 持久化、Nacos 数据和 MinIO 对象不能只依赖容器可写层。容器删除后,可写层也会消失。
volumes:
mysql-data:
object-data:数据卷还需要考虑:
- 备份与恢复;
- 权限;
- 磁盘容量;
- 升级兼容性;
- 错误挂载;
- 删除 Compose 项目时是否保留。
docker compose down -v 会删除声明的数据卷,不能在不确认数据范围时执行。
镜像要可追踪
长期使用 latest 会让同一 Compose 文件在不同时间拉到不同镜像,不利于复现。
更稳妥的方式是使用明确版本或镜像摘要,并记录:
- 源代码版本;
- 构建时间;
- 镜像标签;
- 配置版本;
- 数据库迁移版本。
业务服务升级时,先确认数据库和接口兼容,再决定启动顺序和回滚方式。
服务启动顺序
一套简化顺序可以是:
网络与数据卷
-> 数据库、缓存、对象存储、消息队列
-> 注册与配置中心
-> 业务服务
-> 网关
-> 前端与监控实际启动可以并行,但依赖必须具备重试和健康检查。某个服务首次连接失败后直接退出,会让整个启动过程变得脆弱。
日志和可观测性
Compose 可以统一查看日志:
docker compose logs -f --tail=200 gateway命令中的服务名是示例。
我会关注:
- 日志是否带服务名和请求标识;
- 是否限制日志大小和保留时间;
- 错误日志能否定位依赖;
- 是否泄露 Token、密码和连接信息;
- 健康检查和应用指标是否可观察;
- 宿主机磁盘是否会被日志占满。
只看到所有容器为绿色,不足以证明系统链路正常。
启动后的验证顺序
容器是否运行
-> 健康检查是否通过
-> 注册中心是否看到服务
-> 网关路由是否可达
-> 认证接口是否正常
-> 核心业务链路是否能走通
-> 异常与重启场景是否可恢复我会使用脱敏测试账号和数据验证,不把真实凭据写进脚本或文档。
重启和故障场景
Compose 允许设置重启策略,但自动重启不等于问题已经解决。
需要测试:
- 数据库晚于业务服务启动;
- 单个服务重启;
- 注册中心短暂不可用;
- 对象存储或消息队列异常;
- 宿主机重启;
- 配置变更后重新创建容器;
- 数据卷是否正确恢复。
重启策略如果配置不当,还可能让持续失败的容器进入快速重启循环,掩盖真正错误。
为什么单机 Compose 不是高可用集群
即使每个服务都在独立容器中,它们仍然运行在同一台宿主机上。宿主机、磁盘或网络出现问题时,所有容器可能同时不可用。
单机 Compose 能提供:
- 环境一致性;
- 服务隔离;
- 统一启停;
- 依赖编排;
- 本地与演示部署便利性。
它不能自动提供:
- 跨主机容灾;
- 调度与自动迁移;
- 真正的多副本负载均衡;
- 存储高可用;
- 自动故障切换。
要验证高可用,还需要多节点部署、外部负载入口、数据复制、监控和故障演练。
Docker Compose 编排微服务系统的核心,是把服务、网络、配置、数据卷和健康检查变成可复现的声明。它非常适合开发、联调和单机部署,但边界必须说清楚:容器化解决环境与编排问题,高可用仍然需要跨节点和数据层面的实际验证。