あまり良く知られていない Kubernetes Operator とは？

オペレーター(Operator)は、約3年前にCoreOSから発表[11][12]され、人間のオペレーターの知識をコード化するといった構想が注目を浴びた、しかし、その実態の難解さが障壁であった。それから最近になって Red Hat社のOpenShift4の発表において、オペレーターの推進が前面に押し出され、今年初めには、さらに後押しするように、主要クラウドベンダーと協力してOperatorHub.io を推進することが発表[13]された。IBM Cloud でも Red Hatと統合とOpenShiftの推進に加えて、オペレーターを推進する姿勢が強くなっている。

これは、そもそもオペレーターとは？、その実態についての疑問、現在の目標達成レベルなどについて、調べた結果のメモである。この内容は、筆者が個人的に調べで、まとめた内容である、その中には誤りを含む可能性もあるので、ご留意いただきたい。


## オペレーター(Operator)とは

オペレーター(Operator)は、アプリケーションなどのサービスを管理している人間のオペレーターの代役を務めることを目的とする。

人間のオペレーターは、システムがどのように振る舞うべきか、どう展開するべきか、問題に対処する方法に、深い知識を持っている。そして、K8sを利用する人は、SREの思想に基づいて、繰り返し可能なタスクは、自動化することを好む。 そのような中で、オペレーターはK8s自体が提供する自動化よりさらに多くのタスク自動化のコードを記述する方法をもたらしてくれる[1]。

もともとK8sは自動化のために設計されている。K8sコアには、多くの自動化機能が組み込まれているため、アプリケーション・ワークロードのデプロイと実行などで、自動化の能力をすぐに利用できる。これらの機能を受け持つK8sのリソースやコントローラーは、カスタム・リソース、カスタム・リソース・コントローラーと呼ばれるK8s本体のコードを変更せずに機能の拡張ができるの機能を有している[2]。

オペレーターは、カスタム・リソースとカスタム・コントローラーとして機能する K8s apiserver のクライアントである。

## カスタム・リソース と カスタム・コントローラー

K8s自体のコードを変更せずに機能拡張を実現するには、カスタム・リソース と カスタム・コントローラーを利用する。

### カスタム・リソース

リソースとは、K8s APIのエンドポイントである。例えば、ポッドの K8s API はリソースであり、この組み込みのAPIには、オブジェクトとして実体化、属性の変更、状態取得、削除などのコレクションを含んでいる。 一方、カスタム・リソースは、K8s API の拡張であり、一般的な必須の機能ではなく、特定目的のためのカスタマイズと表現できる。

### カスタム・コントローラー

カスタム・コントローラーによって、カスタム・リソースの生成、状態の取出し、属性変更などが可能となり、宣言型APIの実装を実現するためのコアとなる。

### 動的な変更

K8sクラスターの管理者は、ダイナミック・レジストレーション(dynamic registration)によって、カスタム・リソースを動的に追加、削除、更新がきる。カスタム・リソースを登録されると、以降、kubectl コマンドを利用して、オブジェクトの生成と削除、そして、属性変更が可能となる。
 

### なぜ？ カスタムリソースが必要なのか？

K8s APIを利用して、kubectlコマンドを利用する代わりに、プログラムで自動化するだけならば、わざわざ、カスタムリソースを作成してAPIを操作しなくても、自動化の目的を達成できる。しかし、同じような自動化に対しての再利用が難しい。 つまり、自動化のケースごとに、過去のコードを流用しつつ開発して、一つのコンテナとする。そして、ConfigMapやSecretを併用してパラメータを与えてデプロイする。一方、カスタム・リソースを利用する場合は、同じオペレーターを用いて、APIを通じて動作条件を与えて、幾つでもインスタンス化できるため、再利用性が高いと言える。

例えば、データを保持するステートフルコントローラーの管理下で動作するアプリケーションでは、有益な方法であると考えられる。例えば、KVSのインスタンスを利用する場合は、開発／テスト／本番環境でそれぞれ必要である。それぞれの環境として、ネームスペースやクラスタを変更して何度でも利用したい。環境によって、ポッドのメンバーの数、バックアップの頻度、可用性のレベルが異なるが、実施するべきことは同じである。このようなケースでは、個別に自動運用のポッドを開発するよりも、オペレーターとして開発して、熟成を測った方が、はるかに生産性が高いと考えられる。


## オペレーターフレームワーク

概念的には、オペレーターは人間の操作上の知識をソフトウェアにエンコードし、より簡単にパッケージ化して消費者と共有する。オペレータは、K8s環境を監視し、その現在の状態を使用して数ミリ秒で意思決定を行うソフトウェアベンダーのエンジニアリングチームのようなものと考えると理解しやすい。オペレーターは、アプリケーションの基本的なロジックから特定のロジックを持つまで「成熟度モデル」に従う。つまり、人間のオペレーターがそうであるように、初歩的なオペレーターは、単純なインストールやデプロイしかできない。そして、もう少し熟成度が上がると、ポッド数のスケールや、データバックアップまでの能力を身につける。さらに、円熟した高度なオペレーターは、アップグレードをシームレスに処理し、障害に自動的に対応し、ソフトウェアバックアッププロセスをスキップして時間を節約するなどの深い配慮が可能なように成長を続ける[3]。

オペレータフレームワークは、オープンソースのプロジェクトであり、以下の構成要素が含まれる[5]。

1. Operator SDK
1. Operator Life Cycle Manager
1. Operator Metering
1. OperatorHub.io

#### Operator SDK

SDKは、オペレーターを構築、テスト、およびパッケージ化するツールを提供する。初期段階のSDKは、K8s APIを組み合わせて、スケーリング、アップグレード、またはバックアップの操作を実装する。オペレーターの開発もSDKを通じて継続開発され、より効率よく賢く運用が可能となっていく。オペレーター間で共有される主要なプラクティスとコードパターンがSDKに含まれており、過去の資産を利用できる。

#### Operator Lifecycle Manager

SDKによってオペレーターを開発してビルドしたら、次は、K8sクラスターにデプロイする必要がある。Operator Lifecycle Managerは、K8sクラスター上のオペレーターの管理を容易にするバックプレーンである。これにより、管理者はオペレーターが、どのネームスペースにあるか、実行中オペレーターと誰が対話できるかなどを管理する。また、オペレーターとそのリソースの両方の更新をトリガーするなど、オペレーターとそのリソースの全体的なライフサイクルを管理できる。

#### Operator Metering

将来のバージョンでは、Operator Frameworkにはアプリケーションの使用状況を測定する機能も追加される。これは、ITチームの予算と商用ソフトウェア使用の管理機能をK8sに最初に提供する。オペレーターメータリングは、クラスターのCPUとメモリのレポートに結び付けられ、IaaSコストとライセンスなどのカスタマイズされたメトリックを計算するように設計されている。 Red Hat は、メータリングに積極的に取り組んでおり、今後数か月でオープンソース化され、フレームワークに追加される。

#### OperatorHub.io

2019年2月末、Red Hatは、Amazon Web Services、Google Cloud、Microsoftと共同でOperatorHub.ioを開始した。OperatorHub.ioは、 Kubernetes Operatorのパブリックレジストリである。 開発者およびK8s管理者にとって、高い品質のオペレーターを見つけることは難しい状況が続いているため、解決の支援となることが期待される。2019年8月現在の総登録数は、66件であった。

[OperatorHub.io](https://operatorhub.io/) では、カタログに掲載されたオペレーターの詳細説明では、次の5段階で、成熟度が表現されている[4]。

1. 基本インストール (Basic Install)
1. 影響が無いアップグレード (Seamless Upgrade)
1. フルライフサイクル (Full Lifecycle)
1. 深い洞察 (Deep Insights)
1. 自動操縦 (Auto Pilot)

現在、カタログに掲載されたオペレータのほとんどが初歩的段階であり、2019年8月現在、総登録数 66件で深い洞察や自動操縦のレベルのものは、ほとんど存在しなかった。 オペレーターの目標は非常に高く素晴らしいものであるが、実態は Helm のようなソフトウェアのデプロイとセットアップといったレベルに留まっていることがわかる。


## Helm と Operator のアーキテクチャの違い

オペレーターは、Helm を置き換えるものと誤解されることもあるが、それは間違いである。

#### Helm

次の概念図をもとにHelmのアーキテクチャーを表し、その機能について、箇条書きにまとめた。

![art-of-helm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/e71ae179-bbf5-5f13-d888-78360ca62aea.png)

* helmコマンドから、Helm chartをインストールすることで、K8sクラスタへオブジェクトがデプロイされる。
* helmコマンドは、K8sのAPIオブジェクトのインストール、更新、削除、状態取得ができる。
* helm チャートと呼ばれるマクロを埋め込んだマニフェストのテンプレートやデフォルト値のYAMLなどを、helmコマンドでK8sクラスタへ適用する
* Helm v2 では、K8sクラスタ上でTillerが動作している必要が、v3で廃止される予定
* Helmチャートによって起動したオブジェクトを監視するなどの機能はなく、それらは、K8sのコントローラーが役割を分担する
* helmコマンドは、kubectlコマンドが動作する環境で利用できる
* Helmチャートは、ローカル環境にコピーして、編集して利用することができる。
* Helmチャートを実施するために、他の前提条件となるHelmチャートが必要な場合、追加することができる。

#### Operator

オペレーターについても、次の概念図を用いてアーキテクチャを描き、その機能を箇条書きにした。

![art-of-operator.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/bd353288-0438-109d-4317-9a417f7a33e2.png)

* オペレーターは、K8sクラスタで動作するapiserverのクライアントである。
* オペレーターは、管理対象のオブジェクトの生成、監視、更新、削除などのライフサイクルを管理する
* オペレーターに、指示を与えるには、kubectlコマンドでカスタム・リソースのマニフェストを適用する
* apiserverが、オペレーターによってK8sの機能を拡張したカスタム・リソースのマニフェストを処理できるようにするために、オペレーターの実行に先だって、カスタム・リソース・デフィニッションを生成しておく
* カスタム・リソース・デフィニッションによって、オペレータがapiserverに登録したカスタム・リソースすなわちAPIと、そのコントローラーが対応づけが完了して、カスタムリソースのマニフェストを受け取れるようになる
* オペレーターは、Operator SDKを利用して開発することができる。

Helmは、YAMLなどのマニフェストの集まりをパッケージ化して、一塊りのパッケージとしてインストール、アップデート、削除ができるものである。一方、Operatorは、それ自体がK8sのapiserverのクライアントであり、カスタムリソースのマニフェストに記載された仕様に従って、K8s APIをアクセスすることで、K8sオブジェクトを管理する。 OperatorはオブジェクトそのものをAPIで管理する構造である。


## Operator SDK

operator-sdkコマンドを利用して、オペレーターを開発するための足場(scaffold)となるコードを自動生成することができる。この足場のコードには、Go言語だけではなく、Helmチャート、Ansible playbook を対象とするオペレータを生成することができる。

* HELM [8]
* Ansible [9]
* Go言語 [10]

#### Go言語 オペレーター

上記の三番目のGo言語でオペレータを開発する場合のoperator-sdkコマンドの役割についての箇条書きである。

* オペレーターの雛形の生成 (go言語のソースコード、YAMLファイル)
* オペレーターに対して、APIsの追加、コントローラーの追加
* コンテナ（オペレータ）のビルド
* ローカルでオペレータを動かしてテスト
* オペレーターのAPIsをカスタム・リソース定義のマニフェスト生成
* カスタムリソースのマニフェスト生成

オペレーターの基本機能を持ったコンテナを手軽に開発するための環境といったところである。


## まとめ

オペレーターの構想は素晴らしい、また、K8sの自動化機能を、カスタムリソースを利用して拡張することで、素晴らしく調和した発展が期待される。もちろん、Go言語とK8s APIをベタに書いていけば、kubectl コマンドを駆使する様々な操作を自動化できることは、明らかである。しかし、OperatorHub.ioからもわかるように、信頼できるオペレーター探して利用することが現状では難しい。

オペレーターの開発の初歩について[Go言語で Kubernetes Operator を書いてみた](https://qiita.com/MahoTakara/items/9ce62e8f2226f7b677eb)に書いたので、合わせて参照してもらいたい。

オペレーターを使って、クラウドのDBaaSのようにデータベース運用を自動化して利用できる日を夢見て、発展を見守ると共に、自分でも、熟成度の高いオペレーターを開発について、考察を深めたいと思う。


# 参考資料

[1]. オペレーターパターン、https://kubernetes.io/docs/concepts/extend-kubernetes/operator/
[2]. カスタムリソース、https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/
[3]. オペレーターフレームワーク、https://www.redhat.com/en/blog/introducing-operator-framework-building-apps-kubernetes
[4]. OperatorHub.io、https://operatorhub.io
[5]. オペレーターフレームワーク入門、https://www.redhat.com/en/blog/introducing-operator-framework-building-apps-kubernetes
[6]. Introducing OperatorHub.io: The place for finding Kubernetes-native services, https://www.redhat.com/en/blog/introducing-operatorhubio-place-finding-kubernetes-native-services#
[7]. https://www.atmarkit.co.jp/ait/articles/1903/04/news066.html
[8]. Helmオペレータ・ユーザーガイド、https://github.com/operator-framework/operator-sdk/blob/master/doc/helm/user-guide.md
[9]. Ansibleオペレータ・ユーザーガイド、https://github.com/operator-framework/operator-sdk/blob/master/doc/ansible/user-guide.md
[10]. Go言語オペレーター・ユーザーガイド、https://github.com/operator-framework/operator-sdk/blob/master/doc/user-guide.md
[11]. Introducing Operators: Putting Operational Knowledge into Software, https://coreos.com/blog/introducing-operators.html
[12]. 【翻訳】Operator の紹介：運用の知見をソフトウェアに入れる, https://pocketstudio.net/2016/11/10/introducing-operators-translate-jp/
[13]. Introducing OperatorHub.io: The place for finding Kubernetes-native services、https://www.redhat.com/en/blog/introducing-operatorhubio-place-finding-kubernetes-native-services#