即使有了Docker Compose,项目的部署仍然存在问题,因为Docker Compose只能把项目所有的容器部署在同一台机器上,这在生产环境下是不现实的。
Docker Compose一般只适用于开发环境,而对于生产环境下的项目部署,我们需要用到Docker Swarm。
Docker Swarm介绍
Docker Swarm是Docker官方提供的一套容器编排系统,它将一组Docker主机虚拟成一个单独的虚拟Docker主机。
架构如下:
- swarm节点:
swarm是一系列节点的集合,而节点可以是一台裸机或者一台虚拟机。一个节点能扮演一个或者两个角色,manager或者worker。
manager
Docker Swarm集群需要至少一个manager节点,节点之间使用Raft consensus protocol进行协同工作。
通常,第一个启用docker swarm的节点将成为leader,后来加入的都是follower。当前的leader如果挂掉,
剩余的节点将重新选举出一个新的leader。每一个manager都有一个完整的当前集群状态的副本,可以保证manager的高可用。
worker
worker节点是运行实际应用服务的容器所在的地方。理论上,一个manager节点也能同时成为worker节点,但在生产环境中,
我们不建议这样做。worker节点之间,通过control plane进行通信,这种通信使用gossip协议,并且是异步的。
- task、service、stack:
多个tasks组成一个service,多个services组成一个stack。
task
在Docker Swarm中,task是一个部署的最小单元,task与容器是一对一的关系。
service
swarm service是一个抽象的概念,它只是一个对运行在swarm集群上的应用服务,所期望状态的描述。
它就像一个描述了下面物品的清单列表一样:
服务名称
使用哪个镜像来创建容器
要运行多少个副本
服务的容器要连接到哪个网络上
需要映射哪些端口
stack
stack是描述一系列相关services的集合,可以通过在一个YAML文件中来定义一个stack,类似于docker-compose。
- 多主机网络:
对于单主机网络,所有的容器都运行在一个docker主机上,他们之间的通信一般使用本地的bridge network即可。
而对于swarm集群,针对的是一组docker主机,需要使用docker的overlay network。
Docker Stack
前面有讲过,docker run
仅适用于单机启动单个容器;docker compose
仅适用于单机启动多个容器;docker service
仅适用于集群启动单个service的容器。
即使在生产环境下使用docker service
来部署项目,也是无法接受的。当项目足够复杂时,会有更多关联的service需要创建,通过docker service
手动创建多个service,效率也是十分低下的。
因此,Docker Stack应运而生,Docker Stack适用于集群启动多个service的容器,在集群中可以类似Docker Compose那样通过YAML文件直接部署项目。
只不过Docker Stack忽略了build
指令,不能像Docker Compose那样在docker-compose.yml
中引用Dockerfile构建新镜像,它需要镜像是预先已经构建好的。所以Docker Compose更适合于开发场景,而Docker Stack更适用于生产环境。
- 对应关系:
单机 | 集群 |
---|---|
docker run | docker service create |
docker-compose up | docker stack deploy |
- 使用
docker stack
命令:
使用docker stack不再需要安装docker-compose,直接使用docker stack deploy
命令。
docker stack deploy project_name --compose-file docker-compose.yml
当然,后面跟着的YAML文件名不一定是docker-compose.yml
,可以自定义。
deploy
指令:
指定与service的部署和运行相关的配置。只在使用docker stack deploy
部署时生效,并且会被docker-compose up
和docker-compose run
忽略。
version: "3.7"
services:
redis:
image: redis:alpine
deploy:
replicas: 6
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
endpoint_mode
指令:
为连接到集群的外部客户端指定服务发现方法。
endpoint_mode: vip(默认配置)
为service分配一个虚拟IP(vip),作为客户端在网络上访问service的前端。
Docker在客户端和service可用的工作节点之间路由请求,而客户端不知道有
多少节点参与服务或它们的IP地址或端口。
endpoint_mode: dnsrr
DNS循环(dnsrr)服务发现不使用单个虚拟IP。Docker为服务设置DNS条目,
针对service名称的DNS查询将返回一个IP地址列表,客户端将直接连接到其中之一。
deploy:
mode: replicated
replicas: 2
endpoint_mode: dnsrr
labels
指令:
为服务指定标签。这些标签仅在service上设置,而不在service的任何容器上设置。
deploy:
labels:
com.example.description: "This label will appear on the web service"
要在容器上设置标签,请在deploy
之外使用labels
。
version: "3.7"
services:
web:
image: web
labels:
com.example.description: "This label will appear on all containers for the web service"
mode
指令:
mode有global
和replicated
两种,默认mode是replicated
。当为global
时,每个集群节点仅允许有一个service的容器,不允许有副本;当为replicated
时,每个集群节点可以有指定数量的service的容器。
version: "3.7"
services:
worker:
image: dockersamples/examplevotingapp_worker
deploy:
mode: global
deploy:
mode: replicated
replicas: 5
placement
指令:
指定约束和偏好的设置。node.role == manager
表示只在manager节点创建service的容器。
deploy:
placement