Docker Swarm介绍

2021-11-26

前言

本篇是Docker第十三篇,Docker的使用至此就介绍完成,接下来继续Kubernetes。

Docker系列文章:
  1. 为什么要学习Docker
  2. Docker基本概念
  3. Docker镜像基本原理
  4. Docker容器数据卷
  5. Dockerfile
  6. Docker单机网络上
  7. Docker单机网络下
  8. Docker单机网络实战
  9. Docker隔离技术
  10. Docker限制
  11. Docker Compose
  12. Docker多机网络

为什么需要Docker Swarm

  1. 我们从Docker到Docker Compose都是在单机上完成,这样会带来一个很现实的问题就是高可用的问题,如果只部署到一台机器是无法做到高可用的,这样就不具备生产的条件;

  2. Docker Compose只是简单做了单机服务的编排、扩容,对于多机器的管理、发布、服务发现、负载均衡都没有很好的解决;

  3. 目前我们所有的容器都是在单个宿主机上进行网络通信,多机情况的网络通信也没有解决方案;

针对以上三点,Docker给出了Docker Swarm的解决方案,Docker swarm可以让用户轻松在多个机器上发布和管理应用,并且我们不需要关注每个容器实例具体落在哪一个节点,Docker swarm把我们的应用以服务的形式暴露出去,并内置服务发现和负载均衡,让运行在多个节点上的容器集群感觉就像只有一个应用在跑一样简单,可以轻松实现扩容和自动容错。Docker swarm集群通常有几个工作程序节点和至少一个管理程序节点,负责高效地处理工作程序节点的资源并确保集群有效地运行,提高了应用可用性。

Docker Swarm概念介绍

img
img
Manager Node

Manger 节点是负责管理工作的,从名字就可以看出,注意负责以下事情:

  1. 维护集群的状态;

  2. 对 Services 进行调度;

  3. 为 Swarm 集群提供外部可调用的 API 接口;

  4. 提供服务注册发现、负责均衡等功能;

Manager 节点需要时刻维护和保存当前 Swarm 集群中各个节点的一致性状态,在保证一致性上,Manager 节点采用 Raft 协议来保证分布式场景下的数据一致性;

Worker Node

Worker 节点是用来执行 Task 的;默认情况下 Manager 节点也同样是 Worker 节点,同样可以执行 Task;

image.png
image.png
Service

Services 是指一组任务的集合,服务定义了任务的属性,比如任务的个数、服务策略、镜像的版本号等等,服务有两种模式:

  1. replicated services 按照一定规则在各个工作节点上运行指定个数的任务;
  2. global services 每个工作节点上运行一个任务;
Task

Task是 Swarm 集群中的最小的调度单位,任务包含一个Docker容器和在容器内运行的命令,如果某一个任务奔溃,那么协调器将创建一个新的副本任务,该任务将生成一个新的容器;

Task调度
img
img

Task调度主要分为两部分: Manager节点的任务分配和Worker节点的任务执行;

Manager节点的任务分配主要有以下四步:

  1. 用户通过 Docker Engine Client 使用命令 docker service create 提交 Service 定义;

  2. Manager节点根据定义创建相应的 Task,并分配IP地址;

  3. 将Task分发到对应的节点上;

  4. 节点进行相应的初始化使得它可以执行Task;

Worker节点的任务执行主要有两步:

  1. 连接Manager节点的分配器检查该Task相关定义的信息;
  2. 验证通过以后,开始在 Worker 节点上执行Task;

注意,上述 Task 的执行过程是一种单向机制,比如它会按顺序的依次经历 assigned, prepared 和 running 等执行状态,不过在某些特殊情况下,在执行过程中,某个 Task 执行失败了,Manager 的编排器会直接将该 Task 以及它的 Container 给删除掉,然后在其它节点上另外创建并执行该 Task;

Docker Swarm网络

核心概念介绍
img
img
  1. Overlay Network:管理 Swarm 中 Docker 守护进程间的通信。你可以将服务附加到一个或多个已存在的 overlay 网络上,使得服务与服务之间能够通信;

  2. Ingress Network:一个特殊的 overlay 网络,用于服务节点间的负载均衡。当任何 Swarm 节点在发布的端口上接收到请求时,它将该请求交给一个名为 IPVS 的模块。IPVS 跟踪参与该服务的所有IP地址,选择其中的一个,并通过 ingress 网络将请求路由到它。初始化或加入 Swarm 集群时会自动创建 ingress 网络,大多数情况下,用户不需要自定义配置,但是 docker 17.05 和更高版本允许你自定义;

  3. Docker Gwbridge Network:一种桥接网络,将 overlay 网络连接到一个单独的 Docker 守护进程的物理网络。默认情况下,服务正在运行的每个容器都连接到本地 Docker 守护进程主机的 docker_gwbridge 网络,一种桥接网络,将 overlay 网络(包括 ingress 网络)连接到一个单独的 Docker 守护进程的物理网络。默认情况下,服务正在运行的每个容器都连接到本地 Docker 守护进程主机的 docker_gwbridge 网络;

image.png
image.png
流量分类

Docker Swarm 数据流量分为两个层面:

  1. 控制管理流量(control and management plane traffic): 包括 Swarm 管理消息,例如加入/退出 Swarm 的请求,这些流量总是被加密的;
image.png
image.png
  1. 应用数据流量(Application data plane traffic): 包括容器之间的数据交换,以及容器与外部网络的数据交换,关于这块的原理探讨放在实践的地方;

集群搭建

资源准备

节点全部使用CentOS8.2版, 这边准备了两个node节点和一个master节点:

  1. IP:172.16.0.191 主机名:demo-master-1 担任角色:Swarm Manager
  2. IP:172.16.0.45 主机名:demo-slave-1 担任角色:Swarm Node
  3. IP:192.168.0.231 主机名:demo-slave-2:Swarm Node

保证每个主机之间都能相互ping通并且2377端口可以telnet保持畅通, 每个节点都安装了Docker。

集群安装
  1. 初始化Master节点,命令执行后,该机器自动加入到swarm集群。这个会创建一个集群token,获取全球唯一的 token,作为集群唯一标识。后续将其他节点加入集群都会用到这个token值;
docker swarm init --advertise-addr 172.16.0.191
image.png
image.png
  1. 将Node节点加入集群;
docker swarm join --token SWMTKN-1-3cap7omkvmyuf0q1ybm868880eo5reoil8pcbovmejfzw6pil8-73hc367s4gitudqivrdirvu63 172.16.0.191:2377
  1. 查看Master节点信息;
docker node ls
image.png
image.png
  1. 相关命令;
# 创建服务
docker service create \  
  --image nginx \
  --replicas 2 \
  nginx 

# 更新服务
docker service update \  
  --image nginx:alpine \
  nginx 

# 删除服务
docker service rm nginx

# 减少服务实例
docker service scale nginx=0

# 增加服务实例
docker service scale nginx=5

# 查看所有服务
docker service ls

# 查看服务的容器状态
docker service ps nginx

# 查看服务的详细信息。
docker service inspect nginx
实战
  1. 在Manager节点部署Nginx服务,服务数量为2个,对外暴露的端口是8080映射容器内部的80端口,使用Nginx镜像;
docker service create --replicas 2 --name nginx --publish 8080:80  nginx
image.png
image.png
  1. 查看容器分布状况;
docker service ps swarm-nginx
image.png
image.png
  1. 访问服务;
curl 172.16.0.45:8080
curl 192.168.0.231:8080
image.png
image.png
Internal

Internal容器与容器之间通过overlay网络进行访问,通过service name进行通信,但是service name所对应的ip不是真实ip而是VIP,我们可以下面这个案例进行验证:

img
img
  1. 开始实验前移除创建的服务,创建一个overlay的Network;
docker network create --driver overlay swarm-overlay
#查看网络状况
docker network ls
image.png
image.png
  1. 创建一个nginx的service ,使用swarm-overlay网络;
docker service create --name nginx -p 8080:80 --network swarm-overlay -d nginx
  1. 再创建一个busybox服务;
docker service create --name busybox -d --network swarm-overlay  busybox:1.28.3 sh -c 'while true; do sleep 7200; done'
  1. 查看服务列表;
docker service ls
image.png
image.png
  1. 进入busybox服务内部,使用ping命令访问nginx服务,我们会发现可以访问;
docker exec -it 2f55d73adfb4 sh
ping nginx
image.png
image.png
Ingress

当在任何一个Swarm节点去访问端口服务的时候会通过本节点的IPVS ( ip virtual service )到真正的Swarm节点上。提供以下三种功能:

  1. 外部访问的均衡负载;

  2. 服务端口暴露到各个Swarm节点;

  3. 内部通过IPVS进行均衡负载;

image.png
image.png

接着Internal案例继续进行探索,Swarm节点内部是如何进行转发的;

  1. 查看工作节点的转发规则,我们可以看到把请求转发到172.18.0.2:8000这个地址上去了;
iptables -nL -t nat
image.png
image.png
  1. 接下来我们查看下本机的网络情况,我们找到了docker_gwbridge,可以看到两个ip处于同一网段,那么172.18.0.2应该也连接上docker_gwbridge;
image.png
image.png
  1. 查看docker_gwbridge的interface 信息,我们会发现有多个interface;
brctl show
image.png
image.png
  1. 接下来我们查看下docker_gwbridge网络信息,我们可以发现ingress-sbox就是我们要找的命名空间,gateway_ingress-sbox就是所属的容器;
docker network inspect docker_gwbridge
image.png
image.png
  1. 进入ingress_sbox内部,查看iptables规则,可以看到发送到该ip地址下的8000端口的请求被负载掉了;
#查找ingress_sbox位置
ls /var/run/docker/netns
#进入ingress_sbox
nsenter --net=/var/run/docker/netns/ingress_sbox
#查看ingress_sbox iptables 
iptables -nL -t mangle
image.png
image.png
  1. 查看负载的详细信息;
#在host安装ipvsadm
yum install -y ipvsadm
#再次进入ingress_sbox
nsenter --net=/var/run/docker/netns/ingress_sbox
#查看详细的规则
ipvsadm -l
image.png
image.png
  1. 接下来随便在一台主机找到nginx容器,查看器IP情况,我们会发现与ipvsadm的相对应;
#进入容器
docker exec -it 56c475bb5b2f /bin/bash
#安装一些命令
apt-get update
apt-get install net-tools
#查看网络情况
ifconfig
image.png
image.png

通过探究我们可以得出Docker Swarm网络情况如下:

img当我们访问任一节点的8080端口时,只要我们这个节点处于Swarm集群中,不管服务是否部署到这个节点都能访问,只要端口相同即可。我们本地的请求会被转发到Ingress_sbox这个Network Namespace中,在这个名称空间中再通过lvs转发到具体服务容器的ip和8080端口中去。

结束

欢迎大家点点关注,点点赞!