docker-swarm的运用

上篇博客 写了如何使用docker-compose来部署服务。虽然docker-compose解决了docker间通信问题,但是缺点也是很明显的。就是只能在一台宿主机上通信。我们使用docker-compose在宿主机上部署了20+的应用,宿主机配置 16C 32GB RAM。服务全部启动后,常态内存占用就高达85%。显然是无法应对突发情况的,因此如果服务比较多,仅仅使用docker-compose是不够的。因此我们使用docker-swarm来部署服务。

 

docker-swarm是docker官方推出的docker集群解决方案,相比与k8s更轻量,因此如果服务不多可以采用docker-swarm来部署服务!

 

1.初始化集群

[root@zhongjianjian03 ~]# docker swarm init

 

 

 执行该命令的节点,一般会成为master(leader)节点,之后的一些集群操作命令,也都是在master节点执行。这里一定要注意

注意红线框住的地方,这里给了一个命令,就是其他节点如果要加入集群可以使用这个命令加入。

我这里又找了一台机器,执行了该命令

 

 

 可以看到当前节点加入到了swarm集群,且作为worker节点。此时

我们可以在master节点查看节点状态了

使用命令。

[root@zhongjianjian03 ~]# docker node ls

 

 

 

 

可以看到目前集群有两个节点了(在这里我是使用了两个linux主机,如果只有一台主机,可以试试使用docker-machine来创建虚拟主机,这个工具还有功能就是可以创建管理本地及远程虚拟主机,试想假如有100台主机,如何在上面配置Docker呢?批量执行脚本是个选择,同样的使用docker-machine也是一个选择)。且一台master 一台work 即MANAGER STATUS 其实这个字段还有其他值

Reachable:该节点是管理节点中的从节点,如果 Leader 节点不可用,该节点有资格被选为新的 Leader

Unavailable:该管理节点已不能与其他管理节点通信。如果管理节点不可用,应该将新的管理节点加入群集,或者将工作节点升级为管理节点。

 这里有一个知识点就是如果节点比较多的情况下怎么知道节点对应的宿主机呢?

其实在每个节点 使用 hostname这个命令即可对应到节点的列表中了。(docker node ls 命令会展示节点对应的Hostname)

实际上我们还可以对每个节点进行个性化设置。即添加标签。

# 只能在manager节点执行该命令
docker node update --label-add <label-name>=<label-value> --label-add <label-name>=<label-value>  <hostname>

命令如上。此时我们即可对每个node添加标签了,比如我们可以添加一个名称为ip的标签

使用命令

docker node update --label-add ip=192.168.1.1 www.xxx.com

即可添加到对应的label。

此时我们在manager节点,使用 docker node ls 得到节点列表。

同时使用。

docker node inspect <节点id>

即可找到该节点对应的ip。当然直接使用该命令(不用前面的麻烦步骤)也可以得到当前节点对应的Ip

 

既然集群已经创建好了,那么我们如何部署自己的应用呢?

其实很简单,前面学习的docker-compose的知识可以用到了。

这里先说明一下部署的应用。要部署4个应用。使用docker-swarm在两个节点的情况下,他会给每个节点分配两个应用。最后达成的效果应该是这个四个服务可以互相访问的到。

首先先编写"docker-compose.yml",这里为什么加上了引号,因为严格意义上说我们并不是要使用docker-compose了,因为这里有的参数并不适用于docker-compose。

version: '3'
services:
  node_a1:
    image: xxx/node:v1
    networks:
      - my-net
    ports:
      - "8000:8080"
    deploy:
      replicas: 1
    command: java -jar node-a1-1.jar
  node_a2:
    image: xxx/node:v1
    networks:
      - my-net
    ports:
      - "8001:8080"
    deploy:
      replicas: 1
    command: java -jar node-a2-1.jar
  node_b1:
    image: xxxx/node:v1
    networks:
      - my-net
    ports:
      - "8002:8080"
    deploy:
      replicas: 1
    command: java -jar  node-b1-1.jar
  node_b2:
    image: xxx/node:v1
    networks:
      - my-net
    ports:
      - "8003:8080"
    deploy:
      replicas: 1
    command: java -jar   node-b2-1.jar

networks:
  my-net:
    driver: overlay

可以看到,我们写了四个应用,这四个应用里面是什么内容呢? 其实就是每个应用访问其他三个应用。需要注意的是。这里使用的网络 是 overlay

 

接下来就是要发布服务了。使用命令

# 在master节点执行 , stack.yml 就是刚才编辑的"docker-compose.yml"文件 test 是服务名前缀
[root@zhongjianjian03 ~]# docker stack deploy -c stack.yml test

 

 

 可以看到创建了一个网络,和四个应用。

此时我们可以查看我们的服务有哪些

#mster节点执行
[root@zhongjianjian03 ~]# docker service ls

 

 

可以看到我们的服务有哪些。

但其实我关心的是,我的服务在哪个节点上,毕竟我是swarm集群,有两台机器。

其实查找服务在哪个节点,有两种方法,一种是直接在某个节点上执行

docker ps

这样就可以看到执行命令的节点上跑了哪些容器(也即服务)。

节点A

 

 

 节点B

 

 

 这样我们就找到了服务对应的机器节点。

你可能会想这样很慢,如果节点很多,那要找一个服务所在的节点不是很慢?

其实还可以使用其他方式,首先查询所有的服务列表

 

 比如我想知道 test_node_b2所在的节点。此时我们现在有了 service id 。我们可以通过命令查到服务所在节点信息

# 在master节点执行
[root@zhongjianjian03 ~]# docker service ps i5xlp60hd4x5

 

 

如图,可以看到已经查到了节点信息,可以跟上图做一个比较,发现信息是一致的。

但是当我们的服务比较多的时候,怎么快速找到服务对应的容器是哪个呢?

# 该命令在master/work节点都可以工作,命令返回容器信息(只显示当前节点的)
docker ps --filter name=<service_name> -q(可选)

 

此时,服务都启动了。我们怎么知道服务之前是否互通呢?

很简单,之前我们在编辑“docker-compose.yml”文件时定义了四个服务。

即:node_a1 node_a2 node_b1 node_b2

 

现在这四个服务分布在了两个机器上。我们任意选择一个机器,选择其中的一个容器进去。

比如我们进入node_a1容器

# 需在容器所在的节点 上执行该命令
[root@zhongjianjian03 ~]# docker exec -it d97765b92136 bash
这样我们就进入了容器内部。

接着我们只需要使用ping 命令就可以知道是否可以互相访问了

 

 

 

 

 

 从图片可以知道。网络是通的。接着就可以测试自己应用的通过性了,具体就以实际应用为准了

 

如果这些服务不需要要了可以删除stack

# test为前面定义的名称,此操作会删除stack中定义的所有服务和网络
[root@localhost ~]# docker stack rm test
# 如果忘记了前面定义的stack的名称,可以通过下面的命令查看
[root@localhost ~]# docker stack ls
# 有时候创建了service,但是发现副本数为0,此时需要查看一下service的状态,(这里--no-trunc=true的意思是不要阶段输出,此时我们就可以知道失败的原因了)
[root@localhost ~]# docker service ps --no-trunc=true test_app1

 


至此docker-swarm集群搭建完毕。可以看到跟docker-compose相比,只是在命令上有些不同,docker-compose需要单独安装,而docker-swarm则需要提前创建集群。
现在我们的应用分布在集群里,就可以方便的进行服务冗余了,当然docker-swarm的命令不止这些,但是缺点也比较明显就是没有可视化的界面可供操作,虽然可以通过安装portainer
来管理swarm集群,但功能上会有局限,并没有k8s强大!

同样的,如果同一个stack中添加了某个服务,那么先在 stack.yml中添加新增服务配置。然后使用命令

 

# 这里使用了dock stack deploy命令,与新增stack一样,区别是如果stack存在,则为更新stack,他并不会全部更新,而是只更新变动的服务
docker stack deploy --compose-file=/opt/docker/yml/stack.yml {stackName}

即可完成新增服务的部署!

 

如果不想使用集群了。也可以删除集群。

当前节点状态:

 

 可以看到 AVAILABILITY字段的两个值均是在线状态

删除节点:

# 让 node3 离开,排空 该node 的容器(在 master 上操作)
[root@zhongjianjian03 ~]# docker node update --availability drain i0yhyiotqklaj7626jfavnuky

此时可以看到node的状态

 

 让被移除的node离开集群

# 在被离开的节点上操作
[root@app01 ~]# docker swarm leave

Node left the swarm.

删除node节点

# 在master节点操作
[root@zhongjianjian03 ~]# docker node rm i0yhyiotqklaj7626jfavnuky

此时 节点列表为:

 

 

之后我们只需要使用类似的命令就能删掉主节点:

[root@zhongjianjian03 ~]# docker node update --availability drain rsj6jxbm1fwz7dsbn0pxillxj
rsj6jxbm1fwz7dsbn0pxillxj


[root@zhongjianjian03 ~]# docker swarm leave --force
Node left the swarm.

 

之后再次查看集群状态

 

 集群已移除!。

 

如果master节点未被删除,现在有新节点要加入集群,应该如何获取Token呢?

 

# 在master节点上使用命令 docker swarm join-token 可以查看或更换join token。
docker swarm join-token worker:查看加入woker的命令。
docker swarm join-token manager:查看加入manager的命令
docker swarm join-token --rotate worker:重置woker的Token。
docker swarm join-token -q worker:仅打印Token。

 

 

需要注意的几个点,我们上篇文档介绍了 。docker-compose占位符的使用。

而在docker swarm的stack.yml文件中,除了部分配置有差别外,docker-compose的占位符也是不能直接使用的。

如果你直接使用了,你在启动的容器中使用inspect查看容器信息。是看不到占位符的信息的。

因此总体解决思路是这样的:

# 先执行命令
docker-compose -f custom-docker-compose.yml config > stack.yml

使用docker-compose config命令输出整合了变量文件的YML文件到stack.yml

然后再使用

# 启动stack
docker stack deploy -c stack.yml  <stack name>

 

可以参考

 

同时,docker swarm 与docker-compose本身也是有区别的,当然显著的区别是docker-compose 是单机的,swarm是集群的,同时,对于docker-compose来说,每个服务是container 而docker swarm是每个service,虽然在docker-compose 也可以使用service,这个在 portainer 工具中是可以查看的,有一个能想到的点是,如果我docker swarm发布了很多应用,这个时候我想更改某个服务的端口映射,那么停止服务,更新脚本,重启启动,明显是很麻烦的。其实还是可以通过docker命令来更新的。链接

更新运行中容器端口映射。

#添加端口映射,第一个为宿主机端口,servicename需要注意,看使用的是swarm集群还是直接的compose,如果是swarm集群需要加上stack 名
docker service update --publish-add '5050:8080'  <service_name>

 

 

 

由上所述服务在单副本的情况下,是没有问题的,但是多副本时,就会涉及到服务的负载均衡。简单来讲,docker swarm的负载均衡有两种方式

1.vip

vip这种形式为swarm的默认形式,简单说,如果swarm集群里,部署了一个nginx应用,并且配置容器与宿主机的端口映射,此时你访问集群的任意节点,都可以访问该服务。

2.dnsrr

dnsrr需要单独进行配置,对应命令行中的 --endpoint-mode dnsrr 。这种模式下不支持端口映射,也就是说如果你是前端应用就不能使用该模式了。该模式的是使用DNS轮询的方法进行的负载均衡。因此比较适合做后端服务。也就是说在一个swarm的stack中,后端service有多个副本,适合使用该方式,前端发送的请求后均匀发送到后端的容器中。然而并非每次请求都会均匀分布,比如十次请求,前5次走A容器后5次走B容器,如果manager节点也运行了服务,则manager节点不处理请求。

#version: "3"  #这里需要注意版本,如果是3则报错:error endpoint_mode Additional property endpoint_mode is not allowed
version: "3.3" 
 
services:
  wordpress:
    image: wordpress
    ports:
      - 8080:80
    networks:
      - overlay
    deploy: 
      mode: replicated
      replicas: 2
      endpoint_mode: vip  #wordpress是前端应用(准确说是前后端在一起的应用)使用默认的vip方式
 
  mysql:
    image: mysql
    volumes:
       - db-data:/var/lib/mysql/data
    networks:
       - overlay
    deploy:
      mode: replicated
      replicas: 2
      endpoint_mode: dnsrr #mysql是后端服务,不与宿主机映射端口,可以使用dns轮询的方式
 
volumes:
  db-data:
 
networks:
  overlay:

 compose-file API

 

swarm不同节点无法访问

posted @ 2021-04-12 18:19  陈无问  阅读(835)  评论(0编辑  收藏  举报