見出し画像

Helm Chart・ArgoCDを利用したkubernetesのDeploy管理

こんにちは。Lisse開発チームのテックリードの中嶋です。

弊社の契約書レビューサービスLeCHECKのサーバー基盤はAWS EKS、kubernetes環境を利用しています。kubernetesを利用する際に「yamlファイルをどのようにまとめるか」「どこでバージョン管理するか」などファイルの管理が問題になったり、またどのようにCDを実現させるかという課題も出てくると思います。

この記事ではLeCHECKで採用しているkubernetes環境のDeploy管理についてお話ししたいと思います。

HelmChart

kubernetes環境へのDeployでもっともベーシックな方法はyamlファイルを直接applyする方法です。

kubectl apply -f deployment.yaml

もちろん管理リソースが増えてくるとyamlファイルも大量になるためこれらのファイルを「どこで」「どのように」管理するのかが課題になります。LeCHECKではHelmChartを用いて管理しています。

Helmはkubernetesリソースのパッケージ管理マネジャーです。例えばkubernetes環境にwordpressをインストールしたいときは

helm install my-release oci://registry-1.docker.io/bitnamicharts/wordpress

のようにhelmコマンドからwordpressをインストールすれば必要なkubernetesのリソース、deployment、configmapやserviceなどすべてをインストールすることができます。HelmはChartというフォーマットを用いてこれらのリソースを管理しています。wordpressの例だと以下のような書式になっています。

https://artifacthub.io/packages/helm/bitnami/wordpress

{{ }}で囲ってある値はvalues.yamlというリソースファイルに渡る値を定数として管理しているファイルから読み取って動的に挿入されます。コンテナのリポジトリ名やtagなどは直接リソースファイルに記述せずvalues.yamlで定数を一箇所で管理・まとめることで変更が反映が容易になります。

https://artifacthub.io/packages/helm/bitnami/wordpress

HelmChartの作り方はとても簡単でcreateコマンドでアプリを作成すると以下のようにChartが作成されます。

$ helm create my_app
$ cd my_app 
$ tree .

├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml

作成したChartをHelm installすれば自身の環境にInstallすることができます。マイクロサービスの場合はchartsディレクトリ配下に同じようにChartsを作成すれば複数アプリを一つのChartで管理することができます。LeCHECKのChartはCronjobやDBマイグレーションJobなど、同じCluster内で実行されるアプリケーションリソースを以下のように1つのChartでまとめて管理しています。

.
├── Chart.lock
├── Chart.yaml
├── README.md
├── charts
│   ├── cronjob
│   │   ├── Chart.yaml
│   │   └── templates
│   │       ├── _helpers.tpl
│   │       ├── cronjob1.yaml
│   │       ├── cronjob2.yaml
│   ├── server1
│   │   ├── Chart.yaml
│   │   └── templates
│   │       ├── _helpers.tpl
│   │       ├── deployment.yaml
│   │       └── service.yaml
│   ├── server2
│   │   ├── Chart.yaml
│   │   └── templates
│   │       ├── _helpers.tpl
│   │       ├── deployment.yaml
│   │       ├── service.yaml
│   │       └── target-group-binding.yaml
│   └── migrate-job
│       ├── Chart.yaml
│       └── templates
│           ├── _helpers.tpl
│           └── job.yaml
├── values-dev.yaml
├── values-prod.yaml
└── values-stg.yaml

このChartはアプリケーションリソースのみを管理しており、例えばnamespaceやservice accountなどのリソースは含まれていません。これらのリソースは別途EKS Clusterを作成する際のIaCで定義していますので、リソースが増える時・変更するときはSREチームとの協力が必要不可欠です。

さて、このChartをどこで管理するかですが、HelmのホームページではGCSやS3などCloudのStorageやGithub Pagesなど選択肢が紹介されていますがLisseではHelm ChartはGitHubで管理しています。

GitOps

Gitを信頼できる唯一の情報源としアプリやインフラを管理することをGitOpsと言いますが、これに倣いLisseではアプリ・Chart・インフラリソース(IaC)はすべてGithubで管理しています。Githubに統一することで開発チームメンバーがアクセスしやすく、学習コストを抑えて運用できるメリットがあります。

Chartレポジトリは環境ごとにブランチをわけており、開発環境ではdevelopブランチのChart、本番環境ではmainブランチのChartが反映されるようにしています。Chartの変更ですが、サーバーが増えるなど直接リソースyamlファイルの修正が必要になるときを除いて、通常リリースに伴うコンテナイメージタグの修正はCIで自動で行っています。

現在CIはCodeBuildを利用しているのでそのCIスクリプト内にgit、hubやyqをインストールしてvalues.yamlに記載の該当のイメージタグの変更を行います。実際のScriptはこんな感じです

- echo Build Docker image
- docker build -t $REPOSITORY_NAME:$CODEBUILD_RESOLVED_SOURCE_VERSION .
- docker tag $REPOSITORY_NAME:$CODEBUILD_RESOLVED_SOURCE_VERSION $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION


- echo Clone chart repository
- git clone -b $CHART_BRANCH ${GIT_HUB_REPOSITORY}
- cd chart
- |
  if [ "$ENV" = "dev" ] || [ "$ENV" = "stg" ] ; then
    echo Replace image tag in values.yaml
    yq eval --inplace '.image.tag=env(CODEBUILD_RESOLVED_SOURCE_VERSION)' $ValuesYaml
    echo Create commit to chart repository
    git commit -am "update image tag"
    git push origin $CHART_BRANCH
  else
    git checkout -b update-image-$REPOSITORY_BRANCH-$CODEBUILD_RESOLVED_SOURCE_VERSION
    yq eval --inplace '.image.tag=env(CODEBUILD_RESOLVED_SOURCE_VERSION)' $ValuesYaml
    echo commit to chart repository...
    git commit -am "update image tag"
    git push origin update-image-$REPOSITORY_BRANCH-$CODEBUILD_RESOLVED_SOURCE_VERSION
    echo creating a pull request...
    hub pull-request -m "Image Updated" -b $CHART_BRANCH
  fi

開発・検証環境は直接変更をPushし自動でDeployが走るようにしていますが、本番環境はDeployは現在スプリントごとに決まった時間に行うため手動でSyncできるようにPushではなくPRを作成しています。

以上のように、HelmChartとGithub管理により常に最新の変更がChartレポジトリに反映されるようになります。ChartのDeployについてはArgoCDを活用しています。

ArgoCD

ArgoCDはkubernetesのCDツールとしてもっとも有名なOSSかと思いますが、Chartを管理しているGithubレポジトリをArgoCDアプリと同期させることによりGithubで管理しているChartをソースとしてDeployすることができます。

// argocdにレポジトリ情報を登録
$ argocd repocreds add {{GIT_HUB_REPOSITORY}} --username {{name}} --password {{token}}
// アプリをdeploy
$ kubectl apply -f application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my_app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: {{GIT_HUB_REPOSITORY}}
    targetRevision: {{TARGET_BRANCH}}
    path: ./

  destination:
    server: https://kubernetes.default.svc
    namespace: default

上記のようにargocdにレポジトリ情報を登録して、sourceにGithubのレポジトリ、ブランチを指定したapplicationをapplyします。Chartレポジトリの対象ブランチに修正が入ると差分をキャッチして差分をSyncすることが可能になります。

ArgoCDではAutoSyncを有効にすれば差分がでた時点で自動でSyncが走るので開発・検証環境ではAutoSyncを有効にして完全に自動でDeployをさせています。

ArgoCDは他にもHooksというリソースのdeployを調節できる機能があります。例えばDBマイグレーションジョブはアプリの入れ替えより前に実行される必要がありますが、PreSync hookを利用すれば必ずこのJobが先に実行されるようになります。

apiVersion: batch/v1
kind: Job
metadata:
  generateName: schema-migrate-
  annotations:
    argocd.argoproj.io/hook: PreSync

またArgoCDはアプリのステータスをキャッチして通知する機能があるので開発者はSlack通知でDeploy状況を確認できます。まだまだ利用できていない機能が多いですが、GUIもわかりやすく非dev-opsエンジニアでも扱いやすいためkubernetes運用には欠かせないツールです。

CICD全容

さて、ここまで説明した機能を活用して、LeCHECKサーバーのCICDの全容は以下の図のようになっています。

  1. アプリリポジトリの修正を検知してCI(CodePipeline)が走る

  2. CodeBuildでBuildしたImageをECRにPush

  3. Chartレポジトリのvalues.yamlに記載のImage tagの更新を行う

  4. ArgoCDでSyncを行う

Chartレポジトリのブランチ管理やプロダクトが増えた時のChart管理など、まだ課題が残るところはありますが、Githubでの統一管理、Deployの自動化を通してより開発者が開発に集中できるような仕組みをこれからも模索していきたいと思います。

この記事が少しでも役に立てば嬉しいです。お読みいただきありがとうございました!


一緒に働くメンバーを募集中!

株式会社リセでは、一緒に働くメンバーを募集しています。
カジュアル面談では、30分間お時間をいただき、会社・チーム・プロダクトのご紹介や色々なご質問にお答えします💁‍♂️
皆さんとお話しできることを楽しみにしています!

  • 株式会社リセで募集している開発ポジションはこちら↓

  • こちらからもお好きな日程でカジュアル面談を設定できます↓