sealer,“集群”版本的 Docker,交付复杂度的终结者
背景
随着时代的发展,单机上跑的单体应用已经越来越少了,分布式应用几乎已经无处不在。Docker 很好的对单机应用进行了镜像化的封装,实现在单机上 Build Ship Run, 从此单机上应用的运行没有什么是一个 docker run 解决不了的。
docker 对比 rpm 之类的工具显然一致性好很多,原因是 docker 把 rootfs 同样封装到了镜像之中,也就是所有的依赖都在镜像中。
再看集群和分布式应用,以前 IaaS 主导的云计算只对资源进行了抽象,显然一个操作系统是承上启下的作用,向上需要有很好的应用管理能力,kubernetes 很符合这一定义。
所以现在假设 kubernetes 是管理所有服务器的操作系统,在这个前提下我们要设计一个 “集群” 版本的 Docker,这就是我们今天的主角 sealer。
目前 sealer 也捐献给了 CNCF 基金会,项目地址:https://github.com/sealerio/sealer
(点击文末阅读原文可直接跳转哦~)
快速开始
联想一下 Docker 我们需要启动一个 centos 容器:
docker run centos
所以要用 sealer 启动一个 kubernetes 集群,只需要:
sealer run kubernetes:v1.19.8 \
--masters 192.168.0.2,192.168.0.3,192.168.0.4 \
--nodes 192.168.0.5,192.168.0.6,192.168.0.7 --passwd xxx
这样一个六节点的集群就起来了,当然 sealer 同样支持单节点。
同理,我们可以运行分布式软件如:
sealer run mysql-cluster:8.0
sealer run redis:5.0
各种分布式软件一键安装交付。
交付的痛点
想象没有 sealer 交付的故事是什么样的?假设你已经使用了 kubernetes helm 这些工具,当然没使用的只会比以下步骤更痛苦。
找一个能在离线环境中安装 kubernetes 本身的工具 加载你事先打包好的所有 docker 镜像 启动一个私有镜像仓库 把所有镜像推送到私有镜像仓库中 修改编排文件中镜像仓库地址 执行所有的 helm chart
而使用 sealer 交付故事是:
加载集群镜像 sealer run [集群镜像]
如果的交付文档很长,整个交付面向过程,那就很适合使用 sealer,可以在整个集群一致性上保证交付成功。
那么如何去构建一个自定义的集群镜像呢?
Build 集群镜像
sealer 运行分布式应用很简单,同样要去自定义一个集群镜像也需要很简单,这里采用与 Docker 镜像几乎相同的方式进行构建。
这里以构建一个 dashboard 的集群镜像为例子:
编写一个类似 Dockerfile 的文件,我们叫 Kubefile
FROM kubernetes:v1.19.8
RUN wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml
CMD kubectl apply -f recommended.yaml
第一行 FROM kubernetes:v1.19.8
可以选择你想要的基础镜像。
RUN 指令只会在 Build 的时候执行,去下载 dashboard 的 yaml 文件。
CMD 指令会在集群启动后执行,所以这里并不关心用户使用什么编排工具,比如 sealer 可以很好的与 helm 搭配使用。
build
sealer build -t dashboard:latest .
这里 sealer 不仅只是把 RUN 命令执行了一下,还会去扫描里面包含的所有 docker 镜像并缓存到集群镜像中,这样启动的时候会直接从缓存的私有镜像仓库中去下载镜像。
Run
sealer run dashboard:latest --masters 192.168.0.2 --passwd xxx
kubectl get pod -A|grep dashboard
现在我们就可以运行这个集群镜像,sealer 会先拉起一个 kubernetes 集群,再在其上面部署 dashboard。
这里神奇的地方是虽然 dashboard 编排文件里面写的是 gcr 仓库的镜像地址,sealer 并不会从公网去拉取,而会检测私有镜像仓库是是否存在该镜像,有的话直接从私有镜像仓库中拉取。如此 即便在离线环境中也可以正常拉到镜像,而且整个过程什么也不需要修改。
Push
sealer push registry.cn-qingdao.aliyuncs.com/sealer-io/dashboard:latest
可以把刚才的集群镜像 push 到任意的 registry 中,比如 docker hub。
配置管理
看到上面你可能会感觉确实简单,但是功能好像不太满足,因为一次交付,几乎会有非常多的配置文件需要管理与调整,这在 sealer 里面如何处理?
sealer 对这块的设计也有充分考虑,答案是使用 Clusterfile。
Clusterfile 说白了是就告诉 sealer 启动整个集群需要的配置是怎样的。
apiVersion: sealer.cloud/v2
kind: Cluster
metadata:
name: default-kubernetes-cluster
spec:
image: kubernetes:v1.19.8
ssh:
passwd: xxx
hosts:
- ips: [ 192.168.0.2,192.168.0.3,192.168.0.4 ]
roles: [ master ]
- ips: [ 192.168.0.5 ]
roles: [ node ]
sealer apply -f Clusterfile
即可启动整个集群。
常见需求,比如想修改一个 podsubnet, sealer 支持 merge 所有 kubeadm 配置文件:
---
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
networking:
podSubnet: 100.64.0.0/10
你不需要把所有配置写全,只需要写你关心的字段,会自动合并到默认配置中。
业务配置使用更通用的做法:
---
apiVersion: sealer.aliyun.com/v1alpha1
kind: Config
metadata:
name: mysql-config
spec:
path: etc/mysql.yaml
data: |
mysql-user: root
mysql-passwd: xxx
data 里面的内容会覆盖镜像内部的 path, 指定的文件,同样支持是直接覆盖还是合并等一些策略,那么这里的内容就很适合是 helm values.
sealer 同样支持用环境变量管理少量配置:
apiVersion: sealer.cloud/v2
kind: Cluster
metadata:
name: my-cluster
spec:
image: kubernetes:v1.19.8
env:
docker-dir: /var/lib/docker
hosts:
- ips: [ 192.168.0.2 ]
roles: [ master ] # add role field to specify the node role
env: # overwrite some nodes has different env config
docker-dir: /data/docker
- ips: [ 192.168.0.3 ]
roles: [ node ]
镜像内部的脚本就可以直接使用 docker-dir 环境变量:
#!/bin/bash
echo $docker-dir
插件机制
插件可以帮助用户做一些之外的事情,比如更改主机名,升级内核,或者添加节点标签等……
主机名插件
如果你在 Clusterfile 后添加插件配置并应用它,sealer 将帮助你更改所有的主机名:
---
apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
name: hostname
spec:
type: HOSTNAME
data: |
192.168.0.2 master-0
192.168.0.3 master-1
192.168.0.4 master-2
192.168.0.5 node-0
192.168.0.6 node-1
192.168.0.7 node-2
Hostname Plugin 将各个节点在安装集群前修改为对应的主机名。
脚本插件
如果你在 Clusterfile 后添加 Shell 插件配置并应用它,sealer 将帮助你执行 shell 命令 (执行路径为镜像 Rootfs 目录):
---
apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
name: shell
spec:
type: SHELL
action: PostInstall
'on': node-role.kubernetes.io/master=
data: |
kubectl taint nodes node-role.kubernetes.io/master=:NoSchedule
action : [PreInit| PostInstall] # 指定执行shell的时机
在初始化之前执行命令 | action: PreInit
在添加节点之前执行命令 | action: PreJoin
在添加节点之后执行命令 | action: PostJoin
在执行Kubefile CMD之前 | action: PreGuest
在安装集群之后执行命令 | action: PostInstall
在清理集群前执行命令 | action: PreClean
在清理集群后执行命令 | action: PostClean
组合使用 | action: PreInit|PreJoin
on : #指定执行命令的机器
为空时默认在所有节点执行
在所有master节点上执行 | 'on': master
在所有node节点上执行 | 'on': node
在指定IP上执行 | 'on': 192.168.56.113,192.168.56.114,192.168.56.115,192.168.56.116
在有连续IP的机器上执行 | 'on': 192.168.56.113-192.168.56.116
在指定label节点上执行(action需为PostInstall或PreClean) | 'on': node-role.kubernetes.io/master=
data : #指定执行的shell命令
标签插件
如果你在 Clusterfile 后添加 label 插件配置并应用它,sealer 将帮助你添加 label:
apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
name: label
spec:
type: LABEL
action: PreGuest
data: |
192.168.0.2 ssd=true
192.168.0.3 ssd=true
192.168.0.4 ssd=true
192.168.0.5 ssd=false,hdd=true
192.168.0.6 ssd=false,hdd=true
192.168.0.7 ssd=false,hdd=true
节点 ip 与标签之前使用空格隔开,多个标签之间使用逗号隔开。
集群检测插件
由于服务器以及环境因素 (服务器磁盘性能差) 可能会导致 sealer 安装完 kubernetes 集群后,立即部署应用服务,出现部署失败的情况。cluster check 插件会等待 kubernetes 集群稳定后再部署应用服务。
apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
name: checkCluster
spec:
type: CLUSTERCHECK
action: PreGuest
污点插件
如果你在 Clusterfile 后添加 taint 插件配置并应用它,sealer 将帮助你添加污点和去污点:
apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
name: taint
spec:
type: TAINT
action: PreGuest
data: |
192.168.56.3 key1=value1:NoSchedule
192.168.56.4 key2=value2:NoSchedule-
192.168.56.3-192.168.56.7 key3:NoSchedule
192.168.56.3,192.168.56.4,192.168.56.5,192.168.56.6,192.168.56.7 key4:NoSchedule
192.168.56.3 key5=:NoSchedule
192.168.56.3 key6:NoSchedule-
192.168.56.4 key7:NoSchedule-
data 写法为
ips taint_argument
ips : 多个 ip 通过,
连接,连续 ip 写法为 首 ip - 末尾 ip taint_argument: 同 kubernetes 添加或去污点写法 (key=value:effect #effect 必须为:NoSchedule, PreferNoSchedule 或 NoExecute)。
插件使用步骤
Clusterfile 内容:
apiVersion: sealer.aliyun.com/v1alpha1
kind: Cluster
metadata:
name: my-cluster
spec:
image: registry.cn-qingdao.aliyuncs.com/sealer-io/kubernetes:v1.19.8
provider: BAREMETAL
ssh:
# ssh的私钥文件绝对路径,例如/root/.ssh/id_rsa
pk: xxx
# ssh的私钥文件密码,如果没有的话就设置为""
pkPasswd: xxx
# ssh登录用户
user: root
# ssh的登录密码,如果使用的密钥登录则无需设置
passwd: xxx
network:
podCIDR: 100.64.0.0/10
svcCIDR: 10.96.0.0/22
certSANS:
- aliyun-inc.com
- 10.0.0.2
masters:
ipList:
- 192.168.0.2
- 192.168.0.3
- 192.168.0.4
nodes:
ipList:
- 192.168.0.5
- 192.168.0.6
- 192.168.0.7
---
apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
name: hostname
spec:
type: HOSTNAME
data: |
192.168.0.2 master-0
192.168.0.3 master-1
192.168.0.4 master-2
192.168.0.5 node-0
192.168.0.6 node-1
192.168.0.7 node-2
---
apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
name: taint
spec:
type: SHELL
action: PostInstall
on: node-role.kubernetes.io/master=
data: |
kubectl taint nodes node-role.kubernetes.io/master=:NoSchedule
sealer apply -f Clusterfile #plugin仅在安装时执行,后续apply不生效。
执行上述命令后 hostname,shell plugin 将修改主机名并在成功安装集群后执行 shell 命令。
在 Kubefile 中定义默认插件
很多情况下在不使用 Clusterfile 的情况下也能使用插件,本质上 sealer 会先把 Clusterfile 中的插件配置先存储到 rootfs/plugins 目录,再去使用,所以我们可以在制作镜像时就定义好默认插件。
插件配置文件 shell.yaml:
apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
name: taint
spec:
type: SHELL
action: PostInstall
on: node-role.kubernetes.io/master=
data: |
kubectl get nodes
---
apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
name: SHELL
spec:
action: PostInstall
data: |
if type yum >/dev/null 2>&1;then
yum -y install iscsi-initiator-utils
systemctl enable iscsid
systemctl start iscsid
elif type apt-get >/dev/null 2>&1;then
apt-get update
apt-get -y install open-iscsi
systemctl enable iscsid
systemctl start iscsid
fi
Kubefile:
FROM kubernetes:v1.19.8
COPY shell.yaml plugin
构建一个包含安装 iscsi 的插件 (或更多插件) 的集群镜像:
sealer build -m lite -t kubernetes-iscsi:v1.19.8 .
通过镜像启动集群后插件也将被执行,而无需在 Clusterfile 中定义插件: sealer run kubernetes-iscsi:v1.19.8 -m x.x.x.x -p xxx
总结
以上对 sealer 的核心能力有了一个整体的介绍,目前 sealer 已经在多家企业中生产落地,阿里内部也有非常多的实践,sealer 未来会重点在性能上做进一步突破,加强生态集群镜像制作,帮助企业和开发者更快进行交付。
往期推荐
这一次ElasticSearch可能感受到了来自东方的压力 GoFound
聊聊Tiwitter的架构决策
想要了解Go更多内容,欢迎扫描下方👇 关注 公众号,回复关键词 [实战群] ,就有机会进群和我们进行交流~
分享、在看与点赞,至少我要拥有一个叭~