docker-swarm

概览

启动一个容器如果把端口暴露出来映射到物理机上,则直接端口通信即可,如果有多个容器共同构成一个整体对外提供服务,如典型的LNMP架构,一般只需要暴露一个80端口,此时容器之间通信可以使用docker-compose编排

docker-compose是一个二进制工具,安装docker的时候默认不带,需要额外下载;docker-compose只能实现单机容器之间通过名称+内部端口通信(这个端口无需暴露在物理机上),如果是跨机器容器之间通信docker-compose则不行;docker-compose可以通过一份YAML文件,管理一组容器

docker-swarm可以实现跨机器容器之间的通信,安装docker默认自带,无需额外安装,相比K8S功能要少得多,当然也简单的多

使用docker-compose编排docker容器,几乎没有引入任何docker知识的新概念,docker-compose工具基本上就是拿来启动、重启一组docker容器用,其它的容器调试管理,或者单个容器的重启,完全基于已有的docker知识操作即可,比如我们用docker-compose启动5个容器,然后我们再手动docker rm -fv xxx,关掉一个容器,此时docker-compose不会有任何感知,一切按照正常docker容器的逻辑走,docker-compose不额外启动进程,更不监听端口

使用docker-swarm则不一样了,首先swarm引入了一个服务的概念,也就是我们docker service ls看到的东西,服务背后才是容器,swarm的服务可以docker service create xxx来创建,新版本的swarm也支持直接利用docker-compose的YAML文件来启动服务(比较复杂,对YAML文件有特定的要求)

swarm之所以能实现不同机器上的容器,直接通过服务名来通信,是因为swarm集群直接实现了overlay平面网络,我们不管overlay平面网络细节是什么,看到的效果就是每台机器上都要启动额外的swarm进程,进程之间是通过一个特定的端口通信默认是4789,K8S的flannel实现overlay平面网络的原理也类似

swarm集群里的服务,其启动和停止都要使用swarm专门的管理命令,原始的docker命令则不适用,如果某个容器被我们手动docker rm -fv xxx删掉,swarm服务会根据自定义的规则将其重新拉起来

swarm 对比 K8S (个人使用体会)

  • swarm简单,学习成本较之K8S那是相当低,对docker较为熟练的话,上手swarm几小时的事情,而K8S如果第一次使用,即便对docker熟练,想要妥善安装能够在生产环境上使用的K8S环境,目测没个一星期下不来
  • swarm的稳定性、性能有待提高,不适合大规模集群,节点数最好控制在几十台以内
  • 在实际生产使用环境中,我们发现在一些恶劣的网络环境下,如虚拟化是vmware做的,甚至干脆是用vmware桌面版做的,swarm稳定性就更差,经常会莫名奇妙网络中断

综上,选型swarm作为集群容器编排工具,最好在规模不大,服务较固定,经过良好测试的情况下使用

之前博客园cnblogs,就使用swarm编排容器,看他们写的文章,后面swarm一些诡异问题把他们折腾的够呛,现在已换成K8S

安装

准备3台机器

192.168.31.100
192.168.31.101
192.168.31.102

用到的端口

  • TCP port 2377 for cluster management communications
  • TCP and UDP port 7946 for communication among nodes
  • UDP port 4789 for overlay network traffic

3台机器都安装上docker

cd /etc/yum.repos.d/
wget http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install docker-ce-18.09.9 docker-ce-cli-18.09.9 containerd.io -y
systemctl start docker
mv /etc/yum.repos.d/docker-ce.repo /etc/yum.repos.d/docker-ce.repo.off

创建集群

[root@192-168-31-100 ~]# docker swarm init --advertise-addr 192.168.31.100
Swarm initialized: current node (m04s2jamtjt4r1i34ws8ogtbz) is now a manager.
To add a worker to this swarm, run the following command:
    docker swarm join --token SWMTKN-1-08u11b1u6oyigexvmv10yr8rvl161upyqbx2lo90lr0oaehjfn-82y978ljp0jx70zauaj8t3n9z 192.168.31.100:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

执行上面这条命令,输出的信息非常重要,若是生产环境搭建swarm集群,建议复制保存下来,执行完毕上面的命令,表示本机初始化为docker swarm的manager节点,swarm有manager、worker2种节点,我们这里搭建3台manager节点

我们看下本机新监听的端口

[root@192-168-31-100 ~]# netstat -lntup | grep docker
tcp6       0      0 :::2377                 :::*                    LISTEN      1503/dockerd
tcp6       0      0 :::7946                 :::*                    LISTEN      1503/dockerd
udp6       0      0 :::7946                 :::*                                1503/dockerd

下面的命令可以分别打印,新机器加入swarm集群作为manager还是worker的信息

docker swarm join-token manager #输出加入manager节点的信息
docker swarm join-token worker  #输出加入worker节点的信息
docker swarm join-token --help

如下输出,拿到命令到另外2台机器执行
[root@192-168-31-100 ~]# docker swarm join-token manager
To add a manager to this swarm, run the following command:
    docker swarm join --token SWMTKN-1-08u11b1u6oyigexvmv10yr8rvl161upyqbx2lo90lr0oaehjfn-e8syzjnp83ypsfwofqc41kgu5 192.168.31.100:2377

[root@192-168-31-101 ~]# docker swarm join --token SWMTKN-1-08u11b1u6oyigexvmv10yr8rvl161upyqbx2lo90lr0oaehjfn-e8syzjnp83ypsfwofqc41kgu5 192.168.31
.100:2377
This node joined a swarm as a manager.

[root@192-168-31-102 ~]# docker swarm join --token SWMTKN-1-08u11b1u6oyigexvmv10yr8rvl161upyqbx2lo90lr0oaehjfn-e8syzjnp83ypsfwofqc41kgu5
192.168.31.100:2377
This node joined a swarm as a manager.

检查

docker node ls
docker info

下面的命令3台机器都可以执行
# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
m04s2jamtjt4r1i34ws8ogtbz *   192-168-31-100      Ready               Active              Leader              18.09.9
oesjwho6g9ref3h2s1fsy0d60     192-168-31-101      Ready               Active              Reachable           18.09.9
nmvhzpwo4f54rzdya1qrgnnas     192-168-31-102      Ready               Active              Reachable           18.09.9
# docker info
...
Swarm: active
 NodeID: m04s2jamtjt4r1i34ws8ogtbz
 Is Manager: true
 ClusterID: 05pvx9f8etqa69tshhlr4gcfi
 Managers: 3
 Nodes: 3
 Default Address Pool: 10.0.0.0/8
...

 Manager Addresses:
  192.168.31.100:2377
  192.168.31.101:2377
  192.168.31.102:2377
...

可以看到本机器是否处在swarm模式下,以及本机的角色manager or worker

部署服务到swarm集群上

docker service create --replicas 1 --name helloworld alpine ping docker.com
docker service ls

只有manager节点才可以创建服务

[root@192-168-31-100 ~]# docker service create --replicas 1 --name helloworld alpine ping docker.com
nuuzvjdtplecysrv2qe4zwlqn
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged
[root@192-168-31-100 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
nuuzvjdtplec        helloworld          replicated          1/1                 alpine:latest
[root@192-168-31-100 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
337b10f0c3f0        alpine:latest       "ping docker.com"   27 seconds ago      Up 25 seconds                           helloworld.1.skmotjl8mrh2qh
3sg6y8r4qy4

只启动一个容器副本,这个容器会根据内部算法调度到一台机器上运行,如果我们去手动用docker命令把这个容器删掉,等待一会swarm会自动将其拉起,以保证副本数量始终是1
  • 如果我们启动一个服务监听某个端口,那么所有swarm集群都会监听这个端口
  • 直接在命令行里敲 docker service create xxx 场景服务,后面可能不好维护,可以把相关命令写到脚本里
  • 可以通过标签绑定的形式让某个容器固定落到某台机器上(缺点是维护成本高、无自带高可用功能)
  • 重启docker服务会导致swarm服务漂移

常用swarm管理命令

常用的swarm管理命令,基本上通过 --help 都能看到
docker node --help
docker service --help
docker service create --help
docker swarm --help

查看某个服务的详细信息
docker service inspect --pretty ${service_name}

查看某个服务跑在哪个节点上
docker service ps ${service_name}

删除某个服务
docker service rm ${service_name}

更新某个服务,让其恢复之前定义的状态(相当于重启)
docker service update ${service_name}

查看某个节点上跑了哪些服务(node名称可以是多个,空格分割)
docker node ps [NODE...] | grep ${service_name}


滚动更新某个服务
场景举例:刚开始使用 docker service create xxx 启动3个nginx副本,分布到3台机器,前端做负载均衡,后面量大,准备扩容成5个,swarm可以实现先停止1个容器,然后启动这个容器,确保其running之后,继续下个容器,与K8S滚动更新逻辑类似,更多细节参考官方文档

驱逐swarm节点(节点下线)

场景:如果我们有10个swarm节点,它们都在正常工作状态,那么新创建的服务,对应的容器每台机器上都有可能分配,而现在我们已经知道某个节点可能有问题(比如磁盘坏掉)需要让其平滑下线(从swarm集群中移除)

关键命令一览

docker node update --availability drain  ${NODE_NAME}
docker node update --availability active ${NODE_NAME}
docker node demote  ${NODE_NAME}
docker node promote ${NODE_NAME}
docker node rm      ${NODE_NAME}
docker swarm leave -f

操作演示细节

[root@192-168-31-100 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
m04s2jamtjt4r1i34ws8ogtbz *   192-168-31-100      Ready               Active              Leader              18.09.9
oesjwho6g9ref3h2s1fsy0d60     192-168-31-101      Ready               Active              Reachable           18.09.9
nmvhzpwo4f54rzdya1qrgnnas     192-168-31-102      Ready               Active              Reachable           18.09.9

可以看到上面3台机器都是manager节点,都处在Active正常状态,下面我们驱逐 192-168-31-100

[root@192-168-31-100 ~]# docker node update --availability drain 192-168-31-100
192-168-31-100
[root@192-168-31-100 ~]# docker node ls | grep "192-168-31-100"
m04s2jamtjt4r1i34ws8ogtbz *   192-168-31-100      Ready               Drain               Leader              18.09.9

可以看到 192-168-31-100 已经变成 Drain 状态了,其上的容器会被逐步删除,调度到其它机器上,不能有绑死机器的容器,否则会调度失败,这种操作只适合被swarm管理的机器,类似docker run xxx直接启动的容器不受影响,不建议在swarm集群上手动通过docker run xxx 额外启动容器

标记成Drain,状态之后,可以再用docker ps xxx或者登录到相关机器上docker ps -a,查看是否所有容器都已被妥善驱逐

确认没有其上没有服务,并且在其它机器上已经重建该服务之后,可以 docker node rm ${NODE_NAME} ,把这个节点从swarm集群删除,待调整好之后再重新加入,不删除在那块放在问题也不大,不会有新容器调度上去,当那台机器修复好后可以用 docker node update --availability active ${NODE_NAME} ,重新加入集群

下线快速步骤参考

docker node update --availability drain  ${NODE_NAME}
docker node demote  ${NODE_NAME}
docker swarm leave -f #登录到需要下线的机器执行
docker node rm      ${NODE_NAME}

swarm 负载均衡

在这里插入图片描述

cat /etc/haproxy/haproxy.cfg
global
        log /dev/log    local0
        log /dev/log    local1 notice
...snip...

# Configure HAProxy to listen on port 80
frontend http_front
   bind *:80
   stats uri /haproxy?stats
   default_backend http_back

# Configure HAProxy to route requests to swarm nodes on port 8080
backend http_back
   balance roundrobin
   server node1 192.168.99.100:8080 check
   server node2 192.168.99.101:8080 check
   server node3 192.168.99.102:8080 check

结合haproxy的配置文件和上图分析:

  • 这里的haproxy相当与我们的4层负载均衡,其指向3台swarm机器的8080端口
  • 不管访问哪台机器的8080端口,效果都是一样的,swarm内置的负载均衡策略会帮我们路由到后端容器上
  • 其中一台swarm节点挂掉,依然不影响服务的对外访问

参考

https://docs.docker.com/engine/swarm/
https://docs.docker.com/engine/swarm/swarm-tutorial/deploy-service/
https://docs.docker.com/engine/swarm/swarm-tutorial/drain-node/
https://docs.docker.com/engine/swarm/ingress/
https://docs.docker.com/engine/swarm/how-swarm-mode-works/nodes/

csdn https://blog.csdn.net/xys2015/article/details/109537977