4.2.2 performRelease
当拼接完毕后,下一步就是安装环节。首先要检查Chart是否含有一些Pre-hooks,特别是crd-install这种Hooks。因为针对这种类型的Hooks,Helm会在创建其他资源之前,第一步优先创建该资源,否则后面依赖该资源的对象都会安装失败。
// performRelease runs a release. func (s *ReleaseServer) performRelease(r *release.Release, req *services.InstallReleaseRequest) (*services.InstallReleaseResponse, error) { // crd-install hooks if !req.DisableHooks && !req.DisableCrdHook { if err := s.execHook(r.Hooks, r.Name, r.Namespace, hooks.CRDInstall, req.Timeout); err != nil { fmt.Printf("Finished installing CRD: %s", err) return res, err } } else { s.Log("CRD install hooks disabled for %s", req.Name) } ... ... ... } func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook string, timeout int64) error { kubeCli := s.env.KubeClient code, ok := events[hook] if !ok { return fmt.Errorf("unknown hook %s", hook) } ... // 首先根据不同的权重,将各种Hooks排序,依次将Hooks做成一个可执行数组 executingHooks = sortByHookWeight(executingHooks) // 遍历所有的Hooks for _, h := range executingHooks { // 筛选before-create hook,看看是否需要提前执行Hooks的删除 if err := s.deleteHookByPolicy(h, hooks.BeforeHookCreation, name, namespace, hook, kubeCli); err != nil { return err } b := bytes.NewBufferString(h.Manifest) // 将剩余的资源,特别是CRD资源装载到集群中 if err := kubeCli.Create(namespace, b, timeout, false); err != nil { s.Log("warning: Release %s %s %s failed: %s", name, hook, h.Path, err) return err } // 这里要保证pre-install需要安装的资源必须等待安装成功后才能继续下一步 if hook != hooks.CRDInstall { // 在这里一直等待资源创建成功 if err := kubeCli.WatchUntilReady(namespace, b, timeout, false); err != nil { s.Log("warning: Release %s %s %s could not complete: %s", name, hook, h.Path, err) // 如果Hooks失败,检查Hooks的注释,以确定是否应该删除该Hooks // 在Hooks失败的情况下,清除Hooks中相应的资源 if err := s.deleteHookByPolicy(h, hooks.HookFailed, name, namespace, hook, kubeCli); err != nil { return err } return err } } else { if err := kubeCli.WaitUntilCRDEstablished(b, time.Duration(timeout)*time.Second); err != nil { s.Log("warning: Release %s %s %s could not complete: %s", name, hook, h.Path, err) return err } } } s.Log("hooks complete for %s %s", hook, name) }
·将Hooks按照权重的顺序依次排序,优先级从高到低,一般需要先安装pre-install。
·deleteHookByPolicy函数将需要在安装前删除的资源优先删除。
·将剩余需要创建的资源,尤其是CRD资源提交给集群创建。
·提交后一直等待资源创建完毕,默认超时时间为1min。
·全部Hooks资源创建完毕后,代表该Chart Hooks准备完毕。
Hooks准备完成就可以安装资源了。
s.recordRelease(r, false) if err := s.ReleaseModule.Create(r, req, s.env); err != nil { msg := fmt.Sprintf("Release %q failed: %s", r.Name, err) s.Log("warning: %s", msg) r.Info.Status.Code = release.Status_FAILED r.Info.Description = msg s.recordRelease(r, true) return res, fmt.Errorf("release %s failed: %s", r.Name, err) }
可以看到,接下来先将Release信息记录到Kubernetes集群中,目前Helm默认的方式是记录到kube-system下的configmap中。
基本信息记录完毕后,就可以将剩余Chart渲染后的资源文件提交给Kubernetes ApiServer。下面我们依次看一下代码。
// 如果是重用名称,直接更新对应的configmap // 如果是新的名称,直接创建对应的configmap func (s *ReleaseServer) recordRelease(r *release.Release, reuse bool) { if reuse { if err := s.env.Releases.Update(r); err != nil { s.Log("warning: Failed to update release %s: %s", r.Name, err) } } else if err := s.env.Releases.Create(r); err != nil { s.Log("warning: Failed to record release %s: %s", r.Name, err) } } // 将Chart内容编译成字节流,然后通过client-go无结构体提交给ApiServer func (m *LocalReleaseModule) Create(r *release.Release, req *services.InstallReleaseRequest, env *environment.Environment) error { b := bytes.NewBufferString(r.Manifest) return env.KubeClient.Create(r.Namespace, b, req.Timeout, req.Wait) } [root@iZhp38179i8shwfjy8jbigZ ~]# kubectl get cm -n kube-system --show-labels NAME DATA AGE LABELS wordpress-default.v1 1 40s NAME=wordpress-default,OWNER =TILLER,STATUS=DEPLOYED,VERSION=1
由上可见,集群中安装了Release的信息都被存放在kube-system命名空间下的configmap中。configmap的名称就是Release的名字,后面的点对应着它的版本号。比如这里的v1就是第一次安装的版本,后面的labels也能表明一些身份,比如OWNER=TILLER,代表它是Tiller创建的。
[root@iZhp38179i8shwfjy8jbigZ ~]# kubectl get cm wordpress-default.v1 -n kube-system -o yaml apiVersion: v1 data: release: H4sIAAAAAAAC/+z9XWwkyZYfhuPeuXf33lxAkHoF4a8L/O3Y4mjZnGFmk kind: ConfigMap metadata: creationTimestamp: "2019-11-27T11:57:21Z" labels: MODIFIED_AT: "1574855841" NAME: wordpress-default OWNER: TILLER STATUS: DEPLOYED VERSION: "1" name: wordpress-default.v1 namespace: kube-system resourceVersion: "1637228" selfLink: /api/v1/namespaces/kube-system/configmaps/wordpress-default.v1 uid: 118b0a0e-110d-11ea-83b0-00163e00d57b
Release后面的信息就是base64编码后的Chart信息,有兴趣的读者可以反编译看一下内容。
这些操作全部完成后,需要再次执行post-install hooks,也就是安装之后需要执行的Hooks,执行流程与前面相似。
这样全部的创建流程就完成了,后面就可以将这个Release的状态改为Status_DEPLOYED。