TECHSTEP

ITインフラ関連の記事を公開してます。

ArgoCD Server-side Applyを試す

今回は ArgoCD ver 2.5でBeta版になったServer-side Apply機能について簡単に触れてみます。

Server-side Applyとは

Server-side Applyは、Kubernetesでv 1.14から利用可能になった、リソースの作成・管理方法の1つです。

Kubernetesはリソースを宣言的手法で管理するコマンドとして kubectl apply を利用することができます。

リソースを宣言的に管理するための差分を検出・比較するのは、従来は kubectl コマンドが行っていました (Client-sdie Apply) 。この手法ではいくつかの課題が知られており、これを解決するための方法として Server-side Apply (以降 SSAと記載) という機能が実装されました。

SSAはリソースの管理に metadata.managedField というフィールドを使用します。このフィールドには、kubectlKubernetesコンポーネントなど、誰がこのリソースを管理・更新したのかを記録します。そして前回更新したのと別の誰かがフィールドを更新しようとすると、コンフリクトを発生させて上書きを防止します。

SSAの詳細な説明はこちらのドキュメント等をご確認ください。

ArgoCD Server-side Applyとは

さて、ArgoCDのドキュメントにもClient-side Applyでの課題は記載されており、大きく2つの課題が紹介されています。

  1. 管理するリソースのマニフェストファイルのサイズが巨大な場合: Kubernetesリソースのannotationsには、256kbのサイズ制限があります。Client-side Applyでは、差分管理のため、annotationの last-applied-configuration という値にリソースの状態を記録しています。そのためマニフェストのサイズが巨大になると256kbを超える場合があります(例: Fixing Argo CD “Too long must have at most 262144 bytes” error)。

  2. ArgoCDが完全には管理しないリソースにパッチを当てる場合: ArgoCDだけでなく、それ以外の方法でリソースを更新したい場合も、Server-Side Applyを適用したほうが管理しやすくなります。

ArgoCDのアップデートによりSSAが実装されたことで、これらの課題を解消することが期待できます。

ArgoCDでのSSA機能は、Application からリソースを作成・更新する時、対象のリソースにSSAを適用します。SSAの設定はArgoCDの Application リソースの定義で行い、 Application 適用後に kubectl apply 等で変更しようとすると、差分があればコンフリクトを返します。

なお、 ArgoCDから Application 経由でリソースを更新する際は、現在は差分があっても 強制的に更新されるようです( --force-conflicts オプションを付けて更新するようなイメージ)。

※参考: GitHub - argoproj/argo-cd: Server-Side Apply support for ArgoCD

ArgoCD Server-side Applyを試す

ここからArgoCD SSAを試してみます。今回は EKS ver.1.21上に ArgoCD ver 2.5をデプロイしています。

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.0", GitCommit:"c2b5237ccd9c0f1d600d3072634ca66cefdf272f", GitTreeState:"clean", BuildDate:"2021-08-04T18:03:20Z", GoVersion:"go1.16.6", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"21+", GitVersion:"v1.21.14-eks-fb459a0", GitCommit:"b07006b2e59857b13fe5057a956e86225f0e82b7", GitTreeState:"clean", BuildDate:"2022-10-24T20:32:54Z", GoVersion:"go1.16.15", Compiler:"gc", Platform:"linux/amd64"}

$ argocd version
argocd: v2.4.2+c6d0c8b
  BuildDate: 2022-06-21T21:03:41Z
  GitCommit: c6d0c8baaa291cd68465acd7ad6bef58b2b6f942
  GitTreeState: clean
  GoVersion: go1.18.3
  Compiler: gc
  Platform: linux/amd64
argocd-server: v2.5.1+504da42
  BuildDate: 2022-11-01T21:14:30Z
  GitCommit: 504da424c2c9bb91d7fb2ebf3ae72162e7a5a5be
  GitTreeState: clean
  GoVersion: go1.18.8
  Compiler: gc
  Platform: linux/amd64
  Kustomize Version: v4.5.7 2022-08-02T16:35:54Z
  Helm Version: v3.10.1+g9f88ccb
  Kubectl Version: v0.24.2
  Jsonnet Version: v0.18.0

今回はServer-side Applyを有効にした Application を作成し、SSAが適用されていることを確認します。ArgoCDでSSAを有効にするには、以下のように Applicationspec.syncPolicy.syncOptions に設定を追加します。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook-ssa
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/argoproj/argocd-example-apps.git
    targetRevision: HEAD
    path: guestbook
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  syncPolicy:
    syncOptions:
    - ServerSideApply=true

上記 app-ssa.yaml をデプロイします。

$ kubectl apply -f app-ssa.yaml
application.argoproj.io/guestbook-ssa created

デプロイ後Syncを行い、Statusを確認すると、作成されたDeploymentは annotations.last-applied-configuration がなく、 metadata.managedFiled が追加されていることが確認できます。

$ kubectl get deploy guestbook-ui -oyaml --show-managed-fields
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  creationTimestamp: "2022-11-05T03:22:23Z"
  generation: 1
  labels:
    app.kubernetes.io/instance: guestbook-ssa
  managedFields:
  - apiVersion: apps/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:labels:
          f:app.kubernetes.io/instance: {}
      f:spec:
        f:replicas: {}
        f:revisionHistoryLimit: {}
        f:selector: {}
        f:template:
          f:metadata:
            f:labels:
              f:app: {}
          f:spec:
            f:containers:
              k:{"name":"guestbook-ui"}:
                .: {}
                f:image: {}
                f:name: {}
                f:ports:
                  k:{"containerPort":80,"protocol":"TCP"}:
                    .: {}
                    f:containerPort: {}
    manager: argocd-controller
    operation: Apply
    time: "2022-11-05T03:22:23Z"

(以下割愛)

また、SSAの動きを確認するため、上記 Application で作られたDeploymentのイメージタグを事前に変更してから、 Application で指定するマニフェストファイルと同じ内容のファイルをapplyすると、想定通りコンフリクトが発生しました。

# edit前のイメージタグを確認
$ kubectl get deploy -oyaml | grep image:
        - image: gcr.io/heptio-images/ks-guestbook-demo:0.2

# kubectl editでイメージタグを変更
$ kubectl edit deploy guestbook-ui
deployment.apps/guestbook-ui edited

$ kubectl get deploy -oyaml | grep image:
        - image: gcr.io/heptio-images/ks-guestbook-demo:0.1

# kubectl applyで更新すると差分を検知してコンフリクトを発生
$ kubectl apply -f guestbook-ui-deploy.yaml --server-side
error: Apply failed with 1 conflict: conflict with "kubectl-edit" using apps/v1: .spec.template.spec.containers[name="guestbook-ui"].image
Please review the fields above--they currently have other managers. Here
are the ways you can resolve this warning:
* If you intend to manage all of these fields, please re-run the apply
  command with the `--force-conflicts` flag.
* If you do not intend to manage all of the fields, please edit your
  manifest to remove references to the fields that should keep their
  current managers.
* You may co-own fields by updating your manifest to match the existing
  value; in this case, you'll become the manager if the other manager(s)
  stop managing the field (remove it from their configuration).
See https://kubernetes.io/docs/reference/using-api/server-side-apply/#conflicts

なお ArgoCDからSyncをした場合は、上記イメージタグも上書きされることも確認できました。

# Syncして更新
$ argocd app sync guestbook-ssa
TIMESTAMP                  GROUP        KIND   NAMESPACE                  NAME    STATUS    HEALTH        HOOK  MESSAGE
2022-11-05T12:32:43+09:00            Service     default          guestbook-ui    Synced   Healthy
2022-11-05T12:32:43+09:00   apps  Deployment     default          guestbook-ui  OutOfSync  Healthy
2022-11-05T12:32:43+09:00   apps  Deployment     default          guestbook-ui    Synced  Progressing
2022-11-05T12:32:43+09:00            Service     default          guestbook-ui    Synced  Healthy                  service/guestbook-ui serverside-applied
2022-11-05T12:32:43+09:00   apps  Deployment     default          guestbook-ui    Synced  Progressing              deployment.apps/guestbook-ui serverside-applied

(以下割愛)

# イメージタグは元に戻った
$ kubectl get deploy -oyaml | grep image:
        - image: gcr.io/heptio-images/ks-guestbook-demo:0.2