github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/docs/design/upgrade_cluster_zh.md (about) 1 # sealer upgrade 命令的原理与实现 2 3 ``` 4 截止PR#783,upgrade命令的工作流程可以概括如下: 5 解析命令的参数->执行Apply()函数->执行diff()函数得到todoList->执行todoList中的函数->升级成功->更新当前集群的Image变量值。 6 ``` 7 8 **接下来对流程中的每一步进行详细分析** 9 > 1.解析命令参数,根据参数创建applier。解析命令的参数值,主要是获取当前集群的Clusterfile和期望状态的镜像。根据Clusterfile得到一个`v1.Cluster`对象,由于集群的期望状态与当前状态的区别只是使用不同的镜像,故此步可以建立一个表示集群期待状态的`v1.Cluster`对象,然后使用改`v1.Cluster`对象做为参数,调用apply包下的`NewApplier()`函数,返回一个满足`apply.Interface`接口的applier对象。 10 --- 11 > 2.执行`Apply()`函数。执行步骤1中得到的applier的`apply()`函数。applier有两个变量成员`ClusterDesired`和`ClusterCurrent`。到此时为止,`ClusterDesired`已经根据步骤1中`NewApplier`函数的参数`v1.Cluster`进行了初始化,而`ClusterCurrent`为空。为了接下来能够进行期望状态与当前状态的镜像对比,需要找出当前状态的镜像,代码如下: 12 13 ``` 14 clusterFilePath := common.GetClusterWorkClusterfile(c.ClusterDesired.Name) 15 if utils.IsFileExist(clusterFilePath) { 16 clusterBeforeUpgrade, err := GetClusterFromFile(clusterFilePath) 17 if err != nil { 18 return err 19 } 20 if clusterBeforeUpgrade.Spec.Image != c.ClusterDesired.Spec.Image { 21 c.ClusterCurrent.Spec.Image = clusterBeforeUpgrade.Spec.Image 22 } 23 } 24 ``` 25 26 > 此段代码所做的事情是:到指定路径下找到Clusterfile文件,然后根据Clusterfile文件得到当前集群的状态(此时的状态是未升级的状态),与期望状态的镜像进行对比。如果不同,则说明需要进行升级操作,设置`ClusterCurrent`的`Image`属性,便于接下来进行对比。 27 --- 28 > 3.执行`diff()`函数,把需要执行的函数加入todoList。在`diff()`函数中进行对比,判断是否需要进行升级。如果需要进行升级,则在todoList中加入相应的函数。 29 30 ``` 31 if c.ClusterDesired.Spec.Image != c.ClusterCurrent.Spec.Image { 32 todoList = append(todoList, MountRootfs) 33 todoList = append(todoList, Upgrade) 34 } 35 ``` 36 37 > 此处要说明的是:为了执行一个完整的upgrade操作,在该`if`语句块之前还需要加入todoList的函数有:`PullIfNotExist`和`MountImage`,在该`if`语句块之后还需要加入todoList的函数有:`Guest`和`UnMountImage`。 38 --- 39 > 4.执行todoList中的函数。此处着重介绍`Upgrade`函数的原理,其他函数的介绍参考相应的文档。`Upgrade`函数的具体实现在`runtime`包下,upgrade.go文件。流程可以概括为:==创建ssh.Client对象->升级主控制节点->升级其余控制节点->升级工作节点==。创建ssh.Client对象的代码如下,其中参数的类型是`*v1.Cluster` 40 41 ``` 42 client, err := ssh.NewSSHClientWithCluster(cluster) 43 ``` 44 45 > 所有节点的升级原理大致相同,核心是通过IP地址登录到对应节点,执行集群升级命令。以升级主控制节点为例,主要做了以下几件事情: 46 47 - 将节点rootfs文件系统下bin目录中的二进制文件赋予执行权限,并移动至/usr/bin目录下。(因为/usr/bin包含在环境变量PATH的值中) 48 - 用kubectl drain排空节点。 49 - 用kubectl upgrade升级节点。 50 - 重启节点上的kubelet。 51 - 将节点标记为可调度。 52 53 >其余控制节点上的操作与主控制节点一致,工作节点上不用进行“排空节点”的操作和“标记节点为可调度”的操作。 54 --- 55 > 最后,在upgrade操作成功之后,将`ClusterCurrent`的`Image`属性值,更新为`ClusterDesired`的`Image`属性值。 56 57