Closed5

Argo CDとAWS Load Balancer Controllerに起因するWorkflow失敗

mikutasmikutas

登場人物

Workflow = Argo Workflowsによって利用可能なカスタムリソースで、バッチ処理に使っている

できごとの流れ

  • AWS Load Balancer ControllerをデプロイするApplicationのキャッシュミス
  • AWS Load Balancer Controllerチャートのhelm template実行
  • helm templateの結果、自動生成される証明書に差分が生じ、Syncが必要だとArgo CDが判断
  • Syncが実行され完了する
  • コンテナ内の証明書ファイルが更新される前にPod作成リクエストが送られ、Webhook呼び出しが失敗し、Podの作成が拒否される

失敗防止の方法

  • WebhookのobjectSelector / namespaceSelectorで本当に必要なPodのみWebhook呼び出しの対象にする
  • 一時的なエラーのためWorkflow側で自動リトライする
    • ただし、1回だけのリトライでは早すぎてまだコンテナ内の証明書が更新されていなかった。複数回リトライするのがよさそう
    • retryStrategy.backoffも活用する
    • https://argoproj.github.io/argo-workflows/retries/
  • 微妙) WebhookのFailure PolicyをIgnoreにする
    • 今回作成を拒否されたPodはPod Readiness Gateを利用する意図はなかったので、Workflowの失敗は流れ弾ではある(別にそのWebhookが失敗しようがどうでもいいからPod作成させてよと)。たしかにFailure PolicyがIgnoreであればWorkflowが失敗させられることはなかったが、Ignoreに設定してしまうと今度はReadiness Gateを利用したいPodで機能が有効にならないリスクが生じる。
    • 一度は微妙と書いたが、「Pod作成できない」と「Pod作成できるがReadiness Gateは有効ではない」だと前者のほうが困り度が高いので悪くはない
  • 微妙)証明書の自動生成を利用せず自前で管理する
mikutasmikutas

アラート

WorkflowのイベントWorkflowFailed を監視していたところアラートが鳴った。

WorkflowNodeError -> WorkflowNodeFailed -> WorkflowFailed の流れで発生したようだ。

発端のWorkflowNodeErrorの内容はこうだった。

Internal error occurred: failed calling webhook "mpod.elbv2.k8s.aws": Post "https://aws-load-balancer-webhook-service.kube-system.svc:443/mutate-v1-pod?timeout=10s": x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "aws-load-balancer-controller-ca")

同じ内容がworkflow-controllerのログにも出力されていた(WARNログ)。

これはAWS Load Balancer ControllerによるMutating Admission Webhookが失敗したためにPodの作成が拒否され、Workflowが進行不能となったことを意味する。

mikutasmikutas

Podの作成が拒否された理由

WebhookのFailure PolicyがFailに設定されているため(Ignoreであった場合はWebhookが失敗してもPodの作成は拒否されない)。

これはMutatingWebhookConfigurationwebhooks.failurePolicyフィールドに書かれている。

Webhookの失敗理由

クライアント(kube-apiserver)が期待するauthorityと、サーバー(aws-load-balancer-controller)が提示した証明書のauthorityが違っていたため。

クライアントが期待するauthorityとは、MutatingWebhookConfigurationwebhooks.clientConfig.caBundleフィールドのこと。

サーバーが提示する証明書のauthorityは、aws-load-balancer-tlsというSecretdata.ca.crtフィールドのこと(コンテナでこのSecretをマウントしている)。

authorityが違っていた理由

AWS Load Balancer ControllerのWebhook用証明書の管理方法にはいくつか選択肢があるが、MutatingWebhookConfigurationcaBundleSecretca.crtの中身は一致するようにHelmチャートは作られているので、これらの内容が違っていることは本来はないはずである。

ただ、この2つが一致していてもエラーが発生しうるケースがある。

SecretやConfigMapをコンテナ内にファイルとしてマウントすると、コンテナの再作成をしなくてもSecretやConfigMapの更新は自動的にコンテナ内のファイルへ反映されるが、反映には1分ほどのタイムラグがある。

今回、このラグの間にWebhook呼び出しが行われたことにより、エラーを引き起こした。

以下のログ時系列から、そのように判断した。

  • Sep 04 15:02:57.184 argocd-application-controllerでApplicationのSync中のログ
    • 具体的なログupdated 'アプリケーション名' operation (phase: Running)
  • Sep 04 15:02:58.184 ApplicationのSync完了のログ
    • 具体的なログupdated 'アプリケーション名' operation (phase: Succeeded)
  • Sep 04 15:03:00.886 workflow-controllerでfailed calling webhookのログ

ただし、9月4日は日曜日で、ApplicationをSyncした覚えはない。

mikutasmikutas

休日に勝手にSyncされた理由

証明書が生成される仕組み

AWS Load Balancer ControllerをHelmチャートを利用してデプロイする場合、特定の条件下ではWebhookに使用する証明書が自動的に生成される。

https://github.com/aws/eks-charts/blob/490f14ac7ac502d687691923b037f90648343137/stable/aws-load-balancer-controller/templates/_helpers.tpl#L109

特定の条件とは、

.Values.webhookTLS.caCert .Values.webhookTLS.cert .Values.webhookTLS.keyを入力していない
https://github.com/aws/eks-charts/blob/490f14ac7ac502d687691923b037f90648343137/stable/aws-load-balancer-controller/templates/_helpers.tpl#L99

.Values.keepTLSSecretを入力していない(※追加条件あり)
https://github.com/aws/eks-charts/blob/490f14ac7ac502d687691923b037f90648343137/stable/aws-load-balancer-controller/templates/_helpers.tpl#L103

我々の環境は「特定の条件」に合致していた(=上記どちらの分岐にも入らなかった)ので、デプロイのたびに証明書は再生成されることになる。

追加条件について

.Values.keepTLSSecretはv2.3.0でデフォルトfalseで導入されたフラグで、v2.4.0でデフォルトtrueに変更された。

https://github.com/aws/eks-charts/pull/616

https://github.com/aws/eks-charts/pull/695

我々はデフォルト値のまま使用していたので、エラー発生時点ではフラグはtrueだった。

フラグがtrueであり、Helmのtemplate function lookupがクラスター上のSecretを取得できる場合には証明書の生成が行われず、すでにあるものが利用されるが、

lookupHelmコマンドを直接利用する場合のうち、さらに限定されたケースでのみ機能するため、Argo CDを使ってHelmチャートをデプロイする我々の環境では常に再生成が行われていた。

具体的にはArgo CDがhelm templateを実行するたびに再生成され、「DiffがあるのでSyncしますね」となる。

helm templateが実行された理由

ApplicationのtargetRevisionにはブランチ名を指定しており、先頭のコミットが更新された場合はキャッシュが無効化されhelm templateが実行されるが、日曜日なので誰もpushしていない。

application-controllerのapp-hard-resyncオプションも使っていない。

が、repo-serverのログを見てみると普通にキャッシュミスが起きただけだった。

  • Sep 04 15:02:55.038 manifest cache miss ログ
  • Sep 04 15:02:57.025 helm template 実行ログ

キャッシュに関してデフォルトの設定で利用しており、リポジトリ全体のキャッシュ(repo-serverの--default-cache-expirationフラグ)は24時間、リビジョンのキャッシュ(argocd-cmのtimeout.reconciliation)は3分で期限切れになる。

このスクラップは2022/09/22にクローズされました