查看原文
其他

sealer,“集群”版本的 Docker,交付复杂度的终结者

GoCN GoCN 2022-09-09

背景

随着时代的发展,单机上跑的单体应用已经越来越少了,分布式应用几乎已经无处不在。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 这些工具,当然没使用的只会比以下步骤更痛苦。

  1. 找一个能在离线环境中安装 kubernetes 本身的工具
  2. 加载你事先打包好的所有 docker 镜像
  3. 启动一个私有镜像仓库
  4. 把所有镜像推送到私有镜像仓库中
  5. 修改编排文件中镜像仓库地址
  6. 执行所有的 helm chart

而使用 sealer 交付故事是:

  1. 加载集群镜像
  2. sealer run [集群镜像]

如果的交付文档很长,整个交付面向过程,那就很适合使用 sealer,可以在整个集群一致性上保证交付成功。

那么如何去构建一个自定义的集群镜像呢?

Build 集群镜像

sealer 运行分布式应用很简单,同样要去自定义一个集群镜像也需要很简单,这里采用与 Docker 镜像几乎相同的方式进行构建。

这里以构建一个 dashboard 的集群镜像为例子:

  1. 编写一个类似 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 搭配使用。

  1. build
sealer build -t dashboard:latest .

这里 sealer 不仅只是把 RUN 命令执行了一下,还会去扫描里面包含的所有 docker 镜像并缓存到集群镜像中,这样启动的时候会直接从缓存的私有镜像仓库中去下载镜像。

  1. Run
sealer run dashboard:latest --masters 192.168.0.2 --passwd xxxkubectl get pod -A|grep dashboard

现在我们就可以运行这个集群镜像,sealer 会先拉起一个 kubernetes 集群,再在其上面部署 dashboard。

这里神奇的地方是虽然 dashboard 编排文件里面写的是 gcr 仓库的镜像地址,sealer 并不会从公网去拉取,而会检测私有镜像仓库是是否存在该镜像,有的话直接从私有镜像仓库中拉取。如此 即便在离线环境中也可以正常拉到镜像,而且整个过程什么也不需要修改。

  1. 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.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/v1beta2kind: ClusterConfigurationnetworking: podSubnet: 100.64.0.0/10

你不需要把所有配置写全,只需要写你关心的字段,会自动合并到默认配置中。

业务配置使用更通用的做法:

---apiVersion: sealer.aliyun.com/v1alpha1kind: Configmetadata: name: mysql-configspec: path: etc/mysql.yaml data: | mysql-user: root mysql-passwd: xxx

data 里面的内容会覆盖镜像内部的 path, 指定的文件,同样支持是直接覆盖还是合并等一些策略,那么这里的内容就很适合是 helm values.

sealer 同样支持用环境变量管理少量配置:

apiVersion: sealer.cloud/v2kind: Clustermetadata: name: my-clusterspec: 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/bashecho $docker-dir

插件机制

插件可以帮助用户做一些之外的事情,比如更改主机名,升级内核,或者添加节点标签等……

主机名插件

如果你在 Clusterfile 后添加插件配置并应用它,sealer 将帮助你更改所有的主机名:

---apiVersion: sealer.aliyun.com/v1alpha1kind: Pluginmetadata: name: hostnamespec: 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/v1alpha1kind: Pluginmetadata: name: shellspec: 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|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: 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/v1alpha1kind: Pluginmetadata: name: checkClusterspec: type: CLUSTERCHECK action: PreGuest

污点插件

如果你在 Clusterfile 后添加 taint 插件配置并应用它,sealer 将帮助你添加污点和去污点:

apiVersion: sealer.aliyun.com/v1alpha1kind: Pluginmetadata: name: taintspec: 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/v1alpha1kind: Clustermetadata: name: my-clusterspec: 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/v1alpha1kind: Pluginmetadata: name: hostnamespec: 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/v1alpha1kind: Pluginmetadata: name: taintspec: 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/v1alpha1kind: Pluginmetadata:name: taintspec:type: SHELLaction: PostInstallon: node-role.kubernetes.io/master=data: | kubectl get nodes---apiVersion: sealer.aliyun.com/v1alpha1kind: Pluginmetadata: name: SHELLspec: 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.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 未来会重点在性能上做进一步突破,加强生态集群镜像制作,帮助企业和开发者更快进行交付。



往期推荐



这一次ElasticSearch可能感受到了来自东方的压力 GoFound


B站 API 网关的发展


聊聊Tiwitter的架构决策

想要了解Go更多内容,欢迎扫描下方👇 关注 公众号,回复关键词 [实战群]  ,就有机会进群和我们进行交流~

分享、在看与点赞,至少我要拥有一个叭~

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存