这两者常被放在一起比较,但严格说,Compose 不是集群工具,它只是把多个容器组织在一台机器上;Swarm 才把节点组成集群来调度服务。所以这个问题不是二选一,而是先判断当前环境需要哪种协作方式。如果只是在开发机或一台服务器上跑几个容器,Compose 更直接;如果已经有多个节点,并且希望服务能在节点间调度、故障后重新拉起,才需要考虑 Swarm。
先别急着改配置,明确单机和多节点的边界
很多人拿到 Compose 文件后,想直接把它搬到 Swarm 里,这通常没问题,但前提是文件里的网络和卷声明已经做了调整。理解两者的管理模型,比死记命令更重要。Compose 是显式地创建容器,Swarm 则声明期望状态,由调度器去实现。这个差异会在后续每一次变更中体现出来。操作路径是最直观的差异。
操作差异:从 docker-compose up 到 docker stack deploy
实际部署时,建议先区分目标环境。在本地开发环境,执行 docker-compose up -d 即可启动一组容器;而在 Swarm 集群中,需要先执行 docker swarm init 或加入现有集群,再通过 docker stack deploy -c docker-compose.yml 应用配置文件。检查运行状态的方式也不同:Compose 用 docker-compose ps 查看本机容器,Swarm 用 docker service ls 列出全局服务,用 docker service ps 查看每个任务的分布和是否处于运行状态。若要更新服务配置,Compose 需要重建整个容器组,而 Swarm 的 docker stack deploy 会自动计算差异并发布更新,无需手工停止已有服务。
这里有一个容易忽略的点:Compose 的 up 是创建并启动,重复执行时如果配置没变,它不会主动重建;Swarm 的 stack deploy 则是声明式的,每次都会对比当前运行状态与期望状态,有差异才动。所以如果你习惯手动改容器再执行 docker-compose restart,到了 Swarm 里这套习惯要改掉。
把 Compose 文件搬进 Swarm,最先栽在网络上
把 Compose 文件迁移到 Swarm 时最容易踩的坑是网络和卷。Compose 默认创建 bridge 网络,服务间通过服务名解析没问题,但 Swarm 中必须显式声明 overlay 网络,否则容器可能只能运行在单一节点。另一个坑是数据卷:Compose 的 bind mount 指向本地路径,在 Swarm 中任务被调度到其他节点后,路径不存在或内容不一致。推荐使用 named volume 并接入 NFS、Ceph 等共享存储,避免因节点重启或重新调度造成数据丢失。此外,Swarm 中如果服务没有设置 endpoint_mode,默认的 VIP 模式对客户端友好,但如果你依赖固定的容器 IP,需要改用 dnsrr 模式,这一点很容易忽略。
检查方法很简单:部署后用 docker network ls 看网络 driver 是不是 overlay;再用 docker service ps 看任务是否分布在多个节点,如果所有任务都挤在同一个节点,多半是网络或卷不满足调度条件。数据卷的迁移还需要在节点上确认挂载点是否存在,不能只看启动成功。
Swarm 的自动恢复不是万能,状态化服务要提前绑节点
从编排能力上理解两者边界:Compose 没有故障自动恢复机制,容器退出后不会自动重新拉起;Swarm 自带状态收敛,如果某个节点宕机或任务异常,调度器会将其重新调度到健康节点。但这并不意味着 Swarm 适合所有状态化应用,比如运行数据库时,自动调度会导致 IP 变化、副本间数据不一致。对于依赖共享文件或需要持久化连接的服务,建议把服务固定在特定节点上,或者使用宿主机亲和性约束,否则会出现连接闪断。另外,Swarm 的 ingress 负载均衡基于四层,不做 HTTP 层的路由判断,如果应用依赖 nginx 之类的七层反向代理,需要自己部署并映射主机端口,而不是指望 swarm 路由网格直接按域名分流。
如果需要固定节点,可以给服务加约束:docker service update --constraint-add node.hostname==node01 服务名。验证时用 docker service ps 服务名 看任务被调度到的节点;想要解除约束,用 --constraint-rm 再执行一次。对于数据库这类服务,更稳妥的做法是使用 global 模式部署或外部存储,但不要依赖 Swarm 自动迁移。
选型判断:什么时候留在 Compose,什么时候上 Swarm
如果只是本地功能验证,或者 CI 里跑一组相关容器,Compose 足够。它启动快、配置简单,不需要管理节点和 worker 节点之间的关系。如果应用是多节点 Web 服务,需要滚动更新和故障恢复,Swarm 值得投入。一个可以落地的做法是:项目仓库里维护两份文件,一份 docker-compose.yml 用于本地开发,一份 stack.yml 用于集群部署。stack.yml 里显式指定 version、overlay 网络和卷的共享驱动,这样本地和集群环境不用反复改配置。
改完后看这几个信号
部署完成后,不要只看容器起来了,要观察三个信号。第一,docker stack services 的输出里,REPLICAS 列的期望值和运行值是否一致。第二,docker service ps 服务名 里任务的当前状态是否停在 Running,而不是反复出现 New 或 Updating。第三,网络和卷在集群内可见:docker network ls 能看到 overlay 网络,docker volume ls 在相关节点上能看到共享卷。如果某个服务长时间显示 Pending,先看 docker service ps 里的 ERROR 字段,再用 docker service inspect 查看约束和卷配置。