Swarm介绍
Swarm 是 Docker 公司在 2014 年 12 月初发布的一套较为简单的工具,用来管理 Docker 集群,它将一群 Docker 宿主机变成一个单一的,虚拟的主机。Swarm 使用标准的 Docker API接口作为其前端访问入口,换言之,各种形式的 Docker Client(docker client in go, docker_py,docker 等)均可以直接与 Swarm 通信。Swarm 几乎全部用 Go 语言来完成开发。
Swarm deamon 只是一个调度器(Scheduler)加路由器(router),Swarm 自己不运行容器,它只是接受 docker 客户端发送过来的请求,调度适合的节点来运行容器,这意味着,即使Swarm 由于某些原因挂掉了,集群中的节点也会照常运行,当 Swarm 重新恢复运行之后,它会收集重建集群信息。下面是 Swarm 的结构图:
环境准备
- 三台服务器或者虚拟机
- server01, server02, server03
- 安装了docker
搭建集群
初始化一个manager节点
docker提供了init命令用于初始化一个集群, 从输出信息中可以得到对应的work节点的token
n-tech-admin@server01:~$ docker swarm init
Swarm initialized: current node (wpx3o9mcpuq79ujpumykjkgt7) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-44a0imbc65z7o9fbfj89mxs4xfu7w3pmtfo7s50mt3ues809mr-0xhunq3plzdyhyhebswxuuds8 192.168.10.45:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
在其他服务器输入命令
在上一步的输出中, 已经包含了其他节点加入该集群的命令.只需要输入即可.
n-tech-admin@server02:~$ docker swarm join --token SWMTKN-1-44a0imbc65z7o9fbfj89mxs4xfu7w3pmtfo7s50mt3ues809mr-0xhunq3plzdyhyhebswxuuds8 192.168.10.45:2377
This node joined a swarm as a worker.
n-tech-admin@server03:~$ docker swarm join --token SWMTKN-1-44a0imbc65z7o9fbfj89mxs4xfu7w3pmtfo7s50mt3ues809mr-0xhunq3plzdyhyhebswxuuds8 192.168.10.45:2377
This node joined a swarm as a worker.
查看docker network
创建集群之后, 我们可以看到network增加了docker_gwbridge
和ingress
两个网络.
swarm的ingress连接的是ingress网络, 该网络需要通过docker_gwbridge网桥, 借助于docker daemon网桥跟主机进行连接.
n-tech-admin@server01:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
cdb39c520f0b bridge bridge local
fd5e65ece1c7 docker_gwbridge bridge local
eb06b54c7e76 host host local
tbsdc0m2p1le ingress overlay swarm
f4e8f15f758b none null local
高可用
docker默认支持高可用, 通过选举将work节点挑选为manager节点. 只需要配置所有节点为manager节点即可.
首先可以通过docker node ls查看所有的节点信息.可以看到默认情况下MANAGER STATUS
只有server01是一个Leader节点. 其他节点都是普通节点.
n-tech-admin@server01:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
wpx3o9mcpuq79ujpumykjkgt7 * server01 Ready Active Leader 18.09.3
1bz3t5imxc9evv4poh9o3o65l server02 Ready Active 18.09.0
nuwhcuajlf71q4x23syi7tx06 server03 Ready Active 18.02.0-ce
通过在manager节点
执行 docker node promote 服务器名称
, 可以将其他节点提升为manager节点.
可以看到执行之后, 另外两个work节点的MANAGER STATUS
也变成了Reachable
n-tech-admin@server01:~$ docker node promote server02
Node server02 promoted to a manager in the swarm.
n-tech-admin@server01:~$ docker node promote server03
Node server03 promoted to a manager in the swarm.
n-tech-admin@server01:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
wpx3o9mcpuq79ujpumykjkgt7 * server01 Ready Active Leader 18.09.3
1bz3t5imxc9evv4poh9o3o65l server02 Ready Active Reachable 18.09.0
nuwhcuajlf71q4x23syi7tx06 server03 Ready Active Reachable 18.02.0-ce
创建服务
我们在 manager
创建一个linux服务, 提供一个shell命令让他运行.
通过执行 service ls
命令, 可以看到刚才运行服务已经成功了.
还可以通过 service inspect 服务名
查看服务的详细信息
通过 service logs 服务名
查看服务的详细日志
n-tech-admin@server01:~$ docker service create --name test01 alpine ping baidu.com
ruzuc9hqpyv6dpe6qk8jmlc12
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
n-tech-admin@server01:~$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
ruzuc9hqpyv6 test01 replicated 1/1 alpine:latest
接下来, 我们继续通过swarm创建一个nginx服务, 执行上面相同的命令, 创建完成后, 通过ls命令查看服务.
n-tech-admin@server01:~$ docker service create --name nginx nginx
n6svunal14gc78uffbzn5rl76
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
n-tech-admin@server01:~$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
n6svunal14gc nginx replicated 1/1 nginx:latest
ruzuc9hqpyv6 test01 replicated 1/1 alpine:latest
修改服务
我们发现, nginx没有对外端口, 我们可以通过 update 命令将nginx对外暴露一个端口
然后我们通过浏览器访问 server01, server02, server03三个服务器, 发现都能够得到正确的响应, 这是因为docker通过虚拟IP的方式帮我们访问到最终提供服务的nginx容器.
n-tech-admin@server01:~$ docker service update --publish-add 9967:80 nginx
nginx
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
服务扩展
docker为我们提供了 scale 命令, 可以对服务进行扩容, 我们通过 service scale nginx=3, 将nginx容器扩容到三个, 然后通过ls命令可以看到 REPLICAS
已经变成了3/3.
n-tech-admin@server01:~$ docker service scale nginx=3
nginx scaled to 3
overall progress: 3 out of 3 tasks
1/3: running [==================================================>]
2/3: running [==================================================>]
3/3: running [==================================================>]
verify: Service converged
n-tech-admin@server01:~$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
n6svunal14gc nginx replicated 3/3 nginx:latest *:9967->80/tcp
ruzuc9hqpyv6 test01 replicated 1/1 alpine:latest
服务间应用连通性
通过上面, 我们创建了 test01 服务和 nginx 服务, 然后我们通过 exec -it
登录到 alpine 的 test01 服务, 通过 ping nginx
发现不能连通, 说明默认模式下创建的服务, 不具备服务之间的连通性.
那么, 既然问题提出了, 下面就来说一下怎么解决.
首先, 我们创建一个 network, driver使用 overlay, 名字叫做 local-overlay. 如下
n-tech-admin@server01:~$ docker network create -d overlay local-overlay
7lg34csui03vtcwie57pshodd
n-tech-admin@server01:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
cdb39c520f0b bridge bridge local
fd5e65ece1c7 docker_gwbridge bridge local
501f1e83da67 harbor_harbor bridge local
eb06b54c7e76 host host local
tbsdc0m2p1le ingress overlay swarm
7lg34csui03v local-overlay overlay swarm
f4e8f15f758b none null local
82d08c922135 syncd bridge local
6b2cd023f92f syncd-docker_syncd-network bridge local
然后我们删除上面创建的两个服务.
n-tech-admin@server01:~$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
n6svunal14gc nginx replicated 3/3 nginx:latest *:9967->80/tcp
ruzuc9hqpyv6 test01 replicated 1/1 alpine:latest
n-tech-admin@server01:~$ docker service rm nginx test01
nginx
test01
n-tech-admin@server01:~$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
接下来, 我们再次创建两个服务, 不过这次, 我们需要给服务指定网络使用 local-overlay
n-tech-admin@server01:~$ docker service create --name nginx --network local-overlay -p 9967:80 nginx
9mtl0x99t67nxhllfh0ly2m43
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
n-tech-admin@server01:~$ docker service create --name test02 --network local-overlay alpine ping baidu.com
7fnhnrzrxu9ih9hpu4ysnfijw
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
然后我们进入 test02 服务 的 alpine, 执行上面执行失败的 ping
和 wget
, 我们发现, 所有的操作都已经能够正确执行了, 这是因为docker的vip为我们做了处理.
n-tech-admin@server02:~$ docker exec -it aa sh
/ # ping nginx
PING nginx (10.0.0.2): 56 data bytes
64 bytes from 10.0.0.2: seq=0 ttl=64 time=0.105 ms
64 bytes from 10.0.0.2: seq=1 ttl=64 time=0.100 ms
64 bytes from 10.0.0.2: seq=2 ttl=64 time=0.070 ms
^C
--- nginx ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.091/0.105 ms
/ # wget nginx
Connecting to nginx (10.0.0.2:80)
index.html 100% |********************************************************************************************************************************************************************************| 612 0:00:00 ETA
/ #
剔除集群中服务器
如果想要移除集群中某一个服务器, 首先需要判断它是否是一台管理节点, 如果是管理节点, 首先需要将其降级为普通节点, 然后再执行删除命令
降级
docker node demote 节点的id
删除
docker node rm 节点的id
stack
docker 为集群部署的一系列操作提供了 stack
子命令, 方便一次操作.
首先我们需要准备一个 yml 文件, 里面包含了对服务的配置, 就和 compose
文件一样, 不过比 compose文件多了一些对服务资源的限制.
我在这里提供一个文件. external: true
表示该网络已存在的意思.
version: "3.4"
services:
alpine:
image: alpine
command:
- "ping"
- "www.bing.com"
networks:
- local-overlay
deploy:
endpoint_mode: dnsrr
replicas: 2
restart_policy:
condition: on-faliure
resources:
limits:
cpus: "0.1"
memory: "50M"
depends_on:
- nginx
nginx:
image: nginx
networks:
- local-overlay
ports:
- 9967:80
networks:
local-overlay:
external: true
通过 stack deploy
命令对服务进行部署. 通过 stack service 服务名
查看服务详情, 通过 stack ls
查看有多少个服务.
n-tech-admin@server01:~/yzt_test_folder$ docker stack deploy -c service.yml test
Creating service test_alpine
Creating service test_nginx
n-tech-admin@server01:~/yzt_test_folder$ docker stack ls
NAME SERVICES ORCHESTRATOR
test 2 Swarm
n-tech-admin@server01:~/yzt_test_folder$ docker stack services test
ID NAME MODE REPLICAS IMAGE PORTS
3vqmi2loytn6 test_alpine replicated 2/2 alpine:latest
wp7qiu0nbfol test_nginx replicated 1/1 nginx:latest *:9967->80/tcp
n-tech-admin@server01:~/yzt_test_folder$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
3vqmi2loytn6 test_alpine replicated 2/2 alpine:latest
wp7qiu0nbfol test_nginx replicated 1/1 nginx:latest *:9967->80/tcp
网络模式
docker 集群模式下默认使用 vip
模式, 可以显示的指定使用 dnsrr
模式. 如在 stack 下, 可以在 deploy 子节点指定 endpoint_mode: dnsrr
来修改网络模式.
vip: vip模式中每个服务都有一个固定的ip
dnsrr: dnsrr模式是没有固定ip的, 通过dns服务解析
查看服务的模式可以通过 docker service inspect 服务名
, 然后找到 EndpointSpec
节点即可查看.
总结
通篇说了很多, 总结下来也就那么几个命令.
docker swarm
docker network
docker service
docker node
docker stack