# 15 分钟制作 Kubernetes Operator

原文：[Make a Kubernetes Operator in 15 minutes with Helm](https://blog.openshift.com/make-a-kubernetes-operator-in-15-minutes-with-helm/)

作者：[Rob Szumski](https://blog.openshift.com/author/rszumski/)

之前我们介绍了如何[使用 Ansible 实现 Helm Chart 的自动化](https://blog.openshift.com/automating-helm-charts-with-ansible/)。今天会继续这方面的话题，但是会转用 [Operator](https://coreos.com/blog/introducing-operator-framework)。Operator 是一种打包、部署和管理 Kubernetes 应用的方法。这里说的 Kubernetes 应用，不仅是部署在 Kubernetes 集群中，还使用 Kubernetes API 以及 kubectl 工具进行管理。

本文会尝试根据已有的 Helm chart 来创建一个 Operator，以此展示 Operator 的价值。这一过程无需编写 Go 代码，仅需要使用 [Operator 框架](https://github.com/operator-framework) 中的 [Helm Operator 工具包](https://github.com/operator-framework/helm-app-operator-kit)。最后还会对 Go 和 Helm 实现的 Operator 进行比较。

## 我们期待的用户体验

本文试图描述多数公司中都存在的一种场景：用稳定、可复用以及可审计的方式，在多个环境中发布应用或产品，首先做一下分析。

**稳定的部署过程**：在符合所有需求的情况下（例如所有测试均已通过，或者负责人审核通过），用全自动的方式进行部署。

**可复用的部署过程**：工件一旦完成构建，就应该有一个无法变更的版本号。对于单个组件来说，在容器中进行构建是很方便的，然而分布式系统通常都是多个组件构成的。Helm chart 可以将这些组件组织到一起，但是 Chart 本身也需要版本化。Helm Operator 可以把 Chart 和依赖捆绑到 Operator 容器镜像中，这样就有了一个覆盖完整分布式系统的单一的版本化呈现。借助版本化的 Operator 容器，工程师就能在多个环境中运行同一版本的应用了。

**可审计的部署过程**：应用的部署和运行都是在受控的环境中完成的，而不是工程师的笔记本电脑。Helm Operator 允许用户使用现存的 Helm Chart，无需手工运行 Helm 命令。这样就降低了一次性错误的发生机会，提供了用于审计的轨迹。

这一过程大致包含一下步骤，后续会进一步进行说明：

1. 对 Chart 进行一些变更。例如给应用组件加入版本。
    
2. 一个用于[构建 Operator](https://github.com/operator-framework/helm-app-operator-kit#instructions)的持续构建流程，将新的 Chart 拷贝到容器之中。
    
3. 能把 Operator 部署到测试集群上一个新的命名空间的测试管线。测试套件使用新的 Operator，运行对应配置的应用。假设一个应用同时提供了标准模式和高可用模式的配置，Operator 应该可以使用新的 Chart 来测试这两种模式。新的命名空间应该可以在测试完成后删除。
    
4. 如果测试通过，发布管理员会进行确认，或者自动触发确认过程。接下来持续部署系统会使用这一 Operator 对应用进行在线的滚动更新，或蓝绿部署。这一过程应该能够在应用所在的其他环境、其他命名空间中重复运行。
    

接下来会手工完成整个过程，当然读者可以发挥想象力，例如将 `Quay.io` 加入进来构建镜像，或者用 Jenkins/CircleCI 等运行测试并和 Kubernetes 进行通信。

## 前提条件：Kubernetes 环境和镜像库

Helm Operator 套件需要 Kubernetes 1.9 以上的集群，集群需要有足够资源运行一到两套测试应用。本地需要有 Docker 来构建镜像，并且有 kubectl 用于控制集群。如果熟悉常 Helm 操作，对本文的理解会更有帮助。

## Operator 如何运作

Helm Operator 是用来应对仅需少量部署逻辑的无状态应用的。如果这一描述不符合你的应用的实际情况，在本文最后会提供一些替代选项。

Operator 的主要功能就是在自定义对象和对应应用实例的状态之间进行同步。Helm Operator 套件生成的 Operator 对象中，`spec` 字段是一个配置列表，其内容一般是在 Helm 的 `values.yaml` 文件中指定的。我们会在自定义资源中指定选项值，而不是使用命令参数（`helm install -f values.yaml`），自定义资源对象是 Kubernetes 的原生对象，这样就能够享受到 RBAC 和审计方面的益处。例如这样一个简单的资源：

```yaml
apiVersion: apache.org/v1alpha1
kind: Tomcat
metadata:
    name: example-app
spec:
    replicaCount: 2
```

`replicaCount` 的值是 `2`，会传播给 Chart 的模板：

```bash
{{ .Values.replicaCount }}
```

Operator 构建和部署之后，部署应用的新实例就很只需要简单的创建一个新的自定义资源了。比如说要列出所有环境中的实例，只需要使用 `kubectl`：

```shell
kubectl get Tomcats --all-namespaces
```

这样也就无需使用 Helm 命令行或者安装 Tiller 了；Operator 镜像是由 Helm Operator 套件从 Helm 项目中导入生成的。只要 Operator 实例在运行，并用 CRD 注册自定义资源即可，并且自定义资源需服从 RBAC 的管理，这样也可以更方面的管理产品的变更。

这就好像建立了一个应用上线的流程：首先创建自定义资源，然后实例就会上线和运行。

## 构建 Operator 镜像

我们认为最佳时间就是为每个 Chart 都创建一个新的 Operator。这样看起来更符合 Kubernetes API 的风格（例如 `kubectl get Tomcats`），如果需要更好的控制，还可把 Operator 从 Helm 迁移到 Go。第一步是把 Chart、Kubernetes API 组（例如 `apache.org/v1alpha1`）以及 `Kind`（例如 Tomcat）集成到 Operator 的容器镜像中。这一部分很简单，Dockerfile 把这些变量用[构建参数](https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables---build-arg)的形式公开为变量。只要构建 Dockerfile 然后进行推送即可：

```bash
$ docker build \
  --build-arg HELM_CHART=https://storage.googleapis.com/kubernetes-charts/tomcat-0.1.0.tgz \
  --build-arg API_VERSION=apache.org/v1alpha1 \
  --build-arg KIND=Tomcat \
  -t quay.io/<namespace>/tomcat-operator:v0.0.1 .
$ docker push quay.io/<namespace>/tomcat-operator:v0.0.1
```

## 相关链接

1. **使用 Ansible 实现 Helm Chart 的自动化**:`https://blog.openshift.com/automating-helm-charts-with-ansible/`
    
2. **Operator 框架**：`https://github.com/operator-framework)`
    
3. **Helm Operator 工具包**：`https://github.com/operator-framework/helm-app-operator-kit`
