LoginSignup
18
7

More than 3 years have passed since last update.

GitHubActions + ArgoCD + HELMを使ったGitOps手法でGKEへアプリをデプロイ

Last updated at Posted at 2020-12-12

この記事について

半年前からk8sの勉強を始め、GitOps手法でアプリをデプロイする知見を得ることができたので学んだことのまとめ記事です。

GitOps手法とは?

weave.worksが提唱する開発手法です。
https://www.weave.works/blog/gitops-operations-by-pull-request

GitOps is a way to manage systems like Kubernetes

訳: GitOpsは、Kubernetesなどのシステムを管理する方法です
・・・とあるようにk8sで構築するシステムの管理手法と考えて良いと思います。
実際にGitOpsのキーワードで色んな記事を読んできましたが、今の所k8s以外は見たことがありません。

リソースは基本的にGitで管理し、本番環境への反映はプルリクによる操作が望ましいとされています。
この記事でもソースを管理するアプリリポジトリとk8sのyamlを管理するマニフェストリポジトリの2つを使用して構築していきたいと思います。

今回構築する全体像について

構築する全体像は以下の通りです。
gitops.png

  • アプリはReact(create-react-app)を使用します
  • Nodeへのスケジューリング内容はあくまでイメージです。必ずしも図のように配置されるわけではありません
  • ArgoCDからデプロイされるk8sリソースについてもイメージです。HELMのカスタムValue(後述)の内容によってデプロイされるリソースも変わってきます
  • GCPのロードバランサーなど記事の内容と直接関係ない部分については省略しています

ではここからが本題です。全体像を区分けして解説していきます。

1. GitHubActionsを使用してDockerイメージをGCRへpush

まずはCIの部分を構築していきます。
gitops1.png

ここで使用する技術について

  • GitHubActions・・・GitHubのCIツールです。GitHubリポジトリでのイベントを検知してテストやDockerfileのbuild・pushなどのワークフローを実行できます。

  • GCR・・・GoogleContainerRegistryの略で、Dockerイメージのリポジトリサービスです。要はGCP版のDockerHubのようなもの。

アプリリポジトリについて

完成版はこちらになります。
https://github.com/Nishi53454367/gitops_app_create-react-app

create-react-app作成手順について

プロジェクト初期化手順はREADMEに記載してあります。
今回の記事の内容とは関係ないのでこちらの解説は割愛します。

Dockerfileについて

  • docker/Dockerfile.devは開発用コンテナです。docker-compose.ymlで使用しています
  • docker/Dockerfileがk8sのPodに配置するコンテナです。これをGitHubActionsのワークフローで使用します。ReactリソースをビルドしてNginxのデフォルトディレクトリにコピーしているだけの必要最小限の作りになっています

GitHubActionsワークフローについて

作成手順

GitHub上で対象リポジトリのActionsのタブを選択し、テンプレートを選択します。
今回は以下をベースに修正していきました。
スクリーンショット 2020-12-06 15.02.49.png
完成版は以下のようになっています。

.github/workflows/docker-image.yml
name: Docker Image CI

on:
  # mainブランチへのpushをトリガーにworkflowを実行
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

      # GCPプロジェクトの認証
    - name: GCP Authenticate
      uses: google-github-actions/setup-gcloud@master
      with:
        version: '290.0.1'
        project_id: ${{ secrets.GCP_PROJECT_ID }}
        service_account_key: ${{ secrets.GCP_SA_KEY }}
        export_default_credentials: true
    - name: Configure docker to use the gcloud cli
      run: gcloud auth configure-docker

      # Dockerfileのbuild
    - name: Build the Docker image
      run: docker build . -f docker/Dockerfile -t gcr.io/${{ secrets.GCP_PROJECT_ID }}/create_react_app:${{ github.run_number }}

      # DockerfileをGCRへpush
    - name: Push the docker image
      run: docker push gcr.io/${{ secrets.GCP_PROJECT_ID }}/create_react_app:${{ github.run_number }}
  • 「GCPプロジェクトの認証」の部分は以下を参考に作成しています
    https://github.com/google-github-actions/setup-gcloud/tree/master/setup-gcloud

  • GCP_PROJECT_ID、GCP_SA_KEYはこの名前の機密情報をGitHubのSecretsから取得します(後述)

  • GCRへDockerイメージをpushする時はホスト/プロジェクトID/{任意のイメージ名:任意のtag}でタグ付けをする必要があります。

    • ホストは米国内データセンターの「gcr.io」と「us.gcr.io」、欧州連合の「eu.gcr.io」、アジアのデータセンターの「asia.gcr.io」と何種類か選択できますが、今回は「gcr.io」を使用します
    • {任意のイメージ名:任意のtag}の部分はcreate-react-app:ワークフローの実行回数としています。任意のtagの部分は1からインクリメントされていきます

GCP上での作業

GCPプロジェクトについて

今回はgitops-react-app(プロジェクトIDも同様)という名前のプロジェクトを使用します。

GCRのAPIを有効化

メニューから「Container Registry」を選択して「Container Registry APIを有効化」を押してGCRを使用できる状態にしておきます。

サービスアカウントキー作成

メニューから「IAM と管理」→「サービス アカウント」を選択し、以下の内容でサービスアカウントを作成します。
スクリーンショット 2020-12-06 16.27.16.png
サービスアカウント名、説明の内容はなんでも大丈夫です。
IDはサービスアカウント名を元に自動入力されます。
スクリーンショット 2020-12-06 16.29.02.png
似たようなロールで「ストレージオブジェクト管理者」があるので注意です。

作成したサービスアカウントの右側のメニュー(「・・・」を縦並びにしたやつ)から「鍵を作成」でJSON形式を指定してダウンロードします。

GitHub上での作業

SecretsにGCP機密情報を設定

先ほど自分のマシンにダウンロードした鍵をbase64でエンコードします。

cat {ダウンロードした鍵のパスを指定} | base64

鍵本体もですがこの値も簡単にデコードできるので流出しないように注意してください。

この鍵のbase64エンコード値とGCPプロジェクトIDを.github/workflows/docker-image.ymlで使用しているSecrets名でGitHubのSecretsへ設定すれば準備は完了です。

GitHubリポジトリで「Settings」→「Secrets」→「New repository secret」で以下の内容で設定を行います。

Name Value
GCP_PROJECT_ID gitops-react-app
GCP_SA_KEY 鍵のbase64エンコード値

以下のように設定できればOKです。
スクリーンショット 2020-12-06 17.11.52.png
ここで設定した内容はUpdateを押しても現在の設定値を見ることができず、上書きという形での変更となっています。また、リポジトリをforkしても値が引き継がれることはありません。

動作確認

ではmainブランチへのpushでGCRへDockerイメージが登録されるか確認してみます。

この時点ではGCR上にはまだ何も登録されていません。
スクリーンショット 2020-12-06 17.00.30.png

任意の更新を行い、mainブランチへpushを行うと、GitHub上の「GitHubActions」タブでワークフローが実行されていることを確認できます。
こんな感じで緑のチェックマークが付いていることが確認できれば成功です。
スクリーンショット 2020-12-06 17.03.03.png
GCRを再度確認すると、Dockerイメージが登録されていることが確認できます。
スクリーンショット 2020-12-06 17.04.45.png
イメージを選択するとDockerイメージをpullする時に必要なリポジトリ情報が確認できます。
以下の部分をHELMのカスタムValue(後述)に設定するので控えておきます。

  • リポジトリ:gcr.io/gitops-react-app/create_react_app
  • タグ:3

タグはワークフローの実行回数を指定しているので、これは3回目の実行であることがわかります。
スクリーンショット 2020-12-06 17.06.10.png

以上でCIの設定・動作確認が完了です。

2. マニフェストリポジトリをArgoCDで監視

次にCDの部分を構築していきます。
gitops2.png

ここで使用する技術について

  • HELM・・・k8sリソースのテンプレートパッケージです。穴埋め方式のテンプレートとPodの数やDeploymentでpullするDockerイメージなど環境によって変更したい値の変数を組み合わせk8sリソースをデプロイすることができます。
    この変数を定義するファイルのことをこの記事内でカスタムValueファイルと呼んでいます。アプリケーションでいう環境変数ファイル(.env)と似たようなイメージです。
    環境に応じたカスタムValueファイルを用意しておくことで、STG環境と本番環境でyamlを1から準備する必要がなくなります。
    繰り返しになりますがHELMは穴埋め方式なので、カスタマイズ性が弱いと思います。(やろうとすると分岐だらけの複雑なテンプレートになりそう。)
    複数のアプリでテンプレートを使い回したいような時はKustomizeの方が適していると思います。

  • ArgoCD・・・k8sクラスタにインストールして使用するpull型のCDツールです。
    使い始めて間もないですが、GUIもわかりやすくk8s初学者にとっても使いやすいツールだと思います。

マニフェストリポジトリについて

完成版はこちらになります。
https://github.com/Nishi53454367/gitops_manifest_helm

HELM作成手順について

プロジェクト初期化手順はREADMEに記載してあります。
create helmコマンドを使用して作成すると、deploymentテンプレートがデフォルトでポート80をListenしているシングルPodの構成となっています。
今回は特別な修正を加えなくてもReactアプリをビルドしたNginxコンテナをこのPod内に配置してあげるだけでOKですが、実際にはアプリケーションの構成に合わせた修正が必要になると思います。

カスタムValueファイルについて

今回はカスタムValueファイルは1つだけ作成しています。
実際には「開発用、STG用、本番用」や「サービスA用、サービスB用」など複数用意するケースが多いと思います。
カスタムValueに定義がないとcreate helmした時に作成されるvalues.yamlがデフォルト値となります。よって、values.yamlを見ればどんな値をカスタムで設定できるか確認できます。
もちろんtemplates配下を修正して任意の名前でセットできるように修正も可能です。

今回作成したカスタムValueファイルは以下の通りです。最小限の設定です。

create-react-app-values.yaml
# Pod
replicaCount: 1

# DockerImage
image:
  repository: gcr.io/gitops-react-app/create_react_app
  tag: "3"

# Service
service:
  type: LoadBalancer

DockerImageの部分はCI構築時に確認したDockerリポジトリの情報をセットします
GCRはprivateリポジトリですが、同じGCPプロジェクト内で構築したGKE上で使用するので認証は不要でDockerイメージをpullできます。

ちなみにファイル名はxxxvalues.yamlの形式にしておかないとArgoCD管理画面で設定する時(後述)に候補として出てこなかったので、このルールでファイルを作成しておきます。

GCP上での作業

GKEでクラスタを作成

メニューから「Kubernetes Engine」を選択し、以下の内容でクラスタを作成します。
節約のため以下の通りにしていますが、今回の記事の内容とは関係ないので、好きに変更して問題ありません。

  • ゾーンはus-west1-a
  • マシンタイプは全てe2-small
  • プリエンティブルノード有効

クラスタへArgoCDインストール

作成したクラスタを選択して「接続」を押し、CloudShell接続を行い、以下のコマンドを実行していきます。

ArgoCD用のネームスペースを作成

kubectl create namespace argocd

ArgoCDインストール

Non-HA構成の場合(今回はこっちでやります)

kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

HA構成の場合

kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v1.0.1/manifests/ha/install.yaml

ArgoCD管理画面を外部から接続できるようにpatch

インストールが終わったら以下のコマンドを実行

kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'

ArgoCD管理画面上での作業

ログイン

メニューの「Kubernetes Engine」→「Services と Ingress」を選択してargocd-serverのエンドポイントをクリックしてArgoCDの管理画面を起動します。オレオレ証明書なので警告出ますが続行すると以下の画面が表示されます。
スクリーンショット 2020-12-06 21.06.42.png
Usernameは、admin
Passwordは、ArgoCDのPod名がデフォルトのパスワードになっています

CloudShellで以下のコマンドを実行することで一覧表示されるargocd-server-xxxxxのPod名がパスワードになっています。

kubectl get pods --namespace argocd

マニフェストリポジトリ設定

左側のメニューで歯車マークを選択し、「Repositories」を選択します。
スクリーンショット 2020-12-06 21.17.28.png
「CONNECT REPO USING HTTPS」を選択し、リポジトリの内容を設定します
スクリーンショット 2020-12-06 21.19.31.png
Repository URLにマニフェストリポジトリのURLを入力して「CONNECT」を押します。
リポジトリがprivateの場合は、GitアカウントのUsernameとPasswordに入力すれば接続できます。※1
スクリーンショット 2020-12-06 21.22.00.png
以下のようになれば設定完了です。
スクリーンショット 2020-12-06 21.25.13.png

アプリ作成

スクリーンショット 2020-12-06 21.28.53.png
「NEW APP」を選択し、以下の内容で作成を行います。

GENERAL

スクリーンショット 2020-12-06 21.31.12.png
Application Nameは、任意の名前でOKです。この名前がデプロイされるk8sリソース名に使用されます。

SOURCE

スクリーンショット 2020-12-06 21.33.01.png

  • Repository URLは先ほど設定したマニフェストリポジトリを選択します
  • Revisionは監視対象のブランチを指定します。今回はmainブランチとしています
  • PathはRevisionを入力するとカレントディレクトリにHELMテンプレートが格納されているので、「.」が選択できるようになります。ここで候補値として「.」が出てこない場合、どこか設定が誤っている可能性があります。

DESTINATION

スクリーンショット 2020-12-06 21.38.13.png
Namespaceは今回指定しないのでdefaultにします。

HELM

スクリーンショット 2020-12-06 21.42.36.png
VALUES FILESの部分でカスタムValueファイルが選べるようになっているので、デプロイしたい内容のファイルを選択します。

ここまでの内容で「CREATE」を押すと以下のカードが作成されます。
スクリーンショット 2020-12-06 21.46.30.png
これでデプロイの手前までが完了です。

3. ArgoCDでデプロイ

では最後にデプロイを行います。
引き続きArgoCD管理画面で操作します。
gitops3.png

デプロイ実行

作成したカードを選択し、「SYNC」を押します。
スクリーンショット 2020-12-06 21.48.31.png
続けて「SYNCHRONIZE」を押すとデプロイが始まります。
スクリーンショット 2020-12-06 21.49.49.png
しばらく待って以下のようになれば完了です。
スクリーンショット 2020-12-06 21.52.10.png

接続確認

メニューの「Kubernetes Engine」→「Services と Ingress」を選択するとArgoCDでデプロイしたリソースcreate-react-app-webが追加されています。

エンドポイントをクリックするとReactの初期ページを開くことができます。
スクリーンショット 2020-12-06 21.57.17.png
これで一通り完了です。

ArgoCDでデプロイしたリソースであれば、ステータスやイベントログなどArgoCDの管理画面上で確認できます。もちろんkubectlコマンドでの操作も可能です。

変更内容の反映

マニフェストリポジトリを変更するとArgoCDが変更を検知します。
試しにカスタムValueファイルで定義しているPod数を変更してpushします。

create-react-app-values.yaml
# Pod
replicaCount: 3 # ここを1から3に変更

# DockerImage
image:
  repository: gcr.io/gitops-react-app/create_react_app
  tag: "3"

# Service
service:
  type: LoadBalancer

ArgoCDは一定間隔でマニフェストリポジトリを監視しているので、しばらく待っているとステータスがOutOfSyncに変わります。(「REFRESH」を押して即時にOutOfSyncに変更することも可能です。)
スクリーンショット 2020-12-06 22.12.32.png

この状態で先ほどと同様に「SYNC」→「SYNCHRONIZE」するとデプロイが行われ、Podが3つ増えます。
スクリーンショット 2020-12-06 22.17.04.png
カスタムValueファイルを変更しただけですが、当然templates配下を変更しても検知されます。

アプリの変更を反映したい場合は、
アプリ修正してアプリリポジトリへpush

GitHubActionsのワークフローによってGCRへ新しいタグのDockerイメージが登録
(ワークフローの実行回数をタグに含めているのでタグが3から4にインクリメントされる)

あとは同じ要領でカスタムValueファイルを変更してデプロイするだけです。

カスタムValueの修正例

create-react-app-values.yaml
# Pod
replicaCount: 3

# DockerImage
image:
  repository: gcr.io/gitops-react-app/create_react_app
  tag: "4" # ここを3から4に変更

# Service
service:
  type: LoadBalancer

まとめ

今回まとめたのは基本的な使い方のみでしたが、実際にチームで運用する時は、Dockerイメージのタグ付けルールやDBのマイグレーションのタイミングなどなど検討しないといけないことはたくさんあります。運用事例は今後色んな記事を読んだりして勉強したいと思っています。

また、ArgoCDはまだまだ知らない機能が多いと思うので、今後もっと使い込んでいきたいと思います。GUIベースでの操作でしたが、CLI操作も可能なので何か他のサービスと組合わせてデプロイをもっと効率化できないかなーとかも思ったり。

以上、GitHubActionsとArgoCDとHELMを使用したGitOps手法の構築でした。

追記

※1 GitHubではパスワードを使用した認証は将来的に廃止されます。
https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/
したがってGitHubのprivateリポジトリへの認証はGitHub側で発行したアクセストークンを使用するようにしてください。
ArgoCDへのアクセストークンの設定方法は以下の公式ページの通り。
https://argoproj.github.io/argo-cd/user-guide/private-repositories/#access-token
基本的にPassword欄に発行したアクセストークンを設定するだけです。

18
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
7