TT Lab
はじめる
学ぶ 学習パス コース

CAPA — Argoプロジェクト認定アソシエイト

ホワイトリストとブラックリストは向きが逆だ

TT Labで続きを見る

一言でいうと

AppProjectは、「このチームがどこから取得して、どこに置けるか」を決める境界で、ApplicationSetは、その境界の中でApplicationを大量に作り出す工場です。AppProjectで最も間違えやすいのは、クラスターリソースは許可リスト(書かれたものだけを許可)で、ネームスペースリソースは拒否リスト(書かれたものだけを禁止)という、方向が逆の2つのフィールドです。

なぜ必要なのか

Argo CDにチームが1つしかないときは、defaultプロジェクトで十分です。チームが3つになった瞬間に、疑問が生まれます。Aチームが誤ってBチームのネームスペースにデプロイしたら、どうなるでしょうか。誰かが個人のGitHubリポジトリをソースとして登録したら。アプリ1つがClusterRoleBindingを作って、自分でcluster-adminになったら。RBACだけでは、これを防げません。Argo CDのServiceAccountは、どのみち強い権限を持っており、ユーザーはArgo CDを通して、その権限を借りて使う構造だからです。そのため、Argo CDは、自分の階層で、もう一度ふるいにかけます。そのふるいがAppProjectです。

ApplicationSetは、別の種類の苦痛から生まれました。クラスター5つに、サービス20個なら、Applicationは100個です。手で管理することはできず、新しいクラスターが加わるたびに、20個をコピーしなければなりません。ジェネレーターは、この繰り返しをデータに変えます。

どう動くのか

AppProjectの主要なフィールドは、方向まで一緒に覚える必要があります。

フィールド 方向 意味
sourceRepos 許可リスト ここに書かれたパターンのリポジトリだけを、ソースとして使えます
destinations 許可リスト ここに書かれたクラスター・ネームスペースにだけ、デプロイできます
clusterResourceWhitelist 許可リスト ここに書かれたクラスタースコープの種類だけを、作れます
namespaceResourceBlacklist 拒否リスト ここに書かれたネームスペーススコープの種類だけを、作れません

3つ目と4つ目が逆です。クラスターリソースは、デフォルトが全面禁止なので、Namespaceだけを書けば、それだけが開きます。ネームスペースリソースは、デフォルトが全面許可なので、ResourceQuotaを書けば、それだけが閉じます。この方向を取り違えると、「塞いだと思っていたものが開いている」状態になり、ポリシーがないよりも悪いです。

syncWindowsは、時間帯で同期を開閉します。ルールを1つだけ覚えれば十分です。denyがallowに勝ちます。平日の業務時間のallowと、週末のdenyが重なると、重なった区間は禁止です。manualSync: trueを付けると、そのウィンドウでは自動同期を止め、人が押すものだけを許可します。

ApplicationSetのジェネレーターは、list(静的なリスト)、clusters(登録されたクラスター)、git(ディレクトリのスキャンまたはファイルの読み取り)、pullRequest(PRプレビュー)、scmProvider(組織のリポジトリの自動検出)が基本で、そこに2種類の組み合わせ器が付きます。matrixは、2つのジェネレーターの直積なので、クラスター3つとアプリ4つなら12個が出ます。mergeは、mergeKeysで結合して、同じキーを持つ項目の値を上書きします。全クラスター共通の値を敷いて、特定のクラスターだけ違う値を与えるときに使うのが、mergeです。

テンプレートエンジンのデフォルトはfasttemplateで、これは変数の置換だけを行います。条件や繰り返しが必要なら、spec.goTemplate: trueを有効にする必要があり、有効にした瞬間に、参照の文法もドットの付いた形に変わります。goTemplateOptionsにmissingkey=errorを指定すると、存在しないキーを黙って空文字列にする代わりにエラーを出し、名前が空のApplicationができる事故を防いでくれます。

app-of-appsは、Applicationが、ほかのApplicationを含むディレクトリを指すパターンです。ブートストラップ1回で、プラットフォーム全体が立ち上がる代わりに、親を削除すると、子がすべてpruneの対象になるため、親のprune設定に特に注意する必要があります。

現場での姿

筆者のホームラボは、クラスターが1つですが、ネームスペースでテナントを分けています。ここで学んだことは、AppProjectが描く境界と、実際のリソースの境界は、別物だという点です。AppProjectのdestinationsは、「capa-team-alphaにデプロイしてよい」という文法上の許可にすぎず、そのネームスペースがノードのリソースをどれだけ消費するかは、まったく制御できません。リソースの境界は、ResourceQuotaとLimitRangeが作ります。そして、AppProjectのnamespaceResourceBlacklistにResourceQuotaを入れるのが定石である理由が、ここから出てきます。テナントが自分のクォータを自分で増やしてしまえば、クォータではないからです。クォータはプラットフォームチームが作り、テナントは触れないようにするのが、この2つのフィールドの組み合わせです。

GPUノードが混在するクラスターでは、さらに一歩進めました。GPU Feature Discoveryが付けてくれるラベルは文字列なので、「24GB以上」のような比較セレクターが使えないため、ノードにgpu.homelab/tierのような、意味ベースのラベルを自分で付けて、ワークロードが自分の規模を選べるようにしました。ApplicationSetのlistジェネレーターに、テナントごとにこのようなラベル値を載せて送れば、1つのテンプレートで、異なるノードグループに載るアプリを作り出せます。

次のラボですること

/root/capa-project/に、AppProjectを1つと、ApplicationSetを2つ(listジェネレーター、matrixジェネレーター)作成し、そのプロジェクトが許可するテナントのネームスペース3つと、それぞれのResourceQuotaを、実際のクラスターに載せて、文法上の境界とリソースの境界を、並べて立ててみます。