1. 前言
上一篇我们讲到Docker Compose可以定义和运行多容器应用程序,用一个YAML配置文件来声明式管理服务,在一台安装了Docker engine的Linux系统上可以很好的工作,但是现实中不可能只有一台Linux系统,一台Linux系统不可能有足够的资源运行所有的云原生应用系统,为了支撑整个业务平台,势必要在很多台Linux系统运行云原生应用系统,共同组成一个容器集群,Docker Compose工具并不能管理这样的容器集群,势必有新工具出现。
开源界管理容器集群的系统一般叫作容器编排系统,主要有三个系统:Docker Swarm、Mesos、Kubernetes。当然众所周知,Mesos背后的支撑公司已经出现了问题,Docker Swarm也是有气无力的状态,只有Kubernetes如日中天,成为事实上的标准。
既然Kubernetes是事实上的标准,为什么四年前我还是选择了Docker Swarm?基于简单的三个理由:
- 系统的规模:我们的最大客户线上环境只有几十台Linux服务器,100台物理机都不到,其实也不是所有机器都安装容器集群,存储系统和大数据集群也占了一少部分机器。最小的客户线上环境才10几台Linux服务器,规模就更小了。Docker Swarm足够管理这点容器集群了,一直以来运行基本没出现过问题。
- 操作的复杂度:K8s从安装到运维技术复杂性众所周知,而Docker Swarm本身就集成进Docker Engine中,操作相对来说算非常简单了,中小公司只有少量的运维人员,而且技艺也不够精,选择Docker Swarm就显得更为适合了。
- 内网的问题:大部分在互联网工作的企业,安装什么软件都非常方便,但是少部分安全行业,系统都是部署在严格控制的内网环境里,绝对不能访问外部互联网、移动互联网等,只有一条只准进不准出的FTP通道给企业发包使用。在这样的环境下,大部分Linux服务器已经存在,不可能搬出来到外网安装软件了,如果我们安装K8s难度有多大不可而知,但是我们用二进制包去安装Docker Engine,部署Docker Swarm,整个过程非常顺利。
所以我推荐选择Docker Swarm而不是K8s,如果你的真实系统环境和我差不多的话,不要给公司运维人员带来额外的技术债务。
2. Docker Swarm简介
从Docker Engine 1.12版本开始,Docker Swarm已经包含在其中了,负责容器集群管理和编排。下面列举一下Docker Swarm有哪些特性:
- 集群管理功能直接整合进Docker引擎中:不需要额外单独安装容器编排软件,操作命令直接集成进docker工具里,降低了学习曲线。
- 去中心化设计:在运行时处理任何特殊化,而不是在部署时,也就是部署时不需要管不同角色的节点问题,你能使用Docker engine提供的工具,同时部署managers和works两种类型的nodes。反正我们用docker swarm提供的命令对管理节点和工作节点进行操作即可。
- 声明式服务模式:Docker引擎使用声明性方法来定义应用程序栈中各种服务的所需状态,一般就是在编排文件docker-compose.yml里定义各种状态参数,如容器数量。
- 弹性:对每一个服务,你都可以在编排文件中定义它容器运行的数量,当你增加或减少编排文件里服务的容器数量时,swarm管理功能会自动增加和删除运行容器的数量,不需要人工干预。
- 期望状态的调节功能:管理节点一直监控着集群的运行状态,调节集群实际状态和你期望的状态之间的差异。比如你在编排文件你定义一个服务要10个容器,管理节点一直会监控并满足这个状态,中途如果有节点down掉了,它会在其它活动的节点上运行新容器以便始终满足10个容器。
- 跨多主机网络:你可以对所有服务指定一个overlay类型网络,服务之间就可以无缝通讯了。
- 服务发现功能:在集群中每一个服务都有一个唯一的DNS名,通过这个域名你访问每一个运行中的容器。
- 负载均衡功能:你可以指定服务的一个或多个端口,暴露给外部访问,Swarm会在多个节点之间处理好负载均衡问题。
- 缺省支持安全:支持CA证书,内网方案一般也可以不关心这个。
- 滚动更新:就是新服务发布出错了,可以回滚到先前稳定的版本。
Docker Swarm有几个关键概念需要我们明白:
- Nodes: 节点,一个节点是docker引擎集群的一个实例,你可以将其视为Docker节点。你可以在单个物理计算机或云服务器上运行一个或多个节点,但生产群集部署通常包括分布在多个物理和云计算机上的Docker节点。Swarm节点包括两类:管理节点和工作节点,我们把服务定义发送给管理节点,管理节点把任务分配给工作节点去执行。
- Services: 一个服务就是任务的定义,在docker-compose.yml里主要就是定义一个个服务。
- Tasks: 任务,一个任务就是一个容器以及在容器里运行的命令。
- Load Balancing: 负载均衡。
3. Docker Swarm架构分析
3.1 节点怎样工作
Swarm支持多个管理节点,管理节点负责处理集群的管理任务:1)维护集群状态;2)调度服务;3)提供Swarm模式HTTP API端点服务。工作节点就是执行服务的任务。
3.2 服务怎样工作
上图阐述了服务、任务和容器的协作关系,服务service有多个replicas,分派成多个task去执行,task在container里去执行。
3.3 任务和调度
3.4 副本服务和全局服务
副本服务就是指定了多少副本,就会执行多少个任务和运行容器,一般我们的业务系统服务就是采用这种方式的。
全局服务是每个节点运行一个任务,不需要预先指定副本,每次你添加一个新节点进入Swarm集群,新节点也会被分派执行一个任务,这种服务一般是监控代理、杀毒扫描等服务。
4. Docker Swarm集群部署
我们要部署一个应用程序到Swarm集群,一般的操作步骤是:
- 初始化一个Swarm模式的集群;
- 添加节点到Swarm集群;
- 部署应用服务到Swarm集群;
- 管理Swarm集群。
4.1 部署前环境准备
- 准备几台Linux服务器,安装好Docker Engine,服务器之间网络互通;
- 选择一台Linux服务器为管理节点,查询其IP地址;
- 服务器之间开放协议端口:
- Port
2377
TCP for communication with and between manager nodes; - Port
7946
TCP/UDP for overlay network node discovery; - Port
4789
UDP (configurable) for overlay network traffic。
- Port
4.2 创建一个Swarm
在管理节点执行:
$ docker swarm init --advertise-addr <MANAGER-IP>
例如:
$ docker swarm init --advertise-addr 192.168.99.100
Swarm initialized: current node (dxn1zf6l61qsb1josjja83ngz) is now a manager.To add a worker to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
192.168.99.100:2377To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
查看swarm当前状态:
$ docker info
查看swarm节点情况:
$ docker node ls
4.3 添加工作节点到Swarm集群
在你规划的各个worker node上执行:
$ docker swarm join \
--token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
192.168.99.100:2377This node joined a swarm as a worker.
如果你不记得token了,则去管理节点去执行:
$ docker swarm join-token worker
To add a worker to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
192.168.99.100:2377
4.4 部署一个服务到Swarm集群
在管理节点上执行:
$ docker service create --replicas 1 --name helloworld alpine ping docker.com
9uk4639qpg7npwf3fn2aasksr
docker service create
: 创建服务命令.--name
:服务名helloworld
.--replicas :指定副本数量,即运行任务的容器数量
.alpine ping docker.com:alpine是镜像,执行任务命令是:
ping docker.com
.
查看运行中的服务命令:
$ docker service ls
ID NAME SCALE IMAGE COMMAND
9uk4639qpg7n helloworld 1/1 alpine ping docker.com
4.5 探查一个服务
探查一个服务情况执行:
$ docker service inspect --pretty <SERVICE-ID>
$ docker service ps <SERVICE-ID>
4.6 Scale一个服务
$ docker service scale <SERVICE-ID>=<NUMBER-OF-TASKS>
例如:
$ docker service scale helloworld=5
helloworld scaled to 5
$ docker service ps helloworld
4.7 删除一个运行中的服务
$ docker service rm helloworld
helloworld
4.8 部署一个stack到swarm
采用docker service create 命令部署一个服务太麻烦,太多参数需要自己手工在命令行指定,不是高效的做法,最终我们还是要用docker-compose.yml来定义一切参数,一个简单命令来提交是最好的。
假如我们已经做好了几件事情:
- 应用程序部署需要的所有镜像已经做好了;
- docker-compose.yml编排文件已经做好了;
- 镜像仓库已经存在了,如Docker Register、Docker Hub、Harbor;
- 在本地已经用docker compose测试了应用程序的正确性;
- 应用程序的所需镜像已经推送到镜像仓库。
4.8.1 创建一个stack
使用docker stack deploy命令来执行,stack名为stackdemo:
$ docker stack deploy --compose-file docker-compose.yml stackdemo
Ignoring unsupported options: build
Creating network stackdemo_default
Creating service stackdemo_web
Creating service stackdemo_redis
4.8.2 检查stack的运行情况
使用docker stack services命令来执行,指定stack名:
$ docker stack services stackdemo
ID NAME MODE REPLICAS IMAGE
orvjk2263y1p stackdemo_redis replicated 1/1 redis:3.2-alpine@sha256:f1ed3708f538b537eb9c2a7dd50dc90a706f7debd7e1196c9264edeea521a86d
s1nf0xy8t1un stackdemo_web replicated 1/1 127.0.0.1:5000/stackdemo@sha256:adb070e0805d04ba2f92c724298370b7a4eb19860222120d43e0f6351ddbc26f
4.8.3 删除一个stack
如果你不需要这个stack,则删除它,执行docker service rm:
$ docker stack rm stackdemo
Removing service stackdemo_web
Removing service stackdemo_redis
Removing network stackdemo_default
5. Docker Swarm的官方文档
5.1 Docker Swarm的用户手册
我基本上是按照这个地址来学习操作的,篇幅不大,耐心阅读完就够了,无须阅读其它二手资料:Swarm mode overview | Docker Docs。
5.2 Docker Swarm的命令参考手册
命令参考手册地址:docker swarm | Docker Docs
6. 总结
Docker Swarm 是 Docker 官方推出的容器编排工具,不同于Docker Compose 是一个在单个服务器或主机上创建多个容器的工具, Docker Swarm 是在多个服务器或主机上创建容器集群服务,对于微服务的部署,自然 Docker Swarm 才是解决之道。
对于中小公司的小型云原生应用系统而言,选择Docker Swarm可能更为适合,适合才是最好的,系统架构师需要根据公司实际情况进行慎重选择。