こんにちは😸 Necoの@dulltzです。
皆さんはマルチテナントでGitOpsするためにどのような構成をとっていますか? 我々はArgoCDを利用しています。
以前、@zoetroからArgoCDについての紹介がありました。
上の記事でもテナント*1に対しArgoCDを提供する方法に触れているのですが、 最近そこからもう一歩踏み込んで、テナントがApplicationを任意のタイミングで安全に作れるようにしました。これについて説明します。 なおNecoでは実装をOSSにしているので、記事内にソースコードへのリンクを適宜貼っておきます。気になる方はそちらも御覧ください。
前提知識
- ArgoCD
- KubernetesでGitOpsを行うためのミドルウェアです。*2
- この記事ではArgoCD v1.3.6を対象とします。
Application
- ArgoCDのカスタムリソースです。GitOpsするアプリケーションを宣言します。指定したGitリポジトリパスに置いてあるマニフェストを、ArgoCDはKubernetesに適用してくれます。
AppProject
- ArgoCDのカスタムリソースです。
Application
の論理グループを表現します。AppProject
を使うとApplication
の適用範囲や、Application
にアクセス可能なユーザを制御できます。
- ArgoCDのカスタムリソースです。
- App of Apps
Application
群を管理するためのApplication
を用意することで、Application
自体もGitOpsするというパターンです。*3
現在の構成
先に現在の構成を書いておきます。
Adminチームのマニフェストリポジトリneco-appsにテナントのリポジトリを参照するApp of Apps用Application
を配置することで、
テナントのApplication
をテナント管理のマニフェストリポジトリへ配置できるようにしました。
こうすると何が良いのかというと、テナントチームがApplication
を作るときにKubernetes adminチームへレビューを依頼する手間がなくなります。
詳しい話は後述します。
以前のやり方
以前はテナントがArgoCDを扱えるように、次のような2つのAppProject
を用意していました。
default
: admin向けのprojectです。ArgoCDで可能なすべての権限が許されています。tenant
: テナント向けのprojectです。テナント用のNamespace内にのみアプリケーションをデプロイできます。
これらのうち、テナント用のApplication.spec.project
にはtenant
を指定することで、テナントの権限を制御していました。
テナントのApplication
はすべてNecoチーム(=admin)のマニフェスト用リポジトリneco-appsで管理し、
テナントチームが新たにApplication
を追加したい際には、neco-appsにPRを出してもらうことで対応していました。
この仕組みでは、テナントがApplication
を追加するたびにNecoチームはレビューする必要があり、
テナントはそのレビューを通過するのを待つ必要があります。
どうしてこうなった
テナントがadminチームに毎回PRを投げなければならない仕組みはなんかちょっと面倒そうです。
ここでより良さそうなやり方として思いつくのは、
「AppProject
による権限分離を利用して、
neco-appsにはテナントのApplication
群を管理するApp of Apps用Application
だけを配置しておけば、
テナント用Application
をテナントのリポジトリの中に配置できるのでは?」という方式です。
もしそれができれば、テナントがApplication
を追加しようとするたびNecoチームへPRを出す手間がなくなります。
ですが最初にNecoチームがマルチテナントArgoCDを設計したときは、その方式は採用しませんでした。
なぜかというとApplication
のspec.project
、つまりそのApplication
が所属するAppProject
を指定するフィールドに、任意の値をセットできてしまうからです。
言い換えると、Application
を作る権限を渡すことが、ArgoCDでできるすべてのデプロイを許可することになってしまうということです。
これを防ぐために、neco-appsの中でテナントのApplication
も保持しておき、テナントにはApplication
の作成権限を渡さなかったのでした。
今のやり方
前述の通り、最近やり方を見直してテナントがadminに毎回PRを投げなくても良くなるようにしました。 なぜそうしたのかというと、インフラ管理のための手作業コストの低減がNecoチームの目的の1つだからです。
新しいやり方ではさきほど触れた「テナント用Application
をテナントのリポジトリの中に配置しておいて、neco-appsにはテナントのApplication
群を管理するApp of Apps用Application
だけを配置する」という仕組みになっています。
次のような3つのAppProject
を用意しました。
default
: admin向けのAppProject
です。ArgoCDで可能なすべての権限が許されています。tenant
: テナント向けのAppProject
です。テナント用のNamespace内にのみアプリケーションをデプロイできます。tenant-apps
: テナントのApplication
を作るためのAppProject
です。ArgoCDのApplication ControllerがウォッチするNamespaceにApplication
を作る権限だけを持っています。
テナントのリポジトリを参照するApp of Apps用Application
はtenant-apps
に所属させています。
前述の図を再掲します。
Validating Admission Webhookによる解決
さきほど触れた「テナントがApplication.spec.project
にdefault
を指定できてしまう」問題を解決するために、Validating Admission Webhookを実装しました。
Application
の参照しているリポジトリのURLをもとにApplication.spec.project
として指定可能なプロジェクト名を判定し、テナントの権限を超えたApplication
の作成を禁止しています。
閑話休題: Admission Webhookの実装
巷ではGatekeeperを使いRegoでAdmission Webhookのルールを書く方式が流行っていますが、 NecoではAdmission Webhookをcontroller-runtimeで実装しています。 つまりGoで書いています。
なぜGoで実装しているのかというと、Admission Webhookはカスタムコントローラとほぼ同じやり方で実装できるので、 チームメンバーのスキルセットと相性が良かったからです。
また、現在はneco-containers/admissionにすべてのwebhookを実装しワンプロセスで動かしていますが、 これはそのうち分割するかもしれません。
まとめ
今回紹介した新しいやり方によって、テナントチームがApplication
を作るたびにadminチームへレビューを依頼する手間がなくなりました。
ただしテナントチームが新しいマニフェスト用リポジトリを追加したいときには、adminチームがApp of Apps用Application
を新規追加したり、AppProject
を更新したりする手間が残っています。
このような定形作業は、テナント管理のためのカスタムコントローラを作ることで自動化していく予定です。
今回の内容についてもっと良いやり方があったらぜひ教えてください。
サイボウズではKubernetesが好きなインフラ〜ミドルウェア領域のエンジニアを募集中です。
*1:Kubernetesの管理者権限を持たないユーザとそのグループ
*2:https://github.com/argoproj/argo-cd
*3:https://argoproj.github.io/argo-cd/operator-manual/cluster-bootstrapping/#app-of-apps-pattern