GitOps とは?

近年 Kubernetes の導入事例が増えたことにより、Kubernetes への継続的デリバリーの手段・ツールも様々なものがあります。

CircleCI のような CI/CD ツールを利用して Kubernetes へのデプロイまで一貫した CI/CD パイプラインを作ることも可能ですが、FluxCD そして今回紹介する ArgoCD など CD 専用の OSS ツールと組み合わせる事例も増えてきました。

これらの CD 専用ツールは GitOps を採用している点が共通点として挙げられます。

GitOps とは 2017年に Weaveworks 社がブログ内で紹介した CD の手法 です。

GitOps では、Git を用いて Kubernetes のリソース構成情報を宣言的に記述・管理します。

GitOps によるメリットは下記などが挙げられます。

生産性の向上

Git の操作(コミット、承認など)によって Kubernetes リソースを管理することができるため、これまでのアプリケーション開発と同じような変更プロセスを適用することができます。

デプロイのロールバックも git revert して Pull Request を作成・承認することで実現することができます。

また、手動による kubectl コマンドなどの実行をする必要がなくなります。

可視性の向上

Git を信頼できる唯一の情報源(Single Source of Truth)としているため、コミット履歴を元に誰が・いつ・どのような操作をしたのか簡単に把握することができるようになります。


GitOps の実現手段ですが、例えば マニフェストを Git に置いた上で CircleCI 経由で Kubernetes に変更を適用することによって GitOps を実現することも可能です。

実際に CircleCI を使って GitOps を実現した事例もありますので、参考にしていただければと思います。

GitOpsの概要と実践例 〜Kustomize + CircleCI編〜 - CADDi Tech Blog

このような GitOps は Push 型と呼ばれています。

Push 型の GitOps の場合には、ツールに Kubernetes API を操作するクレデンシャルを渡す必要があります。


対して FluxCD や ArgoCD は Pull 型の GitOps ツールと呼ばれています。

Pull 型の GitOps ツールは Kubernetes から Git への定期的なポーリングを行うことで差分を検知し、変更を適用します。

この Pull 型 の GitOps ツールの場合には、Kubernetes API を操作するクレデンシャルを渡す必要がない点がメリットになります。

そのため、CI/CD ツールに Kubernetes API を操作するクレデンシャルを渡したくない場合には Pull 型の GitOps ツールを利用するのをお勧めします。

その場合に CI/CD パイプライン を実現させるためには、CI と CD を以下のように分割します。

ArgoCD と組み合わせた CI/CD パイプライン
ArgoCD と組み合わせた CI/CD パイプライン(Argo Project Blog より)


CI(CircleCI)

  • テスト(ユニット、インテグレーション、E2E)・静的解析・脆弱性診断など
  • Docker イメージのビルド、Container Registry へのプッシュ
  • マニフェストの Docker イメージタグを変更する Pull Request を作成する

CD(FluxCD、ArgoCD)

  • (上記の Pull Request を承認・マージする)
  • Git ポーリングによって Git の差分を検知する
  • Kubernetes クラスタに変更を適用する


今回は実際に CircleCI を CI として、そして GitOps CD ツールの1つである ArgoCD を利用してこちらを実現したいと思います。

ArgoCD を使って Kubernetes へデプロイする

今回は GitOps ツールとして ArgoCD を使います。

Argo CD は他の GitOps ツールと比べ、GUI がある点が特徴です。

GUI を通して設定や状態の確認、手動での Sync などを行うことが可能です。

デモサイトも用意されています。


ArgoCD による継続的デリバリーを実現するため、まず Kubernetes クラスターに ArgoCD をインストールします。

インストール手順に関しては、公式のドキュメント を参考にしていただければと思います。

今回展開するレポジトリはこちらになります。

https://github.com/tadashi0713/circleci-demo-gitops-manifest

Application の登録が完了し、Sync を実行すると、レポジトリにあるマニフェストを元に展開・更新されます。

gitopsデモのCircleciアプリケーション

手動で Sync させることも可能ですが、Sync Policy を Automatic にすることによって、Git での変更を自動で展開・更新することも可能です。

CircleCI と組み合わせて CI/CD パイプラインを構築する

先ほどのステップだけでは、Kubernetes マニフェストを展開しただけで CI/CD パイプラインとしては完成していません。

次は実際にアプリケーションのビルドから Kubernetes へのデプロイまでの CI/CD パイプラインを作成します。

今回用意した、アプリケーションコードのレポジトリ・設定ファイルはこちらになります。

build_and_push_image ジョブではアプリケーション(Next.js)の Docker ビルド、そして Google Container Registry(GCR) への Push まで行います。

build_and_push_image:
  machine:
    image: ubuntu-2004:202111-01
    docker_layer_caching: true
    resource_class: large
  steps:
    - checkout
    - gcp-gcr/gcr-auth
    - gcp-gcr/build-image:
        image: circleci-demo-gitops
        tag: '${CIRCLE_SHA1:0:7}'
        registry-url: asia.gcr.io
    - gcp-gcr/push-image:
        image: circleci-demo-gitops
        tag: '${CIRCLE_SHA1:0:7}'
        registry-url: asia.gcr.io

CircleCI の機能を使って最適化している部分をいくつか紹介します。

まず、CircleCI の Docker レイヤーキャッシュ機能を使って、Docker ビルドの高速化を行っています。

また、このジョブでは Docker ビルドを行うために Linux VM が使われています。

今回は、この Linux VM のリソースクラスを large にすることで、Docker ビルドの高速化を行っています。

最後に、Docker ビルド・GCR への Push をまでの手順を GCR の CircleCI Orb を使うことで簡潔に記述しています。

gitopsデモのCircleciアプリケーション

CircleCI では GCR だけでなく、AWS ECRAzure ACR の Orb も用意されています。

build_and_push_image ジョブが完了すると、次に create_release_pr ジョブが走ります。

create_release_pr ジョブでは、Kubernetes マニフェストの image タグを今回リリースする新しいタグに変更し、GitHub に Pull Request を作成します。

まず、マニフェスト側のリポジトリをcloneする必要があります。

そのため、今回は通常の checkout コマンドではなく、GitHub CLI Orb を使い clone を行います。

steps:
  - github-cli/setup
  - github-cli/clone:
      repo: git@github.com:tadashi0713/circleci-demo-gitops-manifest.git

事前に CircleCI には GitHub の Token($GITHUB_TOKEN) を環境変数として設定する必要があります。

そして、対象の image タグを変更します。

- run:
    name: Edit manifest file using yq
    command: |
      wget -q https://github.com/mikefarah/yq/releases/download/v4.16.2/yq_linux_386
      sudo mv yq_linux_386 /usr/local/bin/yq
      sudo chmod +x /usr/local/bin/yq
      yq e -i '.spec.template.spec.containers[0].image |="asia.gcr.io/'${GOOGLE_PROJECT_ID}'/circleci-demo-gitops:'${CIRCLE_SHA1:0:7}'"' deployment.yaml

image タグの変更には、yq コマンドというYAML ファイルを編集するための jq コマンドのラッパーを利用しています。

次にこのファイル変更に対してブランチを作成し、git push を行います。

- add_ssh_keys:
    fingerprints:
      - $SSH_KEY_FINGERPRINT
- run:
    name: Commit file
    command: |
      git config --global user.email "gitops@example.com"
      git config --global user.name "GitOps Bot"
      git remote set-url --push origin git@github.com:tadashi0713/circleci-demo-gitops-manifest.git
      git checkout -b release-${CIRCLE_SHA1:0:7}
      git add .
      git commit -m"Release circleci-demo-gitops-app ${CIRCLE_SHA1:0:7}"
      git push origin HEAD

CircleCI において、デフォルトで生成・登録している SSH key は対象レポジトリの read only です。

そのため、マニフェストのレポジトリに git push を行うためには以下2点の設定を行う必要があります。

デプロイキーとユーザーキーの例

最後に gh(github-cli) コマンドを利用し、マニフェストがあるレポジトリに Pull Request を作成します。

前段の Step で既に github-cli の認証は行っているため、追加で認証を行う必要はありません。

- run:
    name: Create Pull Request
    command: gh pr create -t "Release circleci-demo-gitops-app ${CIRCLE_SHA1:0:7}" -b ""

成功すると、マニフェスト側のリポジトリに Pull Request が作成されているのが確認できます。

gitopsデモのCircleciアプリケーション

この Pull Request を merge することで、ArgoCD による継続的デリバリーに繋げることができます。

おわりに

今回は、GitOps(ArgoCD)による、Kubernetes への継続的デリバリーについて紹介しました。

Kubernetes へ継続的デリバリーの方法を検討していた方の参考になれば幸いです。

CircleCI では今回紹介した機能以外にも、CI(継続的インテグレーション)における高速化・開発生産性・可視化における様々な機能を提供しています。

そのため、ArgoCD と組み合わせることによって、品質の高い Kubernetes アプリケーションを継続的に開発できると考えています。


また、CircleCI では 2021 年に Vamp 社を買収し、現在リリースオーケストレーション機能の開発を行っています。

こちらも今後のソリューションの1つとして検討していただければと思います。