基于 Linux 的 Docker Swarm 集群部署及应用

docker-docs

Author:rab



一、规划

1.1 主机规划

OSService角色
192.168.56.161(2C/2G)DockerDocker_Swarm_Manager(Work)
192.168.56.162(2C/2G)DockerDocker_Swarm_Work1
192.168.56.163(2C/2G)DockerDocker_Swarm_Work2

⚠注意:如果你是正式环境下进行部署,Manager 必须大于等于 3 台且为奇数(因为在 Manager 挂掉后要进行新 Manager 选举)。该文档的内容结合官方来进行简单测试使用,生成环境中最低服务器数量为(3主+3从)。

1.2 版本规划

  • Linux:CentOS 7.9
  • Docker:18.06.3

更加具体资料请参考官方文档官方参考文档

二、部署

2.1 Docker 服务部署

直接执行我下面给的安装脚本即可,安装路径你可以安装完成后再自行更改,我这是一个快速自动化安装脚本,不存再路径优化项。

#!/bin/bash
# @Default version:18.06.3

# @Auth:rab
# @Date:2021/12/11
# @适用版本:CentOS 7/8

# 查看是否安装
rpm -qa | grep docker &> /dev/null
if [ $? -eq 0 ];then
	v=`rpm -qa |grep docker |awk -F '-' '{print $3}'`
	echo "docker-ce已经安装,版本为:$v"
	read -p "是否卸载原docker版本并安装其他版本?[y/n] " r
    if [ $r = "y" ];then
        yum remove -y `rpm -qa | grep docker` &> /dev/null
        rpm -qa | grep docker &> /dev/null
        if [ $? -ne 0 ]; then
	    	echo "原docker卸载成功!!"
	    else
	    	echo "原docker卸载失败!!"
	    	exit 1
	    fi
	    # step 1: 安装必要的一些系统工具
		yum install -y yum-utils device-mapper-persistent-data lvm2 &> /dev/null
		# Step 2: 添加软件源信息
		yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo &> /dev/null
		# Step 3
		sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
		# Step 4: 更新并安装Docker-CE
       echo "正在建立docker-ce缓存"
		yum makecache       
	    zz=`yum list docker-ce.x86_64 --showduplicates | sort -r |grep docker-ce.x86_64 |awk '{print $2}'`
	    for rr in $zz
        do
            echo "可选安装版本:$rr"
        done
        read -p "选择要安装的docker版本[如18.06.3.ce-3.el7]: " o
        echo ""
        echo "正在安装 docker-ce-$o,请耐心等待....."                         
        yum -y install docker-ce-$o
        if [ $? -eq 0 ]; then
            echo "docker-ce-${o}安装成功!!"
        else
            echo "docker-ce-${o}安装失败!!"
            exit 2
        fi
        # 启动docker
        systemctl enable docker.service
        systemctl start docker.service
        if [ $? -eq 0 ]; then
            echo "docker-ce-${o}启动成功!!"
        else
            echo "docker-ce-${o}启动失败!!"
            exit 2
        fi
        # 配置加速器
        touch /etc/docker/daemon.json
        tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://q1rw9tzz.mirror.aliyuncs.com"]
}
EOF
		if [ $? -eq 0 ]; then
            echo "docker-ce-${o}阿里加速器配置成功!!"
        else
            echo "docker-ce-${o}阿里加速器配置失败!!"
            exit 2
        fi
		# 重启docker
		systemctl daemon-reload
		systemctl restart docker
		if [ $? -eq 0 ]; then
            echo "docker-ce-${o}重启成功!!"
        else
            echo "docker-ce-${o}重启失败!!"
            exit 2
        fi
	else
	    echo "继续使用原版本,退出执行脚本!!" && exit 1
	fi
else
	echo "docker未安装,将继续执行安装脚本!!"
        echo "正在搜索可安装的 Docker 版本,请耐心等待....."

	# step 1: 安装必要的一些系统工具
	yum install -y yum-utils device-mapper-persistent-data lvm2 &> /dev/null
	# Step 2: 添加软件源信息
	yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo &> /dev/null
	# Step 3
	sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
	# Step 4: 更新并安装Docker-CE
   echo "正在建立docker-ce缓存"
	yum makecache
	zz=`yum list docker-ce.x86_64 --showduplicates | sort -r |grep docker-ce.x86_64 |awk '{print $2}'`
	for rr in $zz
    do
        echo "可选安装版本:$rr"
    done
    read -p "选择要安装的docker版本[如18.06.3.ce-3.el7]: " o
    echo ""
    echo "正在安装 docker-ce-$o,请耐心等待....."

    yum -y install docker-ce-$o &> /dev/null
    if [ $? -eq 0 ]; then
        echo "docker-ce-${o}安装成功!!"
    else
        echo "docker-ce-${o}安装失败!!"
        exit 2
    fi
    # 启动docker
    systemctl enable docker.service
    systemctl start docker.service
    if [ $? -eq 0 ]; then
		echo "docker-ce-${o}启动成功!!"
	else
		echo "docker-ce-${o}启动失败!!"
		exit 2
	fi
    # 配置加速器
    touch /etc/docker/daemon.json
tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://q1rw9tzz.mirror.aliyuncs.com"]
}
EOF
	if [ $? -eq 0 ]; then
		echo "docker-ce-${o}阿里加速器配置成功!!"
	else
		echo "docker-ce-${o}阿里加速器配置失败!!"
		exit 2
	fi
	# 重启docker
	systemctl daemon-reload
	systemctl restart docker
	if [ $? -eq 0 ]; then
		echo "docker-ce-${o}重启成功!!"
	else
		echo "docker-ce-${o}重启失败!!"
        exit 2
	fi
fi
# 如脚本名为docker_install.sh
sudo chmod +x docker_install.sh
./docker_install.sh

执行结果如下图所示。

image-20220801113214240

2.2 Docker Swarm 集群部署

其实 Docker Swarm 集群很简单,一条命令即可完成。

1、初始化 Linux

# 修改主机名
hostnamectl set-hostname Docker_Swarm_Manager
hostnamectl set-hostname Docker_Swarm_Work1
hostnamectl set-hostname Docker_Swarm_Work2

# 互作本地解析(三台均执行)
192.168.56.161 Docker_Swarm_Manager
192.168.56.162 Docker_Swarm_Work1
192.168.56.163 Docker_Swarm_Work2

2、初始化 Manager

在其中一台 Manager 节点执行(其他 Manager 节点按命令并入即可)

Manager 节点也可作为 work 节点使用。

# 初始化swarm集群,创建主管理节点
docker swarm init \
--advertise-addr 192.168.56.161:2377 \
--listen-addr 192.168.56.161:2377

# 参数说明
--advertise-addr:其他节点并入集群的入口地址
--listen-addr:该参数是默认的,如果不添加也是默认IP:2377,它的作用主要是安全问题(如你只希望您的 swarm 管理界面只能在管理网络上访问)

如果已经执行过该命令了,但是又忘记了相关Token信息,可以重新执行

# 先删除之前生成的相关信息
docker swarm leave --force

# 再次初始化新的Manager节点
docker swarm init \
--advertise-addr 192.168.56.161:2377 \
--listen-addr 192.168.56.161:2377

image-20220801120658124

image-20220801120754165

3、节点如何并入集群

  • Manager 节点并入集群

    # 首先在已有的Manager管理节点上生成其他Manager节点并入集群的IP+Token信息
    docker swarm join-token manager
    

    image-20220801120840144

    # 如果我有其他想要成为manager的docker节点
    # 首先在已有的manager节点上生成相关接入信息
    # 执行生成的命令即可加入集群并成为manager角色
    docker swarm join --token SWMTKN-1-17fmka1c0l9e6hr66i5ksrl6wreworhx2gwte0644yaij5agvh-4z5yn1vvlvjzghhg1k36bg81k 192.168.56.161:2377
    
  • Work 节点并入集群

    # 首先在已有的Manager管理节点上生成其他Manager节点并入集群的IP+Token信息
    docker swarm join-token worker
    

    image-20220801121406755

    # 如果我有其他想要加入Docker-Swarm集群的work节点
    # 首先在已有的manager节点上生成相关接入信息
    # 执行生成的命令即可加入集群并成为work角色
    docker swarm join --token SWMTKN-1-17fmka1c0l9e6hr66i5ksrl6wreworhx2gwte0644yaij5agvh-cbfo8i5ubyp4j80y9sqzam9tj 192.168.56.161:2377
    

以上两种角色的 Token 信息都生成完毕后,就可以将对应的服务器加入集群了

# work1
docker swarm join --token SWMTKN-1-17fmka1c0l9e6hr66i5ksrl6wreworhx2gwte0644yaij5agvh-cbfo8i5ubyp4j80y9sqzam9tj 192.168.56.161:2377

# work2
docker swarm join --token SWMTKN-1-17fmka1c0l9e6hr66i5ksrl6wreworhx2gwte0644yaij5agvh-cbfo8i5ubyp4j80y9sqzam9tj 192.168.56.161:2377

image-20220801121743804

4、查看 Docker Swarm 集群状态

image-20220801121931133

5、集群可用性验证

官方案例:Docker Swarm 集群上部署服务

# 部署应用
docker service create --replicas 1 --name helloworld alpine ping docker.com

# 查看部署情况
docker service ls

# 参数说明
# --name helloworld:指定服务名为helloworld
# alpine:为指定的镜像名
# ping docker.com:启动服务后执行的命令

image-20220801122924054

image-20220801123016151

至此 Docker Swarm 集群部署完毕!

三、集群基本用法

根据上面的官方案例来演示。

除非特别说明,否则所有操作均在管理节点执行(操作)。

3.1 运行服务

# 部署应用
docker service create --replicas 1 --name helloworld alpine ping docker.com

# 查看部署情况
docker service ls

# 参数说明
# --replicas 1:指定运行的服务数(也就是你要启动几个容器)
# --name helloworld:指定服务名为helloworld
# alpine:为指定的镜像名
# ping docker.com:启动服务后执行的命令

3.2 查看服务详情

1、简要信息

docker service inspect --pretty helloworld

image-20220801123156070

2、详细信息

docker service inspect helloworld

image-20220801123224388

管理节点会通过相关调度,在集群节点中启动对应的容器,容器名以集群启动的服务名为基础随机生成。

image-20220801144334563

3.3 扩展运行的服务

上面的测试实例为1,没有副本数,我们可以在集群中动态扩展副本数。

# 语法
docker service scale <SERVICE-ID/SERVICE-NAME>=<NUMBER-OF-TASKS>

# 案例
docker service scale helloworld=2

查看 swarm 集群运行服务的基本状态

image-20220801145037815

查看 swarm 集群运行服务在哪个节点上运行(在哪个节点运行,就在哪个节点启动容器)

image-20220801145215249

3.4 删除运行的服务

1、删除

docker service rm helloworld

2、验证是否删除成功

docker service ls

image-20220801150310996

3.5 服务滚动升级

1、升级步骤(假设运行了三个服务)

  • 先停止第一个服务;
  • 为已停止的服务进行升级;
  • 执行更新任务(如镜像版本升级);
  • 若升级完成后返回 RUNNING,则进入自定义的等待时间,等待时间完成后开始下一个服务的升级;
  • 若更新期间(不管何时),更新返回结果为 FAILED,则停止更新。

接下来开始实际案例演示

2、运行 redis 服务

# 集群启动一个3.0.6版本的redis服务
docker service create \
  --replicas 3 \
  --name redis \
  --update-delay 10s \
  redis:3.0.6
  
# 参数说明:
# --replicas 3:服务数为3
# --name redis:运行的服务名(自定义)
# --update-delay 10s:更新完成后等待下一个服务跟新的时间(也就是服务间更的间隔时间)
# redis:3.0.6:指定镜像名

image-20220801153827618

3、redis 版本更新

Manager 根据 UpdateConfig 策略将更新应用到节点

# 将redis镜像版本更新至3.0.7(管理节点执行)
docker service update --image redis:3.0.7 redis

image-20220801154553547

下图是官方更新成功与失败的案例截图:

image-20220801154427672

# 更新失败后,可尝试重新更新
docker service update redis

看看滚动更新效果

image-20220801154926148

3.6 节点脱离集群

以下方法二选一即可

1、节点脱离集群

工作节点自己主动脱离集群

# 使work1脱离集群
[root@docker_swarm_work1 opt]# docker swarm leave

# 强制脱离
[root@docker_swarm_work1 opt]# docker swarm leave --force

查看集群状态

image-20220801143327408

2、管理节点移除节点

管理节点强制使节点脱离集群

# 从管理节点中移除以停止或失效的节点
# 移除管理节点:
docker node demote <节点ID/HOSTNAME>
# 移除work节点:
docker node rm -f <节点ID/HOSTNAME>

通过管理节点使其他节点脱离集群时,如果被移除的这个集群想再次并入集群时,需要做如下操作

# 在要并入集群的节点(被管理节点移除的节点)操作
docker swarm leave --force
# 开始加入集群
docker swarm join --token SWMTKN-1-17fmka1c0l9e6hr66i5ksrl6wreworhx2gwte0644yaij5agvh-cbfo8i5ubyp4j80y9sqzam9tj 192.168.56.161:2377

3.7 节点资源耗尽

如果集群中某节点资源耗尽,那运行在该节点的服务将会发生什么?停止或是转移,答案是会通过管理节点进行相关调度将资源耗尽的节点上的服务进行转移,使其保持正常提供服务。

1、如下,我运行了三个服务

每个节点都起了一个 redis 服务

image-20220801160542727

2、故意将 work1 节点置为资源耗尽状态

docker node update --availability drain docker_swarm_work1

3、查看节点是否可用

docker node inspect --pretty docker_swarm_work1

image-20220801160908128

4、看其上的 redis 服务是否转移了

# 已经转移到管理节点上了
docker service ps redis

image-20220801161011290

5、恢复至可用状态

docker node update --availability active docker_swarm_work1

在看看节点可用状态

image-20220801161244932

但是要注意,恢复后,原来运行的服务不会因为它再次可用而还原到原来的状态。但是此时该节点可以接收管理节点的正常资源调度。

四、集群网络模式

集群网络模式与 docker 网络类型类似,比如桥接、Host等网络模式。一个服务部署于 docker swarm 集群中后,那客户如何才能访问你部署的服务呢?根据我们所学的 Docker 相关知识,我们一般会做端口的映射。因此 docker swarm 集群也是这种思想。那它具体是如何实现的呢?

所有节点都使用一个网络入口(模式),该网络入口(模式)上的每个节点都可以在已映射的端口上接收 docker swarm 集群中任何节点上相关服务的连接,即便该节点没有运行任何服务。

要使用该网络模式之前,需要在 swarm 集群节点间打通以下端口(所以注意防火墙 IP 白名单问题):

  • 7946:容器网络发现端口;
  • 4789:容器网络入口端口。

如下图,尽管我的 node3 节点没有运行任何服务,但我依然可以通过该节点 IP+Port 来实现服务访问。

ingress-routing-mesh

4.1 服务端口

默认情况下,当您发布端口时,它默认就是 TCP 端口。当然,你可以指定 TCP 或 UDP 来发布,当您同时发布 TCP 和 UDP 端口时,如果你省略了协议说明符,则该端口将作为 TCP 端口来发布。

image-20220801165227555

4.1.1 TCP

1、语法

docker service create \
  --name <SERVICE-NAME> \
  --publish published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
  <IMAGE>
  
# 参数说明
# --publish:指定(映射)要发布的端口号
# published:你要实际访问的外部端口(可自定义,不要和系统服务现有端口冲突即可)
# targetL:你swarm集群运行的服务(容器)的真实(内部)端口

# 短语法格式
docker service create \
  --name <SERVICE-NAME> \
  -p <PUBLISHED-PORT>:<CONTAINER-PORT> \
  <IMAGE>

2、案例

docker service create \
  --name my-web \
  --publish published=8080,target=80 \
  --replicas 2 \
  nginx

image-20220801165353092

3、访问验证

上图可看出,这两个服务分别部署在了 work1、work2 上了,管理节点上没有被调度使用,现在就来验证管理是否能正常访问集群中的服务。

image-20220801165529583

所以得出结论,在集群中部署的服务,不管是单节点服务,还是集群,在整个集群节点中都会映射对应的发布端口,所在集群部署服务时,确保所有集群节点的端口与你现在部署的服务端口不发生冲突。

4、如何改变现有服务的发布端口

上面我定义发布端口为 8080,现在需要改为 8181,可做如下修改

# 语法
docker service update \
  --publish-add published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
  <SERVICE>
  
# 实例
docker service update \
  --publish-add published=8181,target=80 \
  my-web

如下图,同样是滚动更新的。

image-20220801172328081

5、如何查看服务的发布端口?

image-20220801172550912

4.1.2 UDP

1、语法

docker service create --name <SERVICE-NAME> \
  --publish published=<PUBLISHED-PORT>,target=<CONTAINER-PORT>,protocol=udp \
  <IMAGE>
  
# 参数说明
# --publish:指定(映射)要发布的端口号
# published:你要实际访问的外部端口(可自定义,不要和系统服务现有端口冲突即可)
# targetL:你swarm集群运行的服务(容器)的真实(内部)端口

# 短语法格式
docker service create \
  --name <SERVICE-NAME> \
  -p <PUBLISHED-PORT>:<CONTAINER-PORT>/udp \
  <IMAGE>

2、案例

# 长语法
docker service create --name dns-cache \
  --publish published=53,target=53,protocol=udp \
  dns-cache

# 短语法
docker service create --name dns-cache \
  -p 53:53/udp \
  dns-cache
4.1.3 TCP 及 UDP

1、语法

docker service create --name dns-cache \
  --publish published=53,target=53 \
  --publish published=53,target=53,protocol=udp \
  dns-cache

# 参数说明
# --publish:指定(映射)要发布的端口号
# published:你要实际访问的外部端口(可自定义,不要和系统服务现有端口冲突即可)
# targetL:你swarm集群运行的服务(容器)的真实(内部)端口

# 短语法格式
docker service create --name <SERVICE-NAME> \
  -p <PUBLISHED-PORT>:<CONTAINER-PORT> \
  -p <PUBLISHED-PORT>:<CONTAINER-PORT>/udp \
  <IMAGE>

2、案例

# 长语法
docker service create --name dns-cache \
  --publish published=53,target=53 \
  --publish published=53,target=53,protocol=udp \
  dns-cache

# 短语法
docker service create --name dns-cache \
  -p 53:53 \
  -p 53:53/udp \
  dns-cache

4.2 Host 网络

如不想经过路由,而直接访问集群服务,可采用 Host 模式,在部署服务时指定。其实这就是 Docker 的 Host 网络模式,共享宿主机网络。

docker service create --name dns-cache \
  --publish published=53,target=53,protocol=udp,mode=host \
  --mode global \
  dns-cache

至此,基于 Linux 的 Docker Swarm 集群部署及应用告一段落,这种简单的容器编排最终还是会转向 K8s,但是我们也要根据实际场景来部署,别什么一来就上 K8s,也许你目前的服务数量都不够 K8s 的基本生产部署条件。因此,我们是逐步转向 K8s 集群的,不管任何技术,它都有个过渡期。后续会继续分享 Docker Swarm 集群详细的工作原理及网络模式。

FAQ

注意关闭相关主机防火墙,或者你开放了防火墙后,注意添加相关 IP Port 白名单、安全组等。

<点击跳转至开头>

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云计算-Security

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值