この記事から得られる知識
この記事を読むと、以下を "完全に理解" できます✌️
- Kubernetesのマルチテナントパターンの種類
- マルチテナントパターンをArgoCDで実践する場合にオススメのパターン (★で表現)
- ArgoCDのNamespacedスコープモードとClusterスコープモード
- ArgoCDのテナントが防いでくれる誤った操作の具体例
記事のざっくりした内容は、以下のスライドからキャッチアップできちゃいます!
- この記事から得られる知識
- 01. はじめに
- 02. なぜマルチテナントが必要なのか
- 03. Kubernetesのマルチテナントパターン
- 04. ArgoCDでのテナントパターン実践一覧
- 04-02. Clusters as-a-Service 実践
- 04-03. Control Planes as-a-Service 実践
- 04-04. Namespaces as-a-Service 実践
- 04-05. カスタムリソーステナントの実践
- 05. CLモードなArgoCD
- 05-02. NSモードなArgoCD - ★★
- 06. どのような誤った操作を防いでくれるのか
- 07. おわりに
- 謝辞
- 記事関連のおすすめ書籍
01. はじめに
どうも、熟成アルトバイエルンです。
さて最近の業務で、全プロダクトの技術基盤開発チームに携わっており、全プロダクト共有のArgoCD🐙のマルチテナント化を担当しました。
プロダクトが稼働するKubernetes Clusterが数十個あり、Clusterによっては複数のチームが合計100
個以上のマイクロサービスを動かしています。
このような大規模なマイクロサービスシステムがいくつもある状況下で、ArgoCDのマルチテナント設計の知見を深められたため、記事で解説しました。
書きたいことを全部書いたところ、情報量がエグいことになってしまったため、気になる章だけでも拾って帰っていただけるとハッピーです🙏
- Kubernetesのマルチテナントパターン (3章)
- ArgoCDでのテナントパターン実践一覧 (4章)
- ArgoCDのClusterスコープモードとNamespacedスコープモード (5章)
- どのような誤った操作を防いでくれるのか (6章)
それでは、もりもり布教していきます😗
飛ばしていただいても大丈夫ですが、読んでもらえるとより理解が深まるはずです👍
02. なぜマルチテナントが必要なのか
シングルテナントの場合
そもそも、なぜArgoCDにマルチテナントが必要なのでしょうか。
例えば、マニフェストのデプロイ先となるプロダクト用Cluster (例:foo
、bar
、baz
) があると仮定します。
ArgoCDをシングルテナントにする場合、各プロダクトチームの操作するApplicationを同じテナントに共存させることになります。
この場合、単一のargocd-server (ダッシュボード) から全てのApplicationを操作できて便利です。
しかし、プロダクト用Cluster数が増えていくにつれて、問題が起こり始めます。
例えば、いずれかのプロダクトチームが誤ったApplicationを操作し、結果的に誤ったプロダクト用Clusterにマニフェストをデプロイしてしまう可能性があります。
もちろん、システムでインシデントを起こしてやろうという悪意を持った人が、誤ったプロダクト用Clusterを意図的に選ぶ可能性もあります😈
マルチテナントの場合
その一方で、いい感じのマルチテナントにしたとします。
プロダクトチームは、認可されたテナントに所属するApplicationにのみを操作でき、反対に無認可のテナントのApplicationは操作できません。
これにより、誤ったプロダクト用Clusterにマニフェストをデプロイすることを防げます。
03. Kubernetesのマルチテナントパターン
マルチテナントパターンの一覧
ArgoCDのテナント設計を実践する前に、Kubernetesにはどんなマルチテナントパターンがあるのでしょうか。
Kubernetesのマルチテナントパターンは、以下に大別できます。
Clusters |
Control Planes |
Namespaces |
カスタムリソース テナント |
||
---|---|---|---|---|---|
テナント単位 | 実Cluster | 仮想Cluster | Namespace | ツール固有の論理空間 | |
テナント間でKubernetesリソースを分離できるか | Cluster スコープ リソース |
✅ | ✅ | ✅ | ツールによる |
Namespaced スコープ リソース |
✅ | ✅ | ツールによる | ||
ツール |
|
|
Namespaceを増やすだけなので特別なツール不要 |
|
本記事では言及しませんが、"ソフトマルチテナンシー" と "ハードマルチテナンシー" といった分類方法もあります。
この分類方法では、テナント間の分離度の観点で各マルチテナントを種別します。
ソフトマルチテナンシーは、互いに信頼できる前提の上で、テナント間を弱く分離します。
その一方で、ハードマルチテナンシーは、互いに信頼できない前提の上でテナント間を強く分離します。
分離度がソフトとハードのいずれであるかに客観的な指標がなく、やや曖昧な種別になってしまうため、本記事の X as-a-Service の方が個人的には好みです♡♡♡
Clusters as-a-Service
Clusters as-a-Serviceは、テナントごとに独立したClusterを提供します。
ツールとして、AWS EKS、GCP GKE、Azure AKE、Kubeadmなどがあります。
Control Planes as-a-Service
Control Planes as-a-Serviceは、テナントごとに独立したコントロールプレーン (言い換えば仮想Cluster) を提供します。
ツールとして、Kcp、tensile-kube、vcluster、VirtualClusterなどがあります。
Namespaces as-a-Service
Namespaces as-a-Serviceは、テナントごとに独立したNamespaceを提供します。
Namespaceを増やすだけなため、ツールは不要です。
カスタムリソーステナント
カスタムリソーステナントは、テナントごとにツール固有の論理空間 (例:ArgoCDのAppProject、CapsuleのTenant、kioskのAccount、KubeZooのTenantなど) を提供します。
ツールによっては、X as-a-Service も兼ねている場合があります。
今回紹介するAppProjectは、前述の『Namespace as-a-Service』を兼ねています。
AppProjectについては、カスタムリソーステナント で解説しています。
04. ArgoCDでのテナントパターン実践一覧
お待たせしました。
ここからは、KubernetesのマルチテナントパターンをArgoCDで具体的に実践し、おすすめのパターン実践を解説していきます。
なお、オススメするものを ★ としています。
実Cluster テナント |
仮想Cluster テナント |
Namespace テナント |
AppProject テナント |
AppProject テナント |
||
---|---|---|---|---|---|---|
対応するテナントパターン | Clusters |
Control Planes |
Namespaces |
カスタムリソース テナント |
||
ArgoCDがテナント間で占有 / 共有 | 占有 | 占有 | 占有 | 共有 | 占有 | |
テナント間でKubernetesリソースを分離できるか | Namespaced スコープ リソース |
✅ | ✅ | ✅ | ✅ | ✅ |
Cluster スコープ リソース |
✅ | ✅ | ||||
オススメ | ★ | ★★ |
以降の図の凡例です。
ArgoCDの各コンポーネント (application-controller、argocd-server、dex-server、repo-server) と各リソース (Application、AppProject) を区別しています。
04-02. Clusters as-a-Service 実践
実Clusterテナント
実Clusterテナントは、Clusters as-a-Serviceなテナントの実践であり、実際のClusterをテナントの単位とします。
後述の仮想Clusterと対比させるために、"実Cluster" と呼ぶことにします。
各プロダクトチームは、実Clusterテナント内のApplicationを操作し、正しいプロダクト用Clusterにマニフェストをデプロイします。
オススメしない理由
実Clusterテナントには、以下のメリデメがあります。
デメリットの回避策も考慮して、独断と偏見でオススメしませんでした。
半年以内にアップグレードしないとサポートが切れるKubernetesクラスターが33個もあって、泣いちゃった
— 長谷川 広樹 (俺です) (@Hiroki__IT) January 18, 2023
特性 |
メリット ⭕️ | デメリット × | デメリットの回避策 | |
---|---|---|---|---|
拡張性 | - | テナントを増やすために実Clusterを用意する必要があり、作業量が多い。 | ➡︎ | IaCツールで実Clusterを用意するようにすれば作業量を減らせるが、やっぱりとてもつらい😭 |
安全性 (セキュリティ) |
ClusterからClusterへの名前解決を不可能にすれば、他のテナントからの通信を遮断できる。 | - | ➡︎ | - |
保守性 | ClusterスコープまたはNamespacedスコープなKubernetesリソースを他のテナントから分離できる。 これらのKubernetesリソース (特にCRD) の変更が他のテナントに影響しない。 |
各テナントが、個別に実Clusterを保守しないといけない。 |
➡︎ | 回避できず、とてもつらい😭 |
性能 | Clusterのハードウェアリソースを他のテナントと奪い合うことなく、これを独占できる。 | - | ➡︎ | - |
信頼性 | テナントごとに実Clusterが独立しており、他の実Clusterから障害の影響を受けない。 | - | ➡︎ | - |
04-03. Control Planes as-a-Service 実践
仮想Clusterテナント - ★
仮想Clusterテナントは、Control Planes as-a-Serviceなテナントの実践であり、仮想Clusterをテナントの単位とします。
各プロダクトチームは、仮想Clusterテナント内のApplicationを操作し、正しいプロダクト用Clusterにマニフェストをデプロイします。
オススメした理由
仮想Clusterテナントには、以下のメリデメがあります。
デメリットの回避策も考慮して、独断と偏見で オススメ しました。
特性 |
メリット ⭕️ | デメリット × | デメリットの回避策 | |
---|---|---|---|---|
拡張性 | テナントを増やすためにマニフェストで定義した仮想Clusterを用意するだけでよく、実Clusterを用意することと比べて作業量が少ない。 | - | ➡︎ | - |
安全性 (セキュリティ) |
仮想ClusterからホストClusterへの名前解決を不可能にすれば、他のテナントからの通信を遮断できる。 | - | ➡︎ | - |
保守性 | ClusterスコープまたはNamespacedスコープなKubernetesリソースを他のテナントから分離できる。 これらのKubernetesリソース (特にCRD) の変更が他のテナントに影響しない。 |
各テナントが、個別に仮想Clusterを保守しないといけない。 |
➡︎ | 仮想Clusterに関する知見を持つ組織であれば、各テナントで保守できる。 |
性能 | - | Clusterのハードウェアリソースを他のテナントと奪い合うことになる。 | ➡︎ | 多くの利用者が同時並行的にArgoCDを操作する状況になりにくければ、奪い合いも起こらない。 |
信頼性 | テナントごとに仮想Clusterが独立しており、他の仮想Clusterから障害の影響を受けない。 | - | ➡︎ | - |
04-04. Namespaces as-a-Service 実践
Namespaceテナントは、Namespaces as-a-Serviceなテナントの実践であり、Namespaceをテナントの単位とします。
後述の AppProjectテナント は二重のテナントを持ち、Namespaceテナントも兼ねています。
そのため、ここではNamespaceテナントの解説は省略します。
04-05. カスタムリソーステナントの実践
AppProjectテナント
AppProjectテナントは、カスタムリソーステナントの実践であり、NamespaceとAppProjectをテナントの単位とします。
AppProjectテナントは、二重のテナント (第一テナントにNamespace、第二テナントに複数のAppProject) を持ち、"あらゆる面から" マニフェストのデプロイを制限します。
特に、AppProjectはNamespaceスコープなカスタムリソースであり、自身に所属するApplicationを一括して制限します。
apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: foo-tenant namespace: foo # 自身に所属するApplicationを制限する spec: ...
apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: infra-application namespace: foo spec: # foo-tenantに所属する project: foo-tenant ...
カスタムリソースのCRDの実装から、ドキュメントに未記載の仕様を読み取れることがあります。
例えば、本記事ではAppProjectに自由にNamespaceを設定していますが、ArgoCDのドキュメントには任意のNamespaceを設定できることが明記されていません。
しかし、AppProjectのCRDの
.spec.scope
キーからも分かる通り、AppProjectはNamespacedスコープなカスタムリソースであり、任意のNamespaceを設定できます👍
apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: labels: app.kubernetes.io/name: appprojects.argoproj.io app.kubernetes.io/part-of: argocd name: appprojects.argoproj.io spec: group: argoproj.io names: kind: AppProject ... # Namespacedスコープなカスタムリソースであるとわかる scope: Namespaced ...
CLモード vs. NSモード
ArgoCDには、Clusterスコープモード と Namespacedスコープモード (以降、"CLモード" と "NSモード") があります。
スコープモードに応じて、AppProjectテナントの設計方法が異なります。
本章では、CLモードとNSモードの両方でAppProjectテナントを解説していきます。
05. CLモードなArgoCD
CLモードなArgoCDとは
CLモードなArgoCDの場合、各テナント間で共有のArgoCDを管理します
例えば、AppProjectテナントとして、プロダクト別のNamespace (foo
、bar
、baz
) とAppProject (foo
、bar
、baz
) を用意します。
別途、ArgoCD専用のNamespace (argocd
) を用意し、ここに関連するKubernetesリソース (例:ConfigMap) を配置します。
各プロダクトチームは、AppProjectテナント内のApplicationを操作し、正しいプロダクト用Clusterにマニフェストをデプロイします。
AppProject
NSモードと同様にして、AppProjectに所属するApplicationによるマニフェストのデプロイを制限できます。
例えば、以下のような実装になります。
apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: foo-tenant namespace: foo spec: destinations: # ArgoCD用Clusterに関する認可を設定する # App Of Appsパターンの場合に使用する - namespace: foo server: "https://kubernetes.default.svc" # プロダクト用Clusterに関する認可を設定する - namespace: "*" server: https://foo-cluster.gr7.ap-northeast-1.eks.amazonaws.com # CLモードでは設定が必要である sourceNamespaces: - foo
Applicationを操作するログインユーザーが、無認可のNamespaceやClusterをデプロイ先に指定できないように、.spec.destination
キーで制限しています。
一方で後述のNSモードとは異なり、CLモードなArgoCDは任意のNamespaceのApplicationにアクセスできます。
そのため、.spec.sourceNamespaces
キーで、特定のNamespaceのApplicationがこのAppProjectに所属できないように、ApplicationのNamespaceを制限しています。
ArgoCDコンポーネント用ConfigMap (argocd-cmd-params-cm
)
NSモードと同様にして、argocd-cmd-params-cm
では、ArgoCDの各コンポーネントのコンテナの引数を設定できます。
例えば、以下のような実装になります。
apiVersion: v1 kind: ConfigMap metadata: name: argocd-cmd-params-cm # 専用のNamespaceを設定する namespace: argocd data: # CLモードでは設定が必要である # 全てのNamespaceを指定したい場合は、ワイルドカードを設定する application.namespaces: "*"
.application.namespaces
キーは、argocd-serverとapplication-controllerの--application-namespaces
オプションに相当します。
一方での後述のNSモードとは異なり、CLモードなArgoCDは任意のNamespaceのApplicationにアクセスできます。
--application-namespaces
オプションで、任意のNamespaceにアクセスするための認可を設定できます。
--application-namespaces
オプションの設定方法についてargocd-cmd-params-cm
の代わりに、例えば以下のようにPodに引数を直接渡しても良いです🙆🏻
例えば、以下のような実装になります。
apiVersion: v1 kind: Pod metadata: name: argocd-server namespace: argocd spec: containers: - name: argocd-server image: quay.io/argoproj/argocd:latest args: - /usr/local/bin/argocd-server # コンテナ起動時の引数として - --application-namespaces="*" ...
apiVersion: v1 kind: Pod metadata: name: argocd-application-controller namespace: argocd spec: containers: - name: argocd-application-controller image: quay.io/argoproj/argocd:latest args: - /usr/local/bin/argocd-application-controller # コンテナ起動時の引数として - --application-namespaces="*" ...
ログインユーザー用ConfigMap (argocd-rbac-cm
)
NSモードと同様にして、argocd-rbac-cm
では、Applicationを操作するログインユーザーが、無認可のAppProjectやNamespaceに所属するApplicationを操作できないように制限します。
例えば、以下のような実装になります。
apiVersion: v1 kind: ConfigMap metadata: name: argocd-rbac-cm # 専用のNamespaceを設定する namespace: argocd data: # デフォルトのロール # @see https://github.com/argoproj/argo-cd/blob/master/assets/builtin-policy.csv#L9-L16 policy.default: role:readonly policy.csv: | p, role:foo, *, *, foo/*/*, allow p, role:bar, *, *, bar/*/*, allow p, role:baz, *, *, baz/*/*, allow g, foo-team, role:foo g, bar-team, role:bar g, baz-team, role:baz scopes: "[groups]"
認証済みグループ (foo-team、bar-team、baz-team) に対して、無認可のAppProject (foo
、bar
、baz
) に所属するApplicationを操作できないように、認可スコープを制限しています。
ConfigMap (argocd-rbac-cm) の認可スコープの定義には、 Casbin の記法を使用します。
今回の実装例で使用した
p
(パーミッション) とg
(グループ) では、以下を記法を使用できます👍
apiVersion: v1 kind: ConfigMap metadata: name: argocd-rbac-cm namespace: argocd data: policy.default: role:readonly policy.csv: | # ロールとArgoCD系カスタムリソースの認可スコープを定義する p, role:<ロール名>, <Kubernetesリソースの種類>, <アクション名>, <AppProject名>/<ApplicationのNamespace名>/<Application名>, <許否> # 認証済みグループにロールを紐付ける g, <グループ名>, role:<ロール名> scopes: "[groups]"
オススメしない理由
CLモードなArgoCDのAppProjectテナントには、以下のメリデメがあります。
デメリットの回避策も考慮して、独断と偏見でオススメしませんでした。
特性 |
メリット ⭕️ | デメリット × | デメリットの回避策 | |
---|---|---|---|---|
拡張性 | テナントを増やすためにNamespaceとAppProjectを用意するだけでよく、作業量が少ない。 | - | ➡︎ | - |
安全性 (セキュリティ) |
NetworkPolicyでNamespace間の名前解決を不可能にすれば、他のNamespaceからの通信を遮断できる。 | - | ➡︎ | - |
保守性 | ArgoCD用Clusterの管理者が単一のClusterを保守すればよい。(例:アップグレード、機能修正など) | AppProjectはNamespacedスコープなカスタムリソースのため、ClusterスコープなKubernetesリソースを他のテナントと共有しないといけない。 そのため、ClusterスコープなKubernetesリソース (特にCRD) の変更は全てのテナントに影響する。 |
➡︎ | ArgoCDのアップグレード時 (CRDの変更時) は、ついでにKubernetesもアップグレードしたい。 新しいClusterを別に作成し、そこで新ArgoCDを作成すれば一石二鳥である。 |
性能 | - | Clusterのハードウェアリソースを他のテナントと奪い合うことになる。 | ➡︎ | 多くの利用者が同時並行的にArgoCDを操作する状況になりにくければ、奪い合いも起こらない。 |
信頼性 | - | ClusterまたはArgoCDで障害が起こると、これは全てのテナントに影響する。 | ➡︎ | 代わりにNodeやArgoCDを十分に冗長化して可用性を高めれば、影響を緩和できる。 ただ、そもそもの影響範囲が大きすぎる😭 |
05-02. NSモードなArgoCD - ★★
NSモードなArgoCDとは
NSモードなArgoCDの場合、前述のCLモードとは異なり、各AppProjectテナント間でArgoCDを占有します。
例えば、AppProjectテナントとして、プロダクト別のNamespace (foo
、bar
、baz
) とAppProject (foo
、bar
、baz
) を用意します。
各AppProjectテナントに、ArgoCDと関連するKubernetesリソース (例:ConfigMap) を配置します。
各プロダクトチームは、AppProjectテナント内のApplicationを操作し、正しいプロダクト用Clusterにマニフェストをデプロイします。
AppProject
CLモードと同様にして、AppProjectに所属するApplicationによるマニフェストのデプロイを制限できます。
例えば、以下のような実装になります。
apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: foo-tenant namespace: foo spec: destinations: # ArgoCD用Clusterに関する認可を設定する # App Of Appsパターンの場合に使用する - namespace: foo server: "https://kubernetes.default.svc" # プロダクト用Clusterに関する認可を設定する - namespace: "*" server: https://foo-cluster.gr7.ap-northeast-1.eks.amazonaws.com # NSモードでは設定が不要である # sourceNamespaces: # - foo
Applicationを操作するログインユーザーが、無認可のNamespaceやClusterをデプロイ先に指定できないように、.spec.destination
キーで制限しています。
前述のCLモードとは異なり、NSモードなArgoCDは自身が所属するNamespaceのApplicationのみにアクセスできます。
そのため、.spec.sourceNamespaces
キーでマニフェストのデプロイを制限する必要はありません。
ArgoCDコンポーネント用ConfigMap (argocd-cmd-params-cm
)
CLモードと同様にして、argocd-cmd-params-cm
では、ArgoCDの各コンポーネントのコンテナの引数を設定できます。
例えば、以下のような実装になります。
apiVersion: v1 kind: ConfigMap metadata: name: argocd-cmd-params-cm namespace: foo data: # NSモードでは設定が不要である # application.namespaces: "*"
前述の通り、.application.namespaces
キーは、argocd-serverとapplication-controllerの--application-namespaces
オプションに相当します。
前述のCLモードとは異なり、NSモードなArgoCDは自身が所属するNamespaceのApplicationのみにアクセスできます
そのため、.application.namespaces
キーでNamespaceに関する認可を設定する必要はありません
もちろん、Podのコンテナ引数にも設定は不要です。
ログインユーザー用ConfigMap (argocd-rbac-cm
)
CLモードと同様にして、argocd-rbac-cm
では、Applicationを操作するログインユーザーが、無認可のAppProjectやNamespaceに所属するApplicationを操作できないように制限します。
例えば、以下のような実装になります。
apiVersion: v1 kind: ConfigMap metadata: name: argocd-rbac-cm namespace: foo data: # デフォルトのロール # @see https://github.com/argoproj/argo-cd/blob/master/assets/builtin-policy.csv#L9-L16 policy.default: role:readonly policy.csv: | p, role:app, *, *, app/*/*, allow p, role:infra, *, *, infra/*/*, allow g, app-team, role:app g, infra-team, role:infra scopes: "[groups]"
認証済みグループ (app-team、infra-team) に対して、無認可のAppProject (app
、infra
) に所属するApplicationを操作できないように、認可スコープを制限しています。
特にオススメした理由
NSモードなArgoCDのAppProjectテナントには、以下のメリデメがあります。
デメリットの回避策も考慮して、独断と偏見で 特にオススメ しました。
特性 |
メリット ⭕️ | デメリット × | デメリットの回避策 | |
---|---|---|---|---|
拡張性 | テナントを増やすためにNamespaceとAppProjectを用意するだけでよく、作業量が少ない。 | - | ➡︎ | - |
安全性 (セキュリティ) |
NetworkPolicyでNamespace間の名前解決を不可能にすれば、他のNamespaceからの通信を遮断できる。 | - | ➡︎ | - |
保守性 | 単一のClusterを保守すればよい。 |
AppProjectはNamespacedスコープなカスタムリソースのため、ClusterスコープなKubernetesリソースを他のテナントと共有しないといけない。 そのため、ClusterスコープなKubernetesリソース (特にCRD) の変更は全てのテナントに影響する。 |
➡︎ | ArgoCDのアップグレード時 (CRDの変更時) は、ついでにKubernetesもアップグレードしたい。 新しいClusterを別に作成し、そこで新ArgoCDを作成すれば一石二鳥である。 |
性能 | - | Clusterのハードウェアリソースを他のテナントと奪い合うことになる。 | ➡︎ | 多くの利用者が同時並行的にArgoCDを操作する状況になりにくければ、奪い合いも起こらない。 |
信頼性 | テナントごとにArgoCDを占有しており、他のArgoCDから障害の影響を受けない。 | Clusterで障害が起こると、これは全てのテナントに影響する。 | ➡︎ | 代わりに、Nodeを十分に冗長化して可用性を高める。 いずれかのインスタンスで障害が起こっても、正常なインスタンスでArgoCDが稼働できる。 |
AppProjectテナント例の一覧
NSモードなArgoCDを採用する場合、AppProjectテナント例を解説していきます。
前述の通り、AppProjectテナントが二重テナント (第一テナントにNamespace、第二テナントに複数のAppProject) を持つことに留意してください。
なお、オススメするものを ★ としています。
テナント例 (二重テナント) |
オススメ | ||
---|---|---|---|
Namespace (第一テナント) |
AppProject (第二テナント) |
||
テナント例1 | プロダクトの実行環境別 | プロダクトの実行環境別 | |
テナント例2 | プロダクト別 | プロダクトの実行環境別 | ★ |
テナント例3 | プロダクト別 | プロダクトのサブチーム別 | ★★ |
本記事では言及しませんが、Namespaceにはいくつかの分割パターンがあり、本記事ではこれも取り入れてAppProjectテナントを設計しています。
例えば、"管理チーム別" (今回でいうプロダクト別) というNamespaceの分割パターンは、様々な著名な書籍やブログで紹介されています👀
テナント例1
Namespace (プロダクトの実行環境別)、AppProject (プロダクトの実行環境別)
プロダクトの実行環境 (Dev環境、Tes環境) 別に管理されたClusterがいる状況と仮定します。
この場合に、プロダクトの実行環境別にNamespace (dev
、tes
) とAppProject (dev
、tes
) を用意します。
オススメしなかった理由
テナント例1には、以下のメリデメがあります。
独断と偏見でオススメしませんでした。
特性 |
メリット ⭕️ | デメリット × | デメリットの回避策 | |
---|---|---|---|---|
拡張性 | - | ArgoCDのPod数が多くなり、将来的にNode当たりのPodやIPアドレスの上限数にひっかかりやすい。 その時点で、AppProjectテナントの増やせなくなる。 |
➡︎ | 例えばAWS EKSの場合、Node数を増やしたり、Nodeのスペックを上げる。 ただ、お金がかかる😭 |
安全性 (セキュリティ) |
ログインユーザー用ConfigMap (argocd-rbac-cm ) を使用すれば、無認可の実行環境別AppProjectに所属するApplicationを操作できないように制限できる。 |
- | ➡︎ | - |
保守性 | 異なる実行環境に関するApplicationが共存しておらず、別のargocd-serverから操作することになるため、実行環境間の選択ミスが起こりにくい。 | - | ➡︎ | - |
テナント例2 - ★
Namespace (プロダクト別)、AppProject (プロダクトの実行環境別)
プロダクトの実行環境 (Dev環境、Tes環境) 別に管理されたClusterがいる状況と仮定します。
プロダクト別にNamespace (foo
、bar
) 、プロダクトの実行環境別にAppProject (dev
、tes
) を用意します。
オススメした理由
テナント例2には、以下のメリデメがあります。
独断と偏見で オススメ しました。
特性 |
メリット ⭕️ | デメリット × | デメリットの回避策 | |
---|---|---|---|---|
拡張性 | ArgoCDのPod数が多くなり、将来的にNode当たりのPodやIPアドレスの上限数にひっかかりにくい。 | - | ➡︎ | - |
安全性 (セキュリティ) |
ログインユーザー用ConfigMap (argocd-rbac-cm ) を使用すれば、無認可の実行環境別AppProjectを操作できないように制限できる。 |
- | ➡︎ | - |
保守性 | - | 異なる実行環境に関するApplicationが共存しており、同じargocd-server (ダッシュボード) から操作することになるため、実行環境間の選択ミスが起こりやすい。 | ➡︎ | ダッシュボードにはApplicationのフィルタリング機能があるため、選択ミスを回避できる。 |
テナント例3 - ★★
Namespace (プロダクト別)、AppProject (プロダクトのサブチーム別)
プロダクトの実行環境 (Dev環境、Tes環境) 別に管理されたClusterがいる状況と仮定します。
プロダクト別にNamespace (foo
、bar
) 、プロダクトのサブチーム別にAppProject (app
、infra
) を用意します。
特にオススメした理由
テナント例3には、以下のメリデメがあります。
独断と偏見で 特にオススメ しました。
特性 |
メリット ⭕️ | デメリット × | デメリットの回避策 | |
---|---|---|---|---|
拡張性 | ArgoCDのPod数が多くなり、将来的にNode当たりのPodやIPアドレスの上限数にひっかかりにくい。 | - | ➡︎ | - |
安全性 (セキュリティ) |
ログインユーザー用ConfigMap (argocd-rbac-cm ) を使用すれば、無認可のサブチーム別AppProjectに所属するApplicationを操作できないように制限できる。 |
- | ➡︎ | - |
保守性 | - | 異なる実行環境に関するApplicationが共存しており、同じargocd-server (ダッシュボード) から操作することになるため、実行環境間の選択ミスが起こりやすい。 | ➡︎ | ダッシュボードにはApplicationのフィルタリング機能があるため、選択ミスを回避できる。 |
06. どのような誤った操作を防いでくれるのか
そろそろ解説を読むのがしんどい方がいるのではないでしょうか。
『君がッ、泣くまで、解説をやめないッ!』
AppProjectテナントとNamespacedスコープモードがマニフェストのデプロイをどのように制限するのかについて、例を挙げて解説します。
ここでは、以下のAppProjectを作成したと仮定します。
AppProjectテナントが二重テナント (第一テナントにNamespace、第二テナントに複数のAppProject) を持つことに留意してください。
apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: # appチーム name: app namespace: foo spec: destinations: # ArgoCD用Clusterに関する認可を設定する # Namespace (foo) へのデプロイを許可する - namespace: foo server: "https://kubernetes.default.svc" # プロダクト用Clusterに関する認可を設定する # Namespace (app) へのデプロイを許可する - namespace: app server: https://foo-cluster.gr7.ap-northeast-1.eks.amazonaws.com
apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: # infraチーム name: infra namespace: foo spec: destinations: # ArgoCD用Clusterに関する認可を設定する # Namespace (foo) へのデプロイを許可する - namespace: foo server: "https://kubernetes.default.svc" # プロダクト用Clusterに関する認可を設定する # Namespace (infra) へのデプロイを許可する - namespace: infra server: https://foo-cluster.gr7.ap-northeast-1.eks.amazonaws.com
マニフェストのデプロイ制限
プロダクトの実行環境 (Dev環境、Tes環境) 別に管理されたClusterがいる状況と仮定します。
プロダクト別にNamespace (foo
) 、プロダクトのサブチーム別にAppProject (app
、infra
) を用意します。
AppProjectテナントは、例えば 赤線 の方法で、マニフェストのデプロイを制限します。
マニフェストをデプロイできる場合
マニフェストを正しくデプロイする場合、AppProjectテナントはこれを制限しません。
(1) argocd-serverは、argocd-cmd-params-cm
からアクセスできるNamespaceを取得します。
apiVersion: v1 kind: ConfigMap metadata: name: argocd-cmd-params-cm namespace: foo data: # 設定しないことで、argocd-serverは同じNamespaceにしかアクセスできなくなる。 # application.namespaces: "*"
(2) fooプロダクトのinfraチームが、argocd-serverを操作します。
(3) argocd-serverは、argocd-rbac-cm
からApplication操作に関する認可スコープを取得します
apiVersion: v1 kind: ConfigMap metadata: name: argocd-rbac-cm namespace: foo data: policy.default: role:readonly policy.csv: | p, role:app, *, *, app/*/*, allow p, role:infra, *, *, infra/*/*, allow g, app-team, role:app g, infra-team, role:infra scopes: "[groups]"
(4) infraチームは、認可されたAppProjectに所属するApplicationを操作します。
(5) infraチームは、Dev環境のfooプロダクト用ClusterのNamespace (infra
) にマニフェストをデプロイできます。
(🚫制限例1) 無認可のNamespaceでApplicationを作成しようとした場合
例えば、fooプロダクトのinfraチームが無認可のNamespace (bar
) でApplicationを作成しようとします。
すると、argocd-serverは以下のようなエラーを返却し、この操作を制限します。
namespace bar is not permitted in project 'infra-team'
無認可のNamespaceでApplicationを作れてしまうと、そのApplicationから無認可のプロダクト用Clusterにマニフェストをデプロイできてしまいます😈
(🚫制限例2) 無認可のAppProjectでApplicationを作成しようとした場合
例えば、fooプロダクトのinfraチームが、無認可のAppProject (app
) でApplicationを作成しようとします。
すると、argocd-serverは以下のようなエラーを返却し、この操作を制限します。
Application referencing project 'app' which does not exist
任意のAppProjectでApplicationを作成できてしまうと、そのApplicationから無認可のプロダクト用Clusterにマニフェストをデプロイできてしまいます😈
(🚫制限例3) 無認可のClusterをデプロイ先に指定しようとした場合
例えば、fooプロダクトのinfraチームがApplicationを操作し、無認可のプロダクト用Cluster (bar-cluster
) をデプロイ先として指定しようします。
すると、argocd-serverは以下のようなエラーを返却し、この操作を制限します。
application destination {https://bar-cluster.gr7.ap-northeast-1.eks.amazonaws.com infra} is not permitted in project 'infra-team'
任意のClusterをデプロイ先に指定できてしまうと、Applicationから無認可のプロダクト用Clusterにマニフェストをデプロイできてしまいます😈
(🚫制限例4) 無認可のNamespaceをデプロイ先に指定しようとした場合
例えば、fooプロダクトのinfraチームがApplicationを操作し、無認可のNamespace (app
) をデプロイ先に指定しようします。
すると、argocd-serverは以下のようなエラーを返却し、この操作を制限します。
application destination {https://foo-cluster.gr7.ap-northeast-1.eks.amazonaws.com app} is not permitted in project 'infra-team'
任意のNamespaceをデプロイ先に指定できてしまうと、そのApplicationから無認可のNamespaceにマニフェストをデプロイできてしまいます😈
AppProjectテナントは、その他にも以下のような認可を設定できます。
- argocd-serverとapplication-controllerでデプロイできるKubernetesリソースの種類 (
.spec.clusterResourceWhitelist
キー、.spec.namespaceResourceWhitelist
キーなど) - repo-serverでポーリングできるリポジトリ (
.spec.sourceRepos
キー)
apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: foo-tenant namespace: foo spec: clusterResourceWhitelist: - group: "*" kind: "*" namespaceResourceWhitelist: - group: "*" kind: "*" sourceRepos: - "*" ...
"AppProjectテナントによるマニフェストのデプロイ丸ごとの制限" という観点でテーマが異なるため、本記事では言及しませんでした🙇🏻
カスタムリソースのReconciliation制限
プロダクトの実行環境 (Dev環境、Tes環境) 別に管理されたClusterがいる状況と仮定します。
プロダクト別にNamespace (foo
) 、プロダクトのサブチーム別にAppProject (app
、infra
) を用意します。
AppProjectテナントは、例えば 赤線 の方法で、ArgoCD系カスタムリソースに対するapplication-controllerのReconciliationを制限します。
ArgoCD系カスタムリソースをReconciliationできる場合
正しいNamespaceに対してReconciliationを実行する場合、AppProjectテナントはこれを制限しません。
(1) application-controllerは、argocd-cmd-params-cm
から自身がアクセスできるNamespaceを取得します。
apiVersion: v1 kind: ConfigMap metadata: name: argocd-cmd-params-cm namespace: foo data: # 設定しないことで、application-controllerは同じNamespaceにしかアクセスできなくなる。 # application.namespaces: "*"
(2) application-controllerは、同じNamespaceに所属するArgoCD系カスタムリソースに対して、Reconciliationを実行します。
(🚫制限例1) 無認可のNamespaceにReconciliationを実行しようとした場合
例えば、application-controllerがReconciliationの対象とするNamespaceを選ぼうとしているとします。
すると、application-controllerは内部で検証メソッドを実行し、無認可のNamespace (bar
) は選ばないようにします。
07. おわりに
KubernetesのマルチテナントパターンとArgoCDでのパターン実践をもりもり布教しました。
あらゆる面からマニフェストのデプロイを制限してくれる、AppProjectテナントの素晴らしさが伝わりましたでしょうか。
KubernetesのマルチテナントパターンをArgoCDでどう実践するべきか、について困っている方の助けになれば幸いです👍
謝辞
本記事のタイトルは、私が崇拝しているドメイン駆動設計の書籍 "実践ドメイン駆動設計" から拝借しました🙏
また、ArgoCDでのパターン実践の収集にあたり、以下の方からの意見も参考にさせていただきました。
@toversus26
さん
この場で感謝申し上げます🙇🏻