👻

Argo CD ApplicationSetを削除するとpolicyによらずApplicationが削除される

2023/12/11に公開

この記事は Kubernetes Advent Calendar 2023 の 11日目の記事です。


12/11時点で最新のv2.9.3でも修正されていない(=どのバージョンでも発生する)、ApplicationSetに関する不具合について書いています。

https://github.com/argoproj/argo-cd/issues/12172

ApplicationSet

ApplicationSetはApplicationを抽象化することで、Applicationの作成で楽ができるかもしれないカスタムリソースです。

  • spec.sourceを抽象化
    • sourceを抽象化すると、単一のApplicationSetからリポジトリ内の複数の異なるファイルまたはディレクトリを指したApplicationを生み出したり、複数の異なるrepoURLを指すApplicationを生み出すことができます。
  • spec.destinationを抽象化
    • destinationを抽象化すると、単一のApplicationSetから複数のクラスター宛のApplicationを生み出すことができます。

基本はsourcedestinationの抽象化で、アプローチの違いにより何種類ものgeneratorがあります。

ApplicationSet (Controller) のpolicy

https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Controlling-Resource-Modification/

applicationset-controllerには4種類のpolicyのいずれかを設定することができます。
policyの説明は現時点(2023/12/11)のstable版ドキュメントに基づき和訳しています。

  • create-only: ApplicationSet コントローラーがアプリケーションを変更または削除できないようにします。
  • create-update: ApplicationSet コントローラーがアプリケーションを削除できないようにします。更新は許可されています。
  • create-delete: ApplicationSet コントローラーがアプリケーションを変更できないようにします。削除は許可されています。
  • sync: 更新と削除が許可されます。

policyはコントローラーの引数で指定するか、argocd-cmd-params-cm ConfigMapのapplicationsetcontroller.policyで制定します。
公式Helmチャートではconfigs.params."applicationsetcontroller.policy" valueで指定できます(デフォルトはsync)。

「削除できない」policyでもApplicationが削除される?

policycreate-onlycreate-updateに設定したうえでApplicationSetを削除すると、そこから生まれたApplicationは削除されてしまいます。

現在のpolicyの意味

現在のpolicyはあくまで 「ApplicationSetコントローラーが」 アプリケーションを削除するかどうかを制御できます。

「ApplicationSetコントローラーによる」Applicationの削除

ApplicationSetコントローラーがApplicationを削除するのは 「ApplicationSetの削除以外」 で必要ができたときに限られます。

Git generatorを使ったApplicationSetの例で考えます。

  generators:
  - git:
      repoURL: https://github.com/argoproj/argo-cd.git
      revision: HEAD
      directories:
      - path: applicationset/examples/git-generator-directory/cluster-addons/*

cluster-addonsを覗くと2つのディレクトリがあります。
cluster-addons

そのため、このApplicationSetからは2つのApplicationが生み出され、それぞれのspec.source.pathは以下のようになります。

  • applicationset/examples/git-generator-directory/cluster-addons/argo-workflows
  • applicationset/examples/git-generator-directory/cluster-addons/prometheus-operator

ここから、以下のような場合にApplicationを削除する必要が生じます。

リポジトリが変更されたとき

prometheus-operatorディレクトリを削除した場合、ApplicationSetからApplicationを生成しなおすとargo-workflowsディレクトリに対応した1個だけになります。
一方クラスターにはprometheus-operatorディレクトリに対応するApplicationが残っているため、ApplicationSetコントローラーはこれを削除することになります。

ApplicationSetが変更されたとき

prometheus-operatorディレクトリを除外する条件をgeneratorに書き足した場合も、ApplicationSetからApplicationを生成しなおすとargo-workflowsディレクトリに対応した1個だけになるため、Applicationの削除が起こります。

      directories:
      - path: applicationset/examples/git-generator-directory/cluster-addons/*
      - path: applicationset/examples/git-generator-directory/cluster-addons/prometheus-operator
        exclude: true

ApplicationSetを削除したとき、Applicationを削除しているのは誰?

Applicationコントローラーが削除しています。

ApplicationSetから生み出されたApplicationにはmetadata.ownerReferencesフィールドが書き込まれており、Kubernetesのガベージコレクションの仕組みにしたがって削除されます。
policyはこれには影響がありません。

ownerReferences

https://kubernetes.io/docs/concepts/overview/working-with-objects/owners-dependents/

https://kubernetes.io/docs/concepts/architecture/garbage-collection/

Applicationを残してApplicationSetを削除する方法

ownerReferencesを使ったガベージコレクションの仕組みに則っているため、削除リクエストのcascadeオプションを入力すればApplicationを残してApplicationSetを削除することが可能です。

kubectl delete appset foobar --cascade=orphan

https://kubernetes.io/docs/tasks/administer-cluster/use-cascading-deletion/

とはいえ、ややこしい…

policyによって制御される「削除」と制御されない「削除」があるということは、それぞれの削除が発生する経緯を紐解いていくとわかるのですが、ややこしく感じます(GitHubでissueを起票した時点では私も正確に理解していませんでした)。
結局、この動作は仕様ではなく不具合であると認定され、正しい動作は
「ApplicationSetの削除時も、policycreate-only/create-updateの場合はApplicationを削除しないようにする」であると定義されました。

policyの適用範囲をApplicationSetの削除にも広げる

正しい動作をさせるためには、ApplicationSetの削除時にpolicyを参照し、create-onlyまたはcreate-updateの場合にはApplicationからownerReferencesフィールドを削除する必要があります。
以下のプルリクエストでその修正を行いました。

https://github.com/argoproj/argo-cd/pull/15903
https://github.com/argoproj/argo-cd/pull/16506

Discussion