cf-operator的介绍

cf-operator马上就要在近期宣布beta release。beta版会实现在Kuberntes上部署Cloud Foundry或者BOSH release应用的功能。作为主要开发者之一,想在beta之前写几篇文章介绍cf-operator。第一篇文章将主要介绍cf-operator的由来和主要功能。

什么是cf-operator

想要说清楚cf-operator的功能和实现,就需要先说说近几年Cloud Foundry社区(以下简称CFF)对于Kubernetes的探索和将CF和Kube结合的尝试。了解其中的目标和不足。这些尝试包括如下三类:

  • 将CF已有功能扩展到Kubernetes:有使用CF BOSH在IaaS上部署和管理Kubernetes集群的kubo项目。在这种方法中,Kubernetes负责调度应用容器,BOSH负责创建虚拟机并调度虚拟机上的任务。这些任务通过执行kubeadm/kubelet来实现集群Nodes的功能。也有将部分功能组件提取并贡献到CNCF的项目,比如nats和buildpack。buildpack是CF用来构建应用镜像的工具。这一功能被应用到来knative中,在build阶段构建应用image。
  • CF Containerization:从BOSH release出发,将CF的组件转化成Docker images和Helm charts,然后通过两者将CF部署到Kubernetes上。这个转化过程用到来fissile工具,将BOSH在虚机上启动BOSH Job的逻辑(组织软件包、应用模板和启动应用进程)提取出来。用户应用默认还是跑在CF的Diego runtime中。
  • 容器调度功能的插件化:在CF内部,Diego负责调度应用容器;而Kubernetes有自己的调度器。CF孵化出Eirini来控制和管理容器后端。目前Eirini仅仅支持Kubernetes。

Cloud Foundry Containerization

cf-operator就是替换CF Containerization中部署的一环。我们先看看现有的部署方式有什么不足。通过scf的源码可以看出,现有的cf on kube是通过make target完成不同的任务:

scf statu quo

  1. make bosh-images uaa-images:构建CF组件的Docker images,构建过程中需要指定stemcell、release和fissile定义的release manifest来配置的image参数
  2. make helm:当有个应用所需的image之后就可以生成Helm Charts
  3. make run:通过Helm部署CF

前段时间SUSE和IBM一直围绕这个流程做自动化构建、部署和企业级扩展并推出了相应的产品。在这个过程中,我们尝试解决很多问题并且发现如下不足:

  1. fissile带来了新的概念(role manifest,opinions)和"outside-BOSH"的功能给开发人员带来了认知负担和技术债务。
  2. fissile的配置文件和BOSH release提供的配置项(properties)没有达到一一对应,并且在部署时,还有一层Helm values的映射关系。给功能调试和扩展带来了不小的困难。
  3. Helm只是个包管理工具,部署和升级应用都是指令式的。部署时容易出现随机错误,部署失败很难依靠Helm本身来排查错误难排查。并且,Helm缺少更高级和处理复杂应用的功能。
  4. 转化的容器应用在架构上也存在缺陷。容器运行时,会先调用configgin来渲染应用模板,然后通过monit来管理多个应用进程。在一个容器中执行多个进程这本身就不合理,容器应该是一个有着资源隔离的和轻量化的进程。而scf从启动到运行将容器当成虚拟机来使用。并且应用执行错误时,也很难定位出问题的进程和追踪问题。

而cf-operator就是为了解决CFF在Kubernetes上部署CF遇到的这些问题。

cf-operator是怎么做的

cf-operator的最初设计是将image build和deploy configuration分离,并且通过Kuberntes的CRD和controller-runtime来实现BOSH release在Kubernetes上的部署。

首先,我们重新划分Fissile和cf-operator的职能:

  • fissile只需要完成image构建的工作,并且构建不再需要release manifest指定BOSH release容器化的配置。
  • cf-operator要做的是:1. 接收cf-deployment manifest并且将BOSH instance group转化成Kubernetes的资源定义 2.将configgin的render BOSH ERB templates步骤放在了每个pod的Init Containers中 3. 移除monit,并使用BOSH Process Manager(BPM)来管理应用进程, 通过BPM和Bosh link的信息来限制process的启动 4. 每个容器只运行一个Job的进程,并且通过 BPM来提供entrypoint所需信息

那么CF Containerization的流程就变成了这样:

cf-o flow

cf-operator将读取BOSH相兼容的cf-deployment manifest的配置信息并使用fissile构建的release image来部署CF。更进一步说,只要用户提供来包含BOSH release的image和相应的BOSH deployment manifest,cf-operator就能够将这个应用部署在Kubernetes上。

为了实现上述功能,cf-operator需要扩展Kube原有的资源类型并且自定义一个总体控制部署的资源类型。

Extended-resources definitions

为了完成实现BOSH deployment在kube上的部署,cf-operator定义了三种资源类型来扩展现有的Statefulset、Job和Secret类型。

1. ExtendedStatefulSet

ExtendedStatefulSet负责Service类型的Instance group在Kubernetes上的实现。一个Service会持续运行并且当出现故障时会自动重启。ExtendedStatefulSet的controller会创建运行Service的Statefulset并且支持如下功能:

  • 当存储Statefulset的配置资源(ConfigMap,Secret)被修改时,ExtendedStatefulSet会被自动更新(创建新版本的Statefulset)
  • 自动的蓝绿部署:当需要更新时,新版本的Statefulset会被创建并且和旧版同时存在。直到新版本满足canary的条件(默认是一个新版本的Pod准备就绪)时,旧版本的资源都会被删除
  • 存储卷的管理:当更新时,能够重用旧版本的PVC
  • 可用区域(AZ)的支持:AZ是BOSH的概念,controller会在每个zone里创建一个StatefulSet并通过node affinity来控制编排

ests controller

为了实现如上功能,cf-operator会启动两个controller来管理ExtendedStatefulSet。一个ExtendedStatefulSet controller会监控ExtendedStatefulSet的定义和其引用的ConfigMap或者Secret(volume或者env value)。当监控的资源发送变化时,这个controller会依据新的spec创建新版本的StatefulSet。而另一个cleanup controller则会监控新StatefulSet的创建,并且当新版本的Pod准备就绪之后尝试删除旧版本的StatefulSet。

2. ExtendedJob

和ExtendedStatefulSet类型,ExtendedJob负责实现Errand的Instance group。一个Errand会创建一个Kube Job来完成任务。并且依据spec不同,ExtendedJob支持如下功能:

  • 不同类型的Job:one-off job是创建之后会被自动执行的任务单元,errand job是需要手动触发执行的任务单元。
  • 当Job的配置资源(ConfigMap,Secret)修改时,one-off job会被自动执行
  • 存储job container执行结果:能够将执行之后的结果存储到Kube Secret中并且删除Kube Job。
  • 带版本的Secret存储:当ExtendedJob选择将结果存储到"Versioned Secrets"时,controller会控制输出存储到比已有Secret的版本加"1"的新Secret中

ejob controller

对于ExtendedJob,cf-operator也注册两个controller来协调。erran-controller和ExtendedStatefulSet controller类似,监控ExtendedJob对象和所引用的配置资源的变化,并创建Kube Job来执行任务。如果你想要trigger errand job需要将 spec.trigger.strategy: manual修改成spec.trigger.strategy: now。而job-controller则会依据spec.output的信息,将运行结果存储到指定的secret中。

3. ExtendedSecret

ExtendedSecret的主要功能是配置和生成BOSH Variables。依据spec.type的不同,ExtendedSecret支持下列敏感数据的生成:

  • password
  • rsa key
  • ssh key
  • self-signed root certificate
  • self-signed certificate
  • cluster-signed certificate

和其他类型不同,cluster-signed certificate的证书是被Kubernetes API Server签发的,这个证书至少是在集群范围内所认可的证书。

esec-controller

ExtendedSecret的两个controller中,一个ExtendedSecret controller负责监控ExtendedSecret的对象,然后依据类型和参数生成相应的敏感数据。如果需要生成集群签发的证书,ExtendedSecret controller会生成CertificateSigningRequest对象。CertificateSigningRequest controller会监控ExtendedSecret controller生成的CertificateSigningRequest对象并且自动批准该对象。当API Server签发该证书之后,ExtendedSecret controller再继续将certificate和相应的private key存储到指定的secret中。

BoshDeployment definition

BoshDeployment的资源定义是一种专门为BOSH Deployment在Kubernetes实现的类型。这个资源的Controller集主要实现三大部分的功能(这里涉及了很多BOSH的概念,需要自己探索):

  • 读取Deployment manifest并插入(interpolate)ops file的内容和BOSH Variables
  • 将BOSH的概念转化成Kubernetes的概念:
    • BOSH service转化成ExtendedStatefulSet和kube Service(如果有服务需要暴露)
    • BOSH errand转化成ExtendedJob
    • BOSH variable转化成ExtendedSecret
    • BOSH stemcell和BOSH release一起转化成Docker image
  • 部署Instance group在Kubernetes上的实现

bdpl-workflow

BoshDeployment的controller集的工作十分复杂,我们先屏蔽一些细节。对于BoshDeployment CRD,Deployment controller会监控这类资源以及所引用的其他配置资源。当BoshDeployment需要更新时,Deployment controller首先会解析base manifest,并且插入spec所引用的ops configMap/secret。处理之后的manifest包含我们期望的应用配置信息和所需的变量信息,所以我们称之为with-ops manifest。并且Deployment controller还会创建三个重要的ExtendedJob:desired manifest eJob(简称dm-ejob),instance group eJob(简称ig-ejob),和bpm config eJob(简称bpm-ejob)。dm-ejob依赖variable secrets,ig-ejobbpm-ejob依赖dm-ejob的结果Secret(例如desired manifest-v1)。ig-ejobbpm-ejob为每个instance group创建相应的secret:

  • Instance Group解析后的属性(properties)(例如ig-resolved.nats-v1)
  • Instance Group的BPM信息 (例如bpm.nats-v1)

而variable secrets都是通过generated-variable controller来生成的。generated-variable controller监控with-ops manifest并解析variables项,然后创建所需的ExtendedSecret。当dm-ejob所需的variable secrets都被ExtendedSecret controller生成之后,Kube才会分配Job pod到空闲的Node上运行。同理,ig-ejobbpm-ejob也会在所需的引用资源都生成之后才延后启动pod。

最终当单个instance group的bpm configs secret被创建出来之后,最后一个controller——bpm controller会监控这类secret的创建并获得早已创建好的desired manifest,通过desired manifest的定义将intance group转化成相应的ExtendedStatefulSet或者ExtendedJob。如果ExtendedStatefulSet需要对外暴露相应的服务,bpm controller也会生成对应的Kube service。直到这时,cf-operator才算是将BOSH Deployment部署到Kubernetes上了。

最后一点展望

通过扩展Kubernetes API,cf-operator做到了像Kube原生资源一样部署BOSH应用(最大的应用应该就是Cloud Foundry了)。并且这个应用还可以直接通过kubectl来操作和管理。但是目前来说,还只是剥离了fissile的部分功能完成部署的邀请。在未来,我们也会汲取知识继续修复问题和提供新功能:

  • 对于BOSH lifecycle management的实现不完全。我们还会继续完善BOSH所定义的应用管理功能。
  • 除了想当然的升级功能,我们还需思考Operation的功能。我们怎么通过cf-operator来实现自恢复、回滚或者备份。
  • 出于最初设计,我们拘泥于细节的实现。还有很多Kubernetes的功能和新理念需要我们掌握和应用。