欢迎访问我的博客,你的支持,是我最大的动力!

企业级容器集群构建(二)SwarmKit解决方案

Docker 小马奔腾 3324℃ 评论
目录:
[显示]

《容器即服务.从零构建企业级容器集群》林帆2018.4 笔记

SwarmKit集群解决方案

SwarmKit是伴随docker1.12成名的,现已集成到docker中,其前身是Swarm项目

swarm、swarmkit、swarm mode之间的关系

使用SwarmKit

SwarmKit的故障节点处理依靠Etcd项目的Raft模块,将集群中节点分为三种角色:Leader、Follower、Candidate

集群中只有一个Leader,其他节点都是Follower,Leader定时向Follower发送心跳包保持其地位;当Follower节点在一定周期没有收到来自Leader的心跳时,发起Leader选举,此时集群中所有正常节点都将进入Candidate状态,有节点在投票中得到总数一半以上的票数时,将成为Leader。每成功选举一次,新Leader的Term任届值会比之前的增加1。当分裂又重新全并时,可能会出现多于一个Leader,此时Term值更高的节点成为真正的Leader。

SwarmKit提供服务调度、服务路由、负载均衡、故障处理、在线升级等能力

SwarmKit依赖Raft协议保持集群状态高可用,Leader节点对数据进行修改时,都需要告知所有Follower节点,并在获得半数以上Follower确认后,才能将数据持久化。这样如果集群节点数量过大,确认消息的成本会成倍增长,所以又将节点划分为Manager和Worker两种角色,这两类节点都参与服务的调度,但只有Manager节点真正保存集群信息并参与Raft选举。[注意区分集群角色:Manager/Worker由人工指定和Raft集群角色Leader/Follower/Candidate自动指定]

创建SwarmKit集群

项目地址:https://github.com/docker/swarmkit [golang]

SwarmKit没有编译过的二进制版本,通常用docker的swarm mode间接使用,当然,要直接使用,可以编译源代码

编译swarmkit

# 编译SwarmKit
yum install git
git clone https://github.com/docker/swarmkit.git
cd swarmkit/
git branch -a
git checkout -b remotes/origin/bump_v1.13.1
# 使用golang:1.8镜像来构建
# SELINUX=disabled
yum install docker
echo '{"registry-mirrors": ["https://registry.docker-cn.com"]}' > /etc/docker/daemon.json
systemctl start docker
docker pull golang:1.8
docker run --rm -it -v pwd/swarmkit:/go/src/github.com/docker/swarmkit \
-w /go/src/github.com/docker/swarmkit/ golang:1.8 make binaries
# 编译不成功,报错如下
# manager/allocator/cnmallocator/drivers_ipam.go:18: undefined: strings.Builder
# direct.mk:100: recipe for target 'bin/swarmd' failed
# 直接拿别人编译好的 [v1.12.0-1531-g79381d0]
docker pull appcelerator/swarmkit
# find / -name swarmctl 在镜像中查找文件
mkdir -p /root/bin
cp /var/lib/docker/overlay2/c93d16d15dd457094d771093c1fd65d2702a4bc9f12fc3dc5a2d0e27a8674252/diff/bin/* /root/bin
# 添加到系统PATH目录中
cp /root/bin/* /usr/local/bin/

使用swarmkit

swarmd负责管理和维护集群的后台进程
swarmctl是用户进行集群交互式操作的工具
不带参数运行swarmd将用默认配置创建一个集群,并将当前节点作为集群第一个manager节点
默认配置会用当前目录存放swarmkit运行中产生的各种数据文件,所以一般带参数运行swarmd

运行swarmkit

swarmd --state-dir /tmp/node-mgmt-01 --listen-control-api /tmp/mgmt-01.sock --hostname mgmt-01 >/tmp/mgmt-01.log 2>&1 &
#swarmd会监听4242端口
查看集群状态
#使用--socket或者设置SWARM_SOCKET环境变量指定socket文件位置
#export SWARM_SOCKET=/tmp/mgmt-01.sock
#swarmctl node ls --socket=/tmp/mgmt-01.sock
swarmctl node ls
#添加新节点到集群需要当前manager节点ip和集群join token
#join token区分worker和manager
#查看join token
swarmctl cluster inspect default

添加节点

每个节点都需要启动swarmd,添加两个worker节点[添加manager节点会出错]
MANAGER_IP=192.168.10.21
JOIN_TOKENS=SWMTKN-1-3eucrdor4lpsmeln2k51vynuejm4nibzsj057ho7kenjnslth1-34f6yk7ekfsfe7isfan9iew1o
swarmd --state-dir /tmp/node-work-01 --hostname work-02 --join-addr ${MANAGER_IP}:4242 --join-token ${JOIN_TOKENS} >/tmp/work-02.log 2>&1 &
swarmd --state-dir /tmp/node-work-01 --hostname work-03 --join-addr ${MANAGER_IP}:4242 --join-token ${JOIN_TOKENS} >/tmp/work-03.log 2>&1 &

swarmctl节点命令

swarmctl node promote 节点id/名称  #将节点提升为manager
swarmctl node demote 节点id/名称  #将节点降级为worker
swarmctl node drain 节点id/名称  #将节点停机 若此节点上有容器,将自动迁移到其他节点上
swarmctl node activate 节点id/名称  #将节点恢复为正常运行状态

swarmctl集群上运行服务

swarmkit集群中,默认所有节点都会参与服务调度,包括manager节点

#创建服务
swarmctl service create --name nginx --image nginx:1.11.1-alpine
#查看服务
swarmctl service ls
#查看服务详细信息
swarmctl service inspect nginx
#更新服务属性
swarmctl service update nginx --replicas 6  #增加副本数
swarmctl service update nginx --replicas 3  #减少副本数
swarmctl service update --help #查看可更改的参数列表
##--image参数用来替换容器镜像,实际上可用于升级服务版本
swarmctl service update nginx --image nginx:1.11.3-alpine
swarmctl service update nginx --image nginx:1.11.3-alpine --update-parallelism 2 --update-delay 4s
##每隔四秒升级两个容器

其他功能

功能:node、service、task、network、cluster、secret
task是最小管理单元,一个task实际对应一个容器
secret是对用户密钥信息的封装
network创建和管理docker网络中scope值为swarm的那部分网络
swarmctl network ls
docker swarm mode

swarm mode弱化了task的概念并增强了对服务编排的支持

集群创建与销毁

#初始化集群
docker swarm init
##会生成worker加入命令和manager加入命令
#加入集群,身份由token区分
docker swarm join \
--token SWMTKN-1-1gf5gfkpf052yzbb02hw5t4z09ucmhtokhphgks211f4xamf3h-18n5d649b6ykvomedei3sbrpa \
192.168.10.21:2377
##端口2377集群管理
##端口4789 udp 容器间流量的vxlan端口
##端口7946 tcp/udp docker守护进程控制端口
#打印加入集群命令
docker swarm join-token worker
docker swarm join-token manager
##token是加入集群的凭证,应妥善保管token,特别是manager的token
##若token泄露可使用token轮换
docker swarm join-token --rotate manager
##会使过去的token失效,只影响新加入的节点,已经在集群中的节点不受token轮换影响
##集群安全隐患除了泄露token还在于任何连接到manager的用户都能直接操纵集群,为此docker提供集群上锁机制
#为集群上锁
docker swarm update --autolock=true
##解锁docker swarm unlock 并使用密钥SWMKEY-1-vgN3p/d+C3hpxbDUwbNQ48MHwaqxcduCpWejAF46jnk
##manager节点的docker服务重启后,才会进入锁定状态(锁了Raft数据文件),此时用户所有与集群相关的操作都被拒绝
systemctl restart docker
docker node ls
docker swarm unlock
#取消锁定
docker swarm update --autolock=false
##若忘记密钥,在没有被锁定的节点,执行docker swarm unlock-key重新显示密钥
##若密钥泄露,docker swarm unlock-key --rotate 重新生成新密钥
#让一个节点退出集群
docker swarm leave
docker swarm leave --force #管理员节点离开
docker swarm init --force-new-cluster #管理员离开后需要执行该操作以重写配置,原集群中节点需重新加入
docker node rm gyu1ccjud3xdnhme2w4q6b7vw #从集群中移出状态为down的节点
##节点离开的几种情况
1、节点是worker,直接退出集群,集群会自动将该节点上所有服务迁移到其他节点上继续运行,状态为Down,需手动移除
2、节点是manager,且为leader,退出失败,可使用--force强制退出
3、节点是manager,且为follower,集群中有三个及以上manager,则先自动降级为worker,再正常退出集群,状态为Down,需手动移除
4、节点是manager,且为follower,集群中只有两个manager,退出失败,可使用--force强制退出
5、集群中所有节点都退出后,集群被销毁

节点管理

#查看节点信息
docker node ls
##status健康性 availability可用性
#查看某一节点信息
docker node inspect b0a99mdu0mg7r0fzgr686s8i4
docker node inspect swarmkit3
#查看task状态
docker node ps
#节点类型转换
worker -> manager
docker node promote 0cs2rai2tzdklf8zgchrldjki
docker node promote swarmkit2
docker node update swarmkit2 --role manager
worker <- manager
docker node demote 0cs2rai2tzdklf8zgchrldjki
docker node demote swarmkit2
docker node update swarmkit2 --role worker
#节点调度
docker node update <node-id> --availability <actie|pause|drain>
docker node update swarmkit2 --availability pause
##active 正常使用
##pause 不参与新task调度 已经在该节点的task继续运行
##drain  维护模式 所有task迁移到其他节点
#移除状态为down的节点
docker node rm <node-id>

服务管理

task对应一个容器
service是对一个或多个相同容器副本的抽象,可以根据负载进行扩缩,同时具有负载均衡功能,为分散的容器提供统一入口
stack实现服务编排,将多个不同的service关联在一起,进行整体部署和升级,对外体现为由多种容器组合成的复杂系统

#服务查看
docker service ls
#创建服务
docker service create --help
docker service create --name web --publish 8080:80 --replicas=3 nginx:1.11.1-alpine
##创建服务并映射容器内80端口到客户机8080端口,所有节点都会映射8080端口,不管该节点是否分配有容器
##服务将注册到集群内的DNS,与该容器处于同一网络的其他容器能直接通过服务名称来访问此服务
##Linux IPVS管理的内核四层负载均衡器,轮询
#查看服务详情
docker service inspect web
#删除服务
docker service rm web
#更新服务属性
docker service update ...
docker service update web --publish-add 8000:80
#一次查看所有task状态信息
docker service ls -q | xargs -n 1 docker service ps
docker service ls -q | xargs -n1 docker service ps
#查看服务日志
docker service logs whoami
#修改服务容器副本数
docker service scale curl=2
docker service update crul --replicas 1
#滚动升级 替换镜像,对无状态的容器,利用负载均衡器实现
docker service update web --image nginx:1.11.5-alpine --update-parallelism 1 --update-delay 3s
##查看watch 'docker service ps web | grep Running'
##滚动升级过程中原来的容器并不删除而是关闭,提供恢复的可能性

实验:同一容器网络内可用服务名访问服务及负载均衡

#创建独立容器overlay网络
docker network create demo --driver overlay
docker network ls
#创建服务whoami 监听8000端口 当有请求访问时 会返回容器ID
docker service create --name whoami --replicas 3 --network demo --publish 8000:8000 flin/whoami
#创建访问被测试服务的容器,与前者在同一网络
docker service create --name curl --network demo flin/curl
#查看某服务运行在哪个节点
docker service ps curl
docker ps|grep curl|awk '{print $1}'
#在容器内使用服务名访问服务
docker exec 09e2e391ac3a curl -s whoami:8000

创建服务时常用参数

--port,暴露服务端口,--publish 8080:80等同于--port mode=ingress,target=80,published=8080,protocol=tcp
--mount,挂载本地目录,--mount type=volume,source=data_vol_01,target=/var/data,volume-driver=flocker 因为在服务自动迁移时,挂载目录可能会丢失,因此通常只挂载特定系统目录或是nfs、ceph存储的网络磁盘分区(配置Flocker或Convoy等工具更佳)
--mode,值有global、replicated(默认),影响--replicas参数,为global时,会在每个节点上运行一个副本,适用于部署监控和基础设施类服务,每个新节点进入集群后都会自动创建一个副本
--restart-condition,自动重启,默认为any,总是重启;none,不自动重启;on-failure,容器退出且返回值不为0时重启
--constraint,限制服务的容器可以被调度的节点,可根据节点ID/主机名/角色/标签进行选择
##为节点添加标签
docker node update swarmkit2 --label-add zone=cn
docker service create --constraint node.labels.zone==cn ...
服务编排compose

compose是docker的服务编排工具

安装

curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

单机使用

docker-compose.yml是compose默认的编排规则描述文件名

#应用yaml
docker-compose up -d
#测试
curl localhost:5000
#批量停止容器
docker-compose stop
#删除整个服务 包括容器、网络、存储等资源
docker-compose down

docker-compose命令与docker很相似,只是将范围扩大到编排文件所描述的整个服务组

docker-compose up 启动会在前台运行,并实时打印运行日志到控制台,-d参数可以在后台运行

yaml文件说明

docker-compose文件顶级属性仅有:version、services、volumes、networks、configs、secrets。其中configs和secrets不能用于单机

官方文档https://docs.docker.com/compose/compose-file

1、版本
version描述当前编排文件语法版本,1 -> 3.7
2、服务
services包含镜像信息、容器信息、副本数量、对网络/磁盘/密文的引用
第二层级的属性是服务名称
对镜像的描述可使用build或image两种语法,build表示从dockerfile开始构建,需指定构建的工作目录和dockerfile文件名称,如

deploy.replicas描述容器副本数量,同级别的属性还有滚动升级参数、重启参数、资源配额限制、部署位置约束等,deploy属性仅用于集群,如

服务的容器可以使用端口、网络、存储、外置配置和密文等资源,但不包括对这些资源本身的描述,如

此外,常用属性还有指定容器启动顺序关系的depends_on、覆写容器入口命令的command、配置环境变量的environment、容器健康检查的healthcheck等
3、存储卷
volumes是对存储卷进行详细描述的地方,主要包含存储卷类型和参数,如

external为false表示存储卷由compose管理,会自动创建和删除;为true时,用户预先创建存储卷并自行管理其生命周期
4、网络
network对服务中使用到的网络进行详细描述,主要包含网络类型和参数,如

网络类型可以是bridge或overlay,但overlay仅用于集群。external为false由compose管理,会自动创建和删除;为true则用户自己预先创建网络,并自行管理网络生命周期
5、外置配置
configs对服务中使用到的外置配置进行详细描述,仅对集群下的编排有效

external表示外置配置生命周期是否由compose统一管理
6、密文
secrets对服务中使用到的密文进行详细描述,只对集群下的编排有效,如

可以指定yaml文件:
docker-compose -f path/to/my-compose-file.yml up
还可以指定多个yaml文件,compose会将其合并为一个编排文件来执行
docker-compose -f docker-compose.yml -f docker-compose-dev.yml up
若yaml文件内容发生了变化,可以再次执行
docker-compose up -d
compose会自动调整和重启相关容器,使得运行的服务与描述保护一致,无须手动重启或重建整个服务组

集群编排

集群服务通常使用overlay类型的网络,不支持--net=host模式的容器,不支持挂载本地设备,增加了对外置配置和密文的支持

swarm集群中,通过编排方式部署到集群的一组服务叫应用栈stack

#运行
docker stack deploy -c docker-compose.yml app
#查看
docker stack ls
#显示stack中的服务
docker stack services app
docker service ls
#显示stack中的容器
docker stack ps app
#访问服务
curl 127.0.0.1:5000   #curl localhost:5000不正确,不清楚原因
#升级服务先修改docker-compose.yml文件,如将flin/page-hit-counter:v1替换为flin/page-hit-counter:v2
#让配置生效
docker stack deploy -c docker-compose.yml app
##会将旧的容器shutdown但并不删除
##升级过程中,只有涉及的容器会重创,未发生变化的容器不会连带重启
#删除应用栈
docker stack rm app

外置配置和密文管理

docker config create 创建需要存储在集群 的配置文件
docker config ls 查看当前集群中所有保存过的外置配置列表
docker config inspect 查看指定配置文件的详细属性
docker config rm 删除指定外置配置

示例:

#创建一个配置 docker 1.13.1中没有docker config命令
cat <<EOF | docker config create demo-config -
{
"name":"demo"
}
EOF
#使用--config将外置挂载到容器
docker service create --detach --replicas 1 --name nginx --config demo-config nginx:alpine
#外置配置默认挂载容器根目录
docker service ps nginx
docker exec -it <容器id> cat /demo-config
#动态修改挂载的外置配置,如将它移除
docker service update --detach --config-rm demo-config nginx
#再检查 发现已经没有了
docker exec -it <容器id> cat /demo-config
##此操作实际上创建了新的容器,容器id会发生变化,同时隐含服务重启的操作

挂载时可以指定目标:
--config src=demo-config-v1,target="/etc/demo-config"
更新时可同时指定移除和添加,实现配置内容替换
--config-rm demo-config-v1 --config-add source=demo-config-v2,target=/etc/demo-config

密文配置
密文在swarm中的存储和在容器网络中传输都是以加密形式存在的,只在目标节点被解密到内存中,然后从内存映射到容器里
单个密文限制在500KB内
密文最终会挂载成容器内/run/secrets/目录下与密文对象同名的文件
docker secret create 创建存储在集群的密文
docker secret ls  显示保存过的密文列表
docker secret inspect 查看指定密文的详细属性
docker secret rm 删除指定密文

docker 17.06开始,密码文位置可以随意指定,如
--secret source=demo-password,target=/opt/passwd
动态更换密文
--secret-rm demo-password --secret-add source=demo-password-v2,target=/opt/passwd

swarm mode图形界面

crane:https://github.com/dataman-cloud/crane

dockerfly:htps://github.com/helyho/dockerfly

portainer:https://github.com/portainer/portainer 推荐 活跃

portainer文档:
部署:https://portainer.readthedocs.io/en/latest/deployment.html
文档:https://portainer.readthedocs.io/en/stable/

下载:https://github.com/portainer/portainer/releases/download/1.19.2/portainer-1.19.2-linux-amd64.tar.gz

portainer前端界面采用angular框架,代码结构和用户体验优雅,采用本地文件存储服务状态,部署时没有依赖,仅需要集群manager节点启动portainer容器即可使用

docker run -d \
--name portainer \
--restart always \
-p 9000:9000 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /opt/portainer:/data \
portainer/portainer

/data目录用来保存portainer状态数据,主要是用户组和集群连接信息等少量数据,界面展示的数据都是从集群实时获取的

docker service create \
--detach \
--name portainer \
--publish 9000:9000 \
--constraint 'node.role  == manager' \
--mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
--mount type=bind,src=/opt/portainer,dst=/data \
portainer/portainer

portainer镜像很小,只有58.7MB,除可以管理swarm,也可以管理单节点docker

portainer可以管理多个集群,可以可视化创建网络、存储、容器、服务等各种资源对象

转载请注明:轻风博客 » 企业级容器集群构建(二)SwarmKit解决方案

喜欢 (0)or分享 (0)