EKS環境へArgo CD Image Updaterを導入し、デプロイ時間と管理コストを削減した話

ogp

はじめに

こんにちは、計測プラットフォーム開発本部SREブロックの渡辺です。普段はZOZOMATやZOZOGLASSなどの計測技術に関わるシステムの開発、運用に携わっています。

先日私達のチームでは、Argo CDと拡張ツールArgo CD Image Updaterを導入した開発環境のCDリアーキテクトを行いました。本記事では、開発環境のCI/CDリアーキテクト設計とArgo CD Image Updaterの導入手順について紹介します。

目次

Argo CDとArgo CD Image Updaterについて

Argo CDは、Kubernetes環境でのGitOpsを実現するためのCDツールです。Gitリポジトリで管理しているKubernetesマニフェストを監視して、Kubernetesクラスターに適用します。

Argo CD Image UpdaterとはArgo CDの拡張ツールで、デプロイされたコンテナイメージを最新のバージョンに自動更新します。こちらはイメージを管理しているリポジトリを監視して、条件に一致した最新のイメージを検知した場合にKubernetesクラスターのコンテナイメージを更新します。

Argo CD Image Updater導入前の課題

計測プラットフォーム開発本部のプロダクトのインフラ基盤は、EKS on Fargateで運用しており、Skaffoldを用いたデプロイを行っていました。また、GitHubで管理しているアプリケーションのリポジトリにKubernetesマニフェストも含まれていました。

例として、ZOZOMATの開発環境CI/CDアーキテクチャを下図に示します。

図1 既存の開発環境CI/CDアーキテクチャ

以下のような流れになります。

  1. 対象ブランチをCircleCIのブランチフィルターの定義に追記する
  2. 1.をコミットし、GitHubに変更をpushする
    • CircleCIのイメージビルド用のジョブが発火する
    • skaffold buildを実行し、イメージをビルドしてECRにpushする
    • ビルド時に生成されたイメージタグが記録されたjsonファイル(以下、イメージタグファイルとする)をS3にアップロードする
  3. ビルド完了を待ち、CDをトリガーするスクリプトを実行する
    • CircleCIからCodePipelineのソースS3にソースコードをアップロードする
    • CodeBuildがソースとイメージタグファイルをS3から取得し、Skaffoldを使ってapplyする
  4. 作業完了後、2のコミットを消す

「イメージタグファイル」について補足します。イメージビルド時にSkaffoldの--file-outputオプションを利用してイメージタグをファイルに記録しS3へ配置します。デプロイ時にS3のイメージタグファイルをダウンロードし、Skaffoldの--build-artifactsオプションでファイルを指定することで適切なタグ情報によるデプロイを実行しています。

このフローには、いくつかの問題点がありました。

  • 各開発者の作業量が多く、デプロイまでに多くの時間を要する
  • デプロイ先の環境を指定してCD用スクリプトを実行するため、オペレーションミスによりステージングや本番環境のCDが実行される
  • 作業手順が複雑でツールも散在しているため、リバースエンジニアリングしづらく、他プロダクトへの横展開も難しい

特に作業開始からデプロイまでの時間の長さがネックでした。

また、計測プラットフォーム開発本部は複数のプロダクトを管理しているため、CI/CDは全て統一されることが望ましい状態と言えます。しかし、現状は各プロダクトで異なる手順となっているため、管理コストも大きな課題となっていました。

Argo CD Image Updater導入による開発環境CI/CD設計

前述の課題を解決するために、まずは開発環境にArgo CDと拡張ツールArgo CD Image Updaterを導入することで、デプロイ時間の短縮を図りました。Argo CD導入後の開発環境のCI/CDアーキテクチャを下図に示します。

図2 Argo CD Image Updater導入後のCI/CDアーキテクチャ

ここでは深く言及しませんが、GitOpsではアプリケーションのソースコードとKubernetesマニフェストを分けて管理することが推奨されています。このため、既存のGitHubリポジトリからKubernetesマニフェストを抜き出し、別GitHubリポジトリで管理するよう対応しました。

以下のような流れになります。

  1. 開発者が対象ブランチを設定したGitHub Actionsの手動ワークフローを実行する
    • イメージをビルドしてECRにpushする
    • Argo CD Image UpdaterがECRリポジトリのイメージを検知する
    • Argo CDが新しいイメージのPodを自動デプロイする

開発者が行う作業は、任意のタイミングでGitHub Actionsを手動実行するだけです。ブランチを指定するだけで開発環境用のイメージがECRに配置されます。

Argo CD単体では、GitHub上のソースコードを更新する必要があるため、Pushしたイメージタグに更新するロジックが必要になります。そこで、Argo CD Image Updaterを導入し、よりスピーディな開発環境へのデプロイを実現します。レジストリに新しいイメージが追加された際に、自動で新しいイメージをデプロイすることが可能になります。

従来の方法では、ビルドしたイメージがECRに配置されるのを待ってからデプロイを行う必要がありました。待っている間に別の作業をしているとついビルドの完了に気づくのが遅れてしまい、結果的にデプロイも遅れるという悩みがメンバー間でありました。自動デプロイによりこうした悩みも解決できました。

承認フローや厳格なGitOpsを求めない開発環境にこそArgo CD Image Updaterは強力なツールとして開発をサポートしてくれます。

導入手順

ここからは、Argo CD Image Updaterの導入手順について紹介していきます(Argo CDは公式ドキュメントを参考に導入しました)。

  • Argo CD Image UpdaterのECR操作権限設定
  • Argo CD Applicationの設定

Argo CD Image UpdaterのECR操作権限設定

Argo CD Image UpdaterがECRリポジトリのイメージタグ情報を取得するため、認証周りの設定が必要になります。ここでは、認証に必要な各リソースについて説明します。

IAMRoleの作成とPodへのアタッチ

KubernetesのServiceAccountでIAM Roleを使用するには、クラスター用のIAM OIDCプロバイダーが必要です。クラスター用のIAM OIDCプロバイダー作成後、CloudFormationでIAMRoleを作成します。

  IAMRoleArgoCDImageUpdater:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: 'argocd-image-updater'
      AssumeRolePolicyDocument: !Sub |
        {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/oidc.eks.<リージョン>.amazonaws.com/id/xxxxxxxxxxxxxx"
              },
              "Action": "sts:AssumeRoleWithWebIdentity",
              "Condition": {
                "StringEquals": {
                  "oidc.eks.<リージョン>.amazonaws.com/id/xxxxxxxxxxxxxx:sub": "system:serviceaccount:<argocd-image-updaterを配置するKubernetes namespace名>:<argocd-image-updaterに設定するServiceAccount名>"
                }
              }
            }
          ]
        }
      Path: '/'
      Policies:
        - PolicyDocument:
            Statement:
            - Effect: 'Allow'
              Action:
                - 'ecr:GetAuthorizationToken'
                - 'ecr:ListImages'
                - 'ecr:BatchGetImage'
                - 'ecr:GetDownloadUrlForLayer'
              Resource: '*'
          PolicyName: 'argocd-image-updater-ecr'

そして、Argo CD Image UpdaterのServiceAccountに作成したIAMRoleをアタッチします。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: argocd-image-updater
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::<AWSアカウントID>:role/argocd-image-updater

これでArgo CD Image UpdaterにECRリポジトリのタグを取得する権限を付与できました。

PodのECR認証トークン発行

Argo CD Image Updaterがスクリプトを実行し、クレデンシャルを設定する方法で実装しました。

registries.confにはレジストリやスクリプトを設定し、ecr-login.shにはECRの認証トークンを発行するスクリプトを設定しています。

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-image-updater-config
data:
  registries.conf: |
    registries:
      - name: ECR
        api_url: https://<AWSアカウントID>.dkr.ecr.<リージョン>.amazonaws.com
        prefix: <AWSアカウントID>.dkr.ecr.<リージョン>.amazonaws.com
        credentials: ext:/app/scripts/ecr-login.sh
        credsexpire: 10h
  ecr-login.sh: |
    #!/bin/sh
    aws ecr --region <リージョン> get-authorization-token --output text --query 'authorizationData[].authorizationToken' | base64 -d

argocd-image-updaterのDeploymentに上記ConfigMapで作成したecr-login.shをマウントします。これにより、Argo CD Image Updaterがecr-login.shを実行できます。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: argocd-image-updater
spec:
  template:
    spec:
      containers:
        - name: argocd-image-updater
          volumeMounts:
            - name: ecr-login-script
              mountPath: /app/scripts
      volumes:
        - name: ecr-login-script
          configMap:
            defaultMode: 0755
            items:
              - key: ecr-login.sh
                path: ecr-login.sh
            name: argocd-image-updater-config
            optional: true

なお、マウントしたConfigMapのファイルの権限はデフォルトで0644なので、defaultMode: 0755と設定しています。デフォルトのままではecr-login.shが実行できず、ECRの認証トークンが発行されないので注意してください。

Argo CD Image Updaterリソースの展開(kustomizeの設定)

私達のチームは環境ごとの差分を管理しやすくするためにkustomizeを用いています。開発環境ディレクトリのkustomization.ymlを以下のとおり設定し、Argo CD Image Updaterと上記で作成したリソースをEKS環境に展開します。

namespace: argocd
resources:
  - https://raw.githubusercontent.com/argoproj-labs/argocd-image-updater/stable/manifests/install.yaml
patchesStrategicMerge:
  - configmap.yml # ConfigMap
  - deployment.yml # Deployment
  - rbac.yml # ServiceAccount

Argo CD Applicationの設定

Argo CD Image Updater管理下に置くApplicationのmetadata.annotationsを以下のとおり設定します。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    argocd-image-updater.argoproj.io/write-back-method: argocd
    argocd-image-updater.argoproj.io/image-list: my-image=<AWSアカウントID>.dkr.ecr.<リージョン>.amazonaws.com/<リポジトリ>
    argocd-image-updater.argoproj.io/my-image.update-strategy: latest
    argocd-image-updater.argoproj.io/my-image.ignore-tags: latest

    省略

write-back-methodにargocdを設定することで、GitHubのソースコードを更新せずに最新のイメージをデプロイできます。

今回私達のチームはArgo CDの特徴であるGitOpsの原則を崩していますが、承認フローなしでソースコードを変更されることに抵抗感があったからです。

一方、write-back-methodにgitを設定するとGitHub上でデプロイするイメージタグを確認できるメリットがあります。こちらはチームの運用などを考慮して選択すると良いと思います。

update-strategyにはlatestを設定し、最新の作成日でタグを更新するようにしています。また、ignore-tagsにlatestを設定しlatestタグを除外しています。

この他にも柔軟な設定ができるので、詳しくは公式ドキュメントを参照してください。

動作確認

以下のコマンドで動作を確認できます。

kubectl exec -it <ArgoCD Image Updater Pod> -- argocd-image-updater test <AWSアカウントID>.dkr.ecr.<リージョン>.amazonaws.com/<リポジトリ> --credentials ext:/app/scripts/ecr-login.sh --registries-conf-path /app/config/registries.conf

リアーキテクト前後の比較

リアーキテクト前 リアーキテクト後
デプロイ時間 約8分 3分以内
開発者の作業数 2 1
利用するツール CircleCI, CodePipeline, CodeBuild, Shell Script, Skaffold GitHub Actions, Argo CD, Argo CD Image Updater
オペレーションミスの可能性 別環境へデプロイする可能性あり 別環境へデプロイする可能性なし
横展開のしやすさ ×

Argo CDの変更チェックをデフォルトの3分に設定しているので、リアーキテクト後のデプロイ時間を3分以内としています。

これまでCodeBuildで行っていたデプロイ処理をArgo CDに移行したことで、約5分デプロイ時間を短縮できました。CodeBuildでの各種ツールのダウンロードに要していた時間を削減できたことが一番の要因です。

また、Argo CD Image Updaterを導入したことで、GitHubへのソース変更ロジックを自前で管理せずに済んだのは横展開しやすい大きな要因になります。同じEKSクラスターで管理する他プロダクトに同様の仕組みを導入するためには、各プロダクトのArgo CD Applicationにてアノテーションを追加するだけで完了します。

まとめ

開発環境にArgo CDとArgo CD Image Updaterを導入したことで、デプロイ時間の短縮と管理コストを抑えることができました。

Argo CDを導入しているが、GitHubのコードを変更せずに自動でイメージのデプロイを行いたい、という開発環境の要求にはArgo CD Image Updaterがピッタリのツールでした。

AWS環境での導入に関しては、公式ドキュメントだけでは難しい部分(特にECR認証トークン発行)もありますが、本記事が導入の手助けになれば幸いです。

なお、Argo CD Image Updater導入を進める途中でv0.12.0がリリースされました。この中でイメージ変更コミットつきブランチを作成する機能も追加されたので、今後は承認フローが必要な本番環境での導入も検討していきたいと思います。ブランチ戦略やリリース手順の統一化などやるべきこともたくさんありますが、SREチームのメンバーと協力しながらやり遂げたいと思います。

終わりに

計測プラットフォーム開発本部では、今後もZOZOFIT等の新しいサービスのローンチを予定しています。更にスピード感を持った開発が求められますが、このような課題に対して楽しんで取り組み、サービスを一緒に盛り上げていける方を募集しています。少しでもご興味のある方は以下のリンクからぜひご応募ください。

hrmos.co

カテゴリー