Kubernetesを使った開発プロセスにこれから必要なのは制約ではないか

この記事はOpenSaaS Studio Advent Calendar 2019の4日目の記事。

複雑化したアプリケーションの整合性担保と統率の難しさ

Kubernetesベースのアプリケーションを開発・運用において、GitOpsスタイルでCI/CDのパイプラインを組むみたいなことは普通になってきた感がある。とはいえ、いくらyamlファイルがある程度ヒューマンリーダブルなフォーマットであっても、PRのレビューにおいてその妥当性をチェックするというのは難しいし時間を必要とする。

レビュアーはPRのスコープ外の既に適用されているリソースにも気を配る必要があるし、conftestのようなマニフェストの静的解析も有用ではあるが、実際にマニフェストがクラスタに適用されてどのような影響が起こりうるか?みたいなとこまでチェックできる人というのは、Kubernetesに精通していてかつ、そのアプリケーションの全体を俯瞰して見れる経験値を積んだ人間だけである。

さらに、アプリケーションの複雑さを増長する要素がある。マイクロサービスアーキテクチャだ(メリットも多いが、ここでは複雑性にだけ言及する)。マイクロサービスアーキテクチャでは、各サービスが協調してようやく一つのシステムとして体をなす。このような構成だと、サービスの依存関係だったり、運用上考慮すべきコンテキストを把握しなければならない。開発者も超人だし、レビュアーも超人だ。

「そのような能力を持つ者を1人でも増やすこと」は課題解決のアプローチとしてあるかもしれないが、多くの人はそこに開発のスケーラビリティを見いだせず、逆に難しさだけが虚しく残る。

コンテナ時代におけるアプリケーションとオーケストレーションの整合性

少し前の時代のことを考えてみよう。アプリケーションをVMにデプロイしていた時代だ。かっちり構築されたインフラにWebサーバの後ろに、ソフトウェアエンジニアはアプリケーションを正しく載せることに集中すればよかった(もちろんリリースエンジニアリングを担当する者の苦労はあったが)。

そして、アプリケーションをコンテナに乗せる時代になり、高い可搬性と伸縮性がもたらされた。インフラやホストをあまり気にせずアプリケーションをデプロイすることが当たり前となった。

同時にWebサーバのようなミドルウェアは、よりアプリケーションに近くなる運用に様変わりし、アプリケーションエンジニアもインフラエンジニアも双方の知識が必要となり、各サービスやコンポーネントの連携、リソースの配分や適切な活用を行うために、Kubernetesに代表されるコンテナオーケストレーション技術が台頭した。

アプリケーションの構築の面で大きなパラダイムシフトが起きたが、開発プロセスがそれに追従するのは少し遅れた感がある。ようやく成熟し始めたといったところであるが、やはり多くのマニフェストファイルがあまりにも簡単にクラスタに適用されてきてしまったと感じる(これは直でkubectl applyだけではなく、パイプライン制御されたCDでのdeliveryも含まれる)。

間違ったマニフェストが適用されることを回避したい

個人的には人の目で見るのが厳しいものがレビューで漏れてしまうのは無理もないと思っていて、マニフェストもその類であると考える。つまるところ、「間違ったマニフェストが適用されることを機械的に回避したい」ということである。

devやtest環境も簡単に作れるからトライアンドエラーがナンボでしょみたいに考えてしまいがちであるが、そこに甘んじているともはやGitOpsとはみたいな変な感じになってくる。「Terraformのapply通ったんでmasterにマージしまーす」に近いものを感じる。applyされたものの実態はまだmasterに反映されてないにも関わらず。

ローカルやサンドボックス的環境でのトライアンドエラーは許容しても、このようなフローは正規の開発プロセスには入れたくないところ。

結局は制約が欲しいのでは?

名著「SQLアンチパターン」の「キーレスエントリ」の章を思い出す。外部キー制約を宣言せずに、整合性をアプリケーションで保証するというアレだ。アプリケーションの実装は絶えず変化して拡大していく中で完全性を求めることは無理があるため、データベースレベルで強い制約を施して副作用を未然に防止するというのは単純かつ合理的だ。

そしてアプリケーション側にもバリデーションを実装するのは当たり前だが、マニフェストファイルも同じ属性のソフトウェアエンジニアが扱うにも関わらず、バリデーションや制約についてそこまで注視されてなかったように感じている(主観な)。

レビューは人や時間に依存するので恒久的ではない。対して制約はポリシーの制定にはコストを払う必要があるが、仮に専門家がプロジェクトを離れても制約は生き続ける(捨てない限りは)ので、制約にコストを払っていくことで得られる物は多いのではないかと考えている。

幸いにもKubernetesではその高い拡張性によって、制約を設ける仕組みを取り入れることができる。Open Policy Agentだ。

Open Policy Agent

Open Policy Agent(以下OPA)はCNCFによってホストされている汎用ポリシーエンジンで、APIにおける認証・認可をはじめ、KubernetesやサービスメッシュのIstioのようなものにまでポリシーを実施できる。

OPAはそこそこ歴史があって2, 3年前からその存在を認識していたが、OPAをKubernetesで実現するためのコントローラーであるgatekeeperの開発が活発というのと、先述した欲求からも強く欲しだしたというところである。

長くなりそうなので

今回はこのくらいにしておく。次はOPAのプロダクトであるgatekeeperの使い所について考察をお届けするつもり。gatekeeperでは独自の制約をCRDとして適用できる。例えば、「このDeploymentにはhogehogeのlabelが不可欠なので、マニフェストに定義されていない場合は制約によってapplyできない」といった制御を可能にする。

(ちなみに次回といっても明日とは限らない。明日は気が変わって違うネタを書いてるかもしれない)