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.0sealer 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.8RUN wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yamlCMD 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 xxxkubectl 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/v2kind: Clustermetadata:name: default-kubernetes-clusterspec:image: kubernetes:v1.19.8ssh:passwd: xxxhosts:- 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/v1beta2kind: ClusterConfigurationnetworking:podSubnet: 100.64.0.0/10
你不需要把所有配置写全,只需要写你关心的字段,会自动合并到默认配置中。
业务配置使用更通用的做法:
---apiVersion: sealer.aliyun.com/v1alpha1kind: Configmetadata:name: mysql-configspec:path: etc/mysql.yamldata: |mysql-user: rootmysql-passwd: xxx
data 里面的内容会覆盖镜像内部的 path, 指定的文件,同样支持是直接覆盖还是合并等一些策略,那么这里的内容就很适合是 helm values.
sealer 同样支持用环境变量管理少量配置:
apiVersion: sealer.cloud/v2kind: Clustermetadata:name: my-clusterspec:image: kubernetes:v1.19.8env:docker-dir: /var/lib/dockerhosts:- ips: [ 192.168.0.2 ]roles: [ master ] # add role field to specify the node roleenv: # overwrite some nodes has different env configdocker-dir: /data/docker- ips: [ 192.168.0.3 ]roles: [ node ]
镜像内部的脚本就可以直接使用 docker-dir 环境变量:
echo $docker-dir
插件机制
插件可以帮助用户做一些之外的事情,比如更改主机名,升级内核,或者添加节点标签等……
主机名插件
如果你在 Clusterfile 后添加插件配置并应用它,sealer 将帮助你更改所有的主机名:
apiVersion: sealer.aliyun.com/v1alpha1kind: Pluginmetadata:name: hostnamespec:type: HOSTNAMEdata: |192.168.0.2 master-0192.168.0.3 master-1192.168.0.4 master-2192.168.0.5 node-0192.168.0.6 node-1192.168.0.7 node-2
Hostname Plugin 将各个节点在安装集群前修改为对应的主机名。
脚本插件
如果你在 Clusterfile 后添加 Shell 插件配置并应用它,sealer 将帮助你执行 shell 命令 (执行路径为镜像 Rootfs 目录):
apiVersion: sealer.aliyun.com/v1alpha1kind: Pluginmetadata:name: shellspec:type: SHELLaction: 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|PreJoinon : #指定执行命令的机器为空时默认在所有节点执行在所有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/v1alpha1kind: Pluginmetadata:name: labelspec:type: LABELaction: PreGuestdata: |192.168.0.2 ssd=true192.168.0.3 ssd=true192.168.0.4 ssd=true192.168.0.5 ssd=false,hdd=true192.168.0.6 ssd=false,hdd=true192.168.0.7 ssd=false,hdd=true
节点 ip 与标签之前使用空格隔开,多个标签之间使用逗号隔开。
集群检测插件
由于服务器以及环境因素 (服务器磁盘性能差) 可能会导致 sealer 安装完 kubernetes 集群后,立即部署应用服务,出现部署失败的情况。cluster check 插件会等待 kubernetes 集群稳定后再部署应用服务。
apiVersion: sealer.aliyun.com/v1alpha1kind: Pluginmetadata:name: checkClusterspec:type: CLUSTERCHECKaction: PreGuest
污点插件
如果你在 Clusterfile 后添加 taint 插件配置并应用它,sealer 将帮助你添加污点和去污点:
apiVersion: sealer.aliyun.com/v1alpha1kind: Pluginmetadata:name: taintspec:type: TAINTaction: PreGuestdata: |192.168.56.3 key1=value1:NoSchedule192.168.56.4 key2=value2:NoSchedule-192.168.56.3-192.168.56.7 key3:NoSchedule192.168.56.3,192.168.56.4,192.168.56.5,192.168.56.6,192.168.56.7 key4:NoSchedule192.168.56.3 key5=:NoSchedule192.168.56.3 key6:NoSchedule-192.168.56.4 key7:NoSchedule-
data 写法为
ips taint_argumentips : 多个 ip 通过,连接,连续 ip 写法为 首 ip - 末尾 ip taint_argument: 同 kubernetes 添加或去污点写法 (key=value:effect #effect 必须为:NoSchedule, PreferNoSchedule 或 NoExecute)。
插件使用步骤
Clusterfile 内容:
apiVersion: sealer.aliyun.com/v1alpha1kind: Clustermetadata:name: my-clusterspec:image: registry.cn-qingdao.aliyuncs.com/sealer-io/kubernetes:v1.19.8provider: BAREMETALssh:# ssh的私钥文件绝对路径,例如/root/.ssh/id_rsapk: xxx# ssh的私钥文件密码,如果没有的话就设置为""pkPasswd: xxx# ssh登录用户user: root# ssh的登录密码,如果使用的密钥登录则无需设置passwd: xxxnetwork:podCIDR: 100.64.0.0/10svcCIDR: 10.96.0.0/22certSANS:- aliyun-inc.com- 10.0.0.2masters:ipList:- 192.168.0.2- 192.168.0.3- 192.168.0.4nodes:ipList:- 192.168.0.5- 192.168.0.6- 192.168.0.7---apiVersion: sealer.aliyun.com/v1alpha1kind: Pluginmetadata:name: hostnamespec:type: HOSTNAMEdata: |192.168.0.2 master-0192.168.0.3 master-1192.168.0.4 master-2192.168.0.5 node-0192.168.0.6 node-1192.168.0.7 node-2---apiVersion: sealer.aliyun.com/v1alpha1kind: Pluginmetadata:name: taintspec:type: SHELLaction: PostInstallon: 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/v1alpha1kind: Pluginmetadata:name: taintspec:type: SHELLaction: PostInstallon: node-role.kubernetes.io/master=data: |kubectl get nodesapiVersion: sealer.aliyun.com/v1alpha1kind: Pluginmetadata:name: SHELLspec:action: PostInstalldata: |if type yum >/dev/null 2>&1;thenyum -y install iscsi-initiator-utilssystemctl enable iscsidsystemctl start iscsidelif type apt-get >/dev/null 2>&1;thenapt-get updateapt-get -y install open-iscsisystemctl enable iscsidsystemctl start iscsidfi
Kubefile:
FROM kubernetes:v1.19.8COPY 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 未来会重点在性能上做进一步突破,加强生态集群镜像制作,帮助企业和开发者更快进行交付。
往期推荐
想要了解Go更多内容,欢迎扫描下方👇 关注 公众号,回复关键词 [实战群] ,就有机会进群和我们进行交流~
分享、在看与点赞,至少我要拥有一个叭~




