1. 概述
Docker 的出现推动了容器化技术的普及,使得构建、交付和运行高度分布式的应用变得更加简单。我们通常使用 docker container
命令来管理独立的 Docker 容器。
Docker 最初主要面向开发者和开发周期。但随着平台的发展,它也通过一个简单而强大的编排器提供了编排服务。
在本文中,我们将先讨论容器化与编排的基本概念,然后深入分析 Docker 容器与编排服务之间的区别及其适用场景,帮助你在不同环境下做出更合适的选择。
2. 容器化与编排简介
将应用程序容器化,是软件开发周期中的关键一步。但部署和管理这些容器却可能迅速变得复杂。当我们只处理少量容器时,使用 Docker 手动管理仍可行。一旦出现故障,我们也能手动重启或更新。
但在现代架构中,一个应用通常被拆分成多个组件,每个组件都运行在各自的容器中。面对数十甚至上百个需要共存或跨多台服务器部署的容器时,手动管理很快变得不可持续。
这时就需要容器编排引擎(Container Orchestration Engine)来帮忙了。
容器编排工具可以自动化容器管理,尤其确保:
✅ 高效利用资源
✅ 高可用性
✅ 容错能力
✅ 透明的容器应用扩展
在这些工具中,Kubernetes 无疑是目前最广泛、最全面的选择。
Docker 自身也提供了集成的编排器:Docker Swarm 模式。它通过“服务”这一概念来编排容器,我们将在后续章节中详细介绍。
3. Docker 独立容器(Standalone Container)
在独立模式下运行容器,意味着直接在本地主机上启动容器,不依赖任何编排器。每个容器都是独立的,通过 Docker CLI 或 API 手动管理。
3.1. 部署
假设我们要部署一个名为 bael-api 的小型 REST 接口服务,用于展示最新的课程或文章。我们还有一个用于存储课程和文章元数据的数据库:
$ docker network create bael-network
$ docker volume create bael-db-data
$ docker container run -d --name db -v bael-db-data:/var/lib/mysql --network bael-network mysql
$ docker container run -d --name bael-api -p 8080:8080 --network bael-network bael-api
✅ 我们创建了一个自定义的 Docker 网络以确保容器间通信,并创建了一个持久化数据卷。接着使用 docker container run
启动两个容器:db
容器为内部服务,bael-api
容器则通过主机 8080 端口对外暴露。
3.2. 手动扩缩容
假设我们的 REST 接口访问量激增,单个容器已无法承受负载。我们可以手动复制多个 bael-api
容器进行横向扩展:
$ docker container run -d --name bael-api_1 -p 8081:8080 --network bael-network bael-api
$ docker container run -d --name bael-api_2 -p 8082:8080 --network bael-network bael-api
⚠️ 虽然现在有三个 API 实例在运行,但问题也随之而来:没有内置机制来实现多个容器之间的智能负载均衡。
❌ 此时必须手动配置外部负载均衡器,如 Traefik 或 HAProxy,才能实现请求的合理分发。
3.3. 手动更新
当需要更新 API 镜像时,流程也相当繁琐:
$ docker stop bael-api
$ docker rm bael-api
$ docker container run -d --name bael-api -p 8080:8080 --network bael-network bael-api:latest
✅ Docker 容器简单易用,但在面对高可用、自动扩缩容和滚动更新等需求时,很快就显得力不从心。
为了解决这些问题,Docker 引入了更高层次的抽象:Swarm 模式与服务(Service)。
4. Docker 服务与 Swarm 编排
为了在生产环境中更高效地管理分布式应用,Docker 提供了一个高级特性:Docker Swarm 模式。
Swarm 模式基于原生的 Docker SwarmKit 编排器,该编排器直接集成在 Docker 引擎中。它允许我们管理一个由多个 Docker 守护进程组成的集群,称为“Swarm 集群”。
我们可以通过初始化一个 Docker Swarm 集群来启用该模式,然后使用 docker service
命令进行管理。
4.1. 服务(Service)
从独立容器转向 Swarm 模式,意味着管理方式也发生了变化。
Service 是 Docker Swarm 的核心抽象。它定义了一个容器的期望状态。与容器不同,服务本身不会创建容器,而是描述一个需要长期维持的状态:
$ docker network create --driver overlay bael-network
$ docker service create --name bael-api --replicas 3 --update-delay 10s --update-parallelism 1 --publish 80:8080 --network bael-network bael-api:latest
✅ 我们创建了一个 overlay 网络以支持跨节点通信,并要求 Swarm 维持三个 bael-api
副本,通过主机 80 端口对外暴露。我们还设置了滚动更新策略:每次更新一个副本,间隔 10 秒。
Swarm 会自动完成以下操作:
✅ 将副本分配到可用节点
✅ 提供内置负载均衡
✅ 监控容器状态并在故障时重启
✅ 在不中断服务的情况下执行扩缩容或更新操作
每个副本由一个“任务”表示。Docker Swarm 中的服务实际上是一组由 Docker 自动编排的任务。
你可以使用以下命令查看服务状态和任务:
$ docker service ls
$ docker service ps bael-api
4.2. 多服务栈(Multi-Service Stack)
我们可以使用 Docker Compose 的 YAML 文件来定义服务,并通过 stack
命令部署整个应用栈。Stack 是一组服务的集合,用于在 Swarm 模式下运行多容器应用。
以下是一个名为 bael-stack.yml
的 Compose 文件示例:
version: "3.7"
services:
db:
image: mysql
networks:
- bael-network
volumes:
- bael-db-data:/var/lib/mysql
bael-api:
image: bael-api
networks:
- bael-network
ports:
- "80:8080"
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
volumes:
bael-db-data:
networks:
bael-network:
driver: overlay
✅ 使用该文件,我们可以通过以下命令部署整个应用栈:
$ docker stack deploy --compose-file bael-stack.yml bael-stack
我们部署了一个名为 bael-stack
的栈,包含两个服务:db
和 bael-api
。
5. 核心区别总结
特性 | Docker 容器(Standalone) | Docker 服务(Swarm) |
---|---|---|
作用范围 | 单一 Docker 主机 | 多节点集群(多主机) |
部署方式 | 命令式(Imperative) | 声明式(Declarative) |
高可用性 | 不支持 | 自动管理 |
扩缩容 | 手动 | 原生支持 |
滚动更新 | 手动 | 自动支持 |
负载均衡 | 不支持 | 内置路由网格(Routing Mesh) |
典型场景 | 本地开发、测试、简单负载 | 生产环境、高可用、跨主机部署 |
✅ 如果你的场景只涉及单台主机且不需要高级编排功能,使用 Docker Compose 配合容器就足够了。
✅ 但对于需要跨多主机部署、具备高可用性和自动扩缩容能力的生产环境,建议使用 Docker Swarm 模式。
6. 总结
本文我们比较了 Docker 独立容器与 Swarm 模式下的服务之间的核心差异。通过了解这些区别,你可以更清晰地判断在不同场景下该使用哪种方式部署应用。
✅ Docker 容器适合本地开发和简单部署场景;
✅ 而 Docker 服务结合 Swarm 模式,则更适合生产环境,具备自动扩缩容、滚动更新、内置负载均衡等能力。
理解这些概念,有助于你更好地组织部署架构、优化资源使用并提升应用的稳定性。