🎃

GitLab と Google Cloud を連携して CI/CD パイプラインを構築する

2024/09/27に公開

はじめに

こんにちは、クラウドエースの岸本です。
今回は、GitLab と Google Cloud を連携して CI/CD パイプラインを構築する手順をご紹介します。

モチベーションとしては、以下があります。

特に DevSecOps プラットフォームとしての GitLab を活用し、前回執筆した【あなたもできる】Google Cloud で CI/CD パイプラインを構築をさらに実践的に活用できるようなパイプラインを構築していきたいと考えています。

使用するプロダクト

今回使用する主なプロダクトは以下の通りです。

GitLab

  • SCM in GitLab
    SCM は Source Code Management の略で、ソースコードの管理を行うためのツールです。
    GitLab は、SCM として利用することができるツールの 1 つです。
    SCM は GitLab 以外にも、GitHub や Bitbucket などがあります。
    詳しくは、SCM in GitLab の公式ドキュメントを参照してください。

  • GitLab CI/CD
    GitLab CI/CD は、GitLab に統合された CI/CD パイプライン機能です。
    プロジェクト内のソースコードの変更を検知し、自動的にビルドやテスト、デプロイを行うことができます。
    GitLab CI/CD の特徴としては、並列にビルドが実行できることや、マルチプラットフォームでジョブを実行できることが挙げられます。
    詳しくは、GitLab CI/CD の公式ドキュメントを参照してください。

Google Cloud

  • Google Cloud IAM
    Identity and Access Management は、Google Cloud リソースへのアクセス権を管理するためのサービスです。
    IAM を使用することで、「誰が」、「何を」、「どのようなアクセスできるか」を制御することができます。
    今回使用する Workload Identity は、IAM を使用してオンプレミス環境やマルチクラウドのワークロードなどの外部 ID に対して IAM ロールを付与するためのサービスです。
    詳しくは、Workload Identity の公式ドキュメントを参照してください。

  • Cloud Run
    Cloud Run は、コンテナ化されたアプリケーションをホスティングできるサービスです。
    Cloud Run は、サーバーレスであり、コンテナのスケーリングを自動で行うため、コストを抑えることができます。
    今回は、CI/CD パイプラインの最終ステージとして Cloud Run にデプロイすることを想定しています。
    詳しくは、Cloud Run の公式ドキュメントを参照してください。

構築

以下の手順で進めていきます。

    1. GitLab と Google Cloud の連携
    1. アプリケーションコードの作成
    1. CI/CD パイプラインの定義ファイル作成
    1. CI/CD パイプラインの実行

1. GitLab と Google Cloud の連携

連携するプロダクトは Google Cloud IAM と Artifact Registry です。
はじめに、Google Cloud IAM との連携を行います。

1-1. Google Cloud IAM との連携と権限設定

GitLab プロジェクト画面の Settings > Integrations > Google Cloud IAM を選択します。
1-1

1. Connection2. Set up workload identity federation が表示されます。

1. Connection は以下のように入力します。

項目 設定値
Project ID Google Cloud のプロジェクト ID を入力
Project number Google Cloud のプロジェクト番号を入力
Pool ID Google Cloud の Workload identity pool ID を入力
Provider ID Google Cloud に設定されるプロバイダ ID を入力
  • Project ID は Google Cloud のプロジェクト ID を入力します。
  • Project number は Google Cloud のプロジェクト番号を入力します。
    Google Cloud のダッシュボード画面から確認できます。
  • Pool ID は Google Cloud の Workload identity pool ID です。
    Pool ID は外部 ID を管理するための ID です。
    迷った場合は、サジェストでも表示されますが、GitLab のプロジェクト ID を入力します。
  • Provider ID は Google Cloud のコンソール画面に設定されるプロバイダ ID になります。
    迷った場合は、GitLab からの連携のため、GitLab と入力します。

次に、2. Set up workload identity federation です。
1. Connectionで設定した情報を元に、コマンドが自動で作成されます。
コマンドをコピーし、Google Cloud の Cloud Shell からコマンドを実行します。

Google Cloud の Cloud Shell でコマンドを実行し、GitLab の Google Cloud IAM 設定画面で「Save Changes」をクリックします。
以上で、GitLab と Google Cloud の連携が完了しました。
GitLab のプロジェクト画面の Settings > Integrations にて、Google Cloud IAM が追加されていることを確認します。
【GitLab の Google Cloud IAM 連携画面】
1-2

Google Cloud コンソール画面から IAM & Admin > Workload Identity Pools にて、GitLab が追加されていることを確認します。
【Google Cloud の Workload Identity Pools 画面】
1-3

最後に、Google Cloud IAM で、GitLab に対して権限を設定します。
Workload Identity で紐付けられたアカウントはprincipalSet://で始まります。
そのアカウントに権限を付与します。
【Workload Identity で紐付けられたアカウントと与えるロール】
1-5

与えるロールとアカウントは以下です。

ロール
  • Artifact Registry Writer
    Artifact Registry にイメージを保存するための権限
  • Cloud Run Admin
    Cloud Run にデプロイするための必要な権限
  • Service Account User
    サービスアカウントを使用してリソースにアクセスするための権限
アカウント
  • principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID/attribute.developer_access/true

詳細については、公式ドキュメントを参照してください。

1-2. Artifact Registry との連携

Artifact Registry との連携を行います。
これは、GitLab で作成されたイメージを Artifact Registry に保存するための連携です。
はじめに、保存先となる Artifact Registry のリポジトリを作成します。
以下のコマンドでリポジトリを作成します。

gcloud artifacts repositories create REPOSITORY_NAME \
    --repository-format=docker \
    --location=asia-northeast1 \
    --project=PROJECT_ID

その後、GitLab の画面で Google Cloud IAM と同様に GitLab プロジェクト画面の Settings > Integrations > Google Artifact Management を選択します。
1. Repository は以下のように入力します。

項目 設定値
Google Cloud project ID Google Cloud のプロジェクト ID を入力
Repository name Artifact Registry のリポジトリ ID を入力
Repository location Artifact Registry のリージョンを入力
  • Google Cloud project ID は Google Cloud のプロジェクト ID を入力します。
  • Repository name は Artifact Registry のリポジトリ ID を入力します。
    リポジトリ ID は、Artifact Registry で作成したリポジトリのフルパスを入力します。
  • Repository location は Artifact Registry のリージョンを入力します。
    今回は asia-northeast1 で作成しているため、asia-northeast1 を入力します。

2. Set up permissions は Google Cloud のコンソール画面でコマンドを実行します。
GitLab のコンポーネントが Artifact Registry にアクセスするための権限を設定します。
GitLab の画面上にあるコマンドをコピーし、Google Cloud の Cloud Shell からコマンドを実行します。

gcloud projects add-iam-policy-binding PROJECT_ID \
  --member='principalSet://iam.googleapis.com/projects/PORJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID/attribute.developer_access/true' \
  --role='roles/artifactregistry.writer'

詳細については、公式ドキュメントを参照してください。

2. アプリケーションコードを作成

ブラウザに Hello World と表示するだけのアプリケーションコードを作成します。
また、特定のブランチにコミットすると、GitLab CI/CD パイプラインが実行されるように設定します。

はじめに、ブランチを作成します。
その後、作成したブランチにアプリケーションコードをコミットします。

2-1. ブランチの作成

ブランチは Code > Branches > New branch を選択し、ブランチ名を入力することで作成できます。
今回は、feature/001 ブランチを作成します。
3-1

2-2. アプリケーションコードの作成

次にアプリケーションコードを作成します。
GitLab リポジトリをクローンして、ローカルでコーディングすることも可能ですが、今回は簡単なデモのためブラウザ上でファイルを追加、編集する機能を利用します。
src ディレクトリを作成し、その中に 「index.html」、「Dockerfile」 を作成します。

Repository > + > New directory を選択し、src と入力します。
これで、src ディレクトリが作成されました。
次に、src ディレクトリを選択し、+ > New file を選択し、ファイル名に「index.html」と入力します。
同じ手順で「Dockerfile」を作成します。

「index.html」 ファイルに以下のコードを記述します。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Simple HTML Page</title>
  </head>
  <body>
    <h1>Hello World</h1>
  </body>
</html>

「Dockerfile」ファイルに以下のコードを記述します。

Dockerfile
# Pythonイメージをベースにする
FROM python:3.9-slim

# 作業ディレクトリを設定
WORKDIR /app

# index.htmlを作業ディレクトリにコピー
COPY index.html .

# ポート8080を開放
EXPOSE 8080

# http.serverモジュールを使ってHTTPサーバを起動
CMD ["python", "-m", "http.server", "8080"]

作成した、「index.html」、「Dockerfile」 ファイルを保存します。

3. CI/CD パイプラインの定義ファイル作成

次に、GitLab での CI/CD パイプラインを定義する「.gitlab-ci.yml」ファイルを作成します。
記述する内容は、大きく分けて以下の 3 つです。

    1. Docker イメージをビルドし、GitLab container registry に Push
    1. GitLab container registry に保存された Docker イメージを Artifact Registry に Push
    1. Artifact Registry に保存された Docker イメージを Cloud Run にデプロイ

GitLab リポジトリのルートディレクトリに「index.html」、「Dockerfile」を作成した際と同様の手順で、「.gitlab-ci.yml」ファイルを作成します。
作成後のディレクトリ構成は以下の通りです。

.
├── src
│   ├── index.html
│   └── Dockerfile
└── .gitlab-ci.yml

次に、「.gitlab-ci.yml」ファイルに環境変数を設定し、上記の 3 つの処理を記述します。

3-1. .gitlab-ci.yml 初期設定

「.gitlab-ci.yml」に以下の内容を記述します。

stages:
  - build
  - push
  - deploy

variables:
  GITLAB_IMAGE: $CI_REGISTRY_IMAGE/hello-world:$CI_COMMIT_SHORT_SHA
  GOOGLE_AR_REPO: GOOGLE_CLOUD_ARTIFACTS_REPOSITORY_FULL_PATH
  GOOGLE_PROJECT: GOOGLE_CLOUD_PROJECT_ID
  GOOGLE_REGION: asia-northeast1
  CLOUD_RUN_SERVICE: hello-world
  • stages は、CI/CD パイプラインのステージを定義します。今回は、buildpushdeploy の 3 つのステージを定義しています。
    ステージは、1 つまたは複数のジョブを含むことができます。
    例えば、build ステージでアプリケーションの Docker イメージを作成するジョブを実行し、push ステージで Artifact Registry にプッシュするジョブを実行することができます。
    詳しくは公式ドキュメントを参照してください。
  • variables は、CI/CD パイプラインで使用する変数を定義します。
    今回は、Docker イメージのタグ名や Google Cloud のプロジェクト ID などを定義しています。
    GOOGLE_CLOUD_ARTIFACTS_REPOSITORY_FULL_PATHGOOGLE_CLOUD_PROJECT_ID を Artifact Registry のパスと Google Cloud のプロジェクト ID に書き換えます。
    詳しくは公式ドキュメントを参照してください。

次に、各ステージでの処理を記述します。

3-2. Docker イメージのビルドと GitLab container registry への Push

# Image build and push to GitLab container registry
image-build:
  image: docker:24.0.5
  stage: build
  services:
    - docker:24.0.5-dind
  rules:
    - if: '$CI_COMMIT_REF_NAME =~ /^feature\//'
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    - docker build -t $GITLAB_IMAGE hello-world/
    - docker push $GITLAB_IMAGE
    - docker logout
詳細
  • image-build は、ジョブの名前を定義します。
    これは、Docker イメージをビルドし、GitLab container registry に Push するジョブです。
  • image は、ジョブを実行する Docker イメージを指定します。
    今回は、Docker イメージのバージョンを指定しています。
  • stage は、ジョブが属するステージを指定します。
    今回は、build ステージに属するジョブとして定義しています。
  • services は、追加の Docker イメージを指定します。
    GitLab では、ジョブの実行に GitLab Runner というアプリケーションが使われており、GitLab Runner は Docker Executor を利用してコンテナ上でジョブを実行します。
    今回のジョブでは、コンテナ内で Docker コマンドを使用するため Docker-in-Docker (dind) 手法を採用しています。
    そのイメージとして、docker:24.0.5-dind を使用しています。
    詳しくは公式ドキュメントを参照してください。
  • rules は、ジョブの実行条件を定義します。
    今回は、feature/ から始まるブランチにコミットされた場合にジョブが実行されるように設定しています。
    詳しくは公式ドキュメントを参照してください。
  • before_script は、ジョブの実行前に実行されるスクリプトを定義します。
    今回は、コンテナ内から GitLab container registry にログインするためのスクリプトを定義しています。
    詳しくは公式ドキュメントを参照してください。
  • script は、ジョブの実行スクリプトを定義します。
    今回は、Docker イメージをビルドし、GitLab container registry に Push するスクリプトを定義しています。
    詳しくは公式ドキュメントを参照してください。

3-3. Artifact Registry への Push

include:
  # Image push to Artifact Registry for 1st manual release
  - component: gitlab.com/google-gitlab-components/artifact-registry/upload-artifact-registry@0.1.1
    inputs:
      stage: push
      source: $GITLAB_IMAGE
      target: $GOOGLE_AR_REPO/hello-world:$CI_COMMIT_SHORT_SHA

upload-artifact-registry:
  rules:
    - if: '$CI_COMMIT_REF_NAME =~ /^feature\/.*/'
詳細
  • include は、外部の YAML ファイルを読み込むための機能です。
    重複する設定を減らしたり、外部公開されている YAML ファイルを読み込むことができます。
    詳しくは公式ドキュメントを参照してください。
  • component は、読み込む YAML ファイルのパスを指定します。
    今回は、Artifact Registry に Docker イメージをプッシュするためのYAML ファイルを参考にしています。
    詳しくは公式ドキュメントを参照してください。
  • inputs は、読み込んだ YAML ファイルの入力を定義します。
    今回は、Artifact Registry にプッシュするための情報である、stagesourcetarget 、を定義しています。
    詳しくは公式ドキュメントを参照してください。
  • upload-artifact-registry は、ジョブの名前を定義します。
    これは、Artifact Registry に Docker イメージをプッシュするジョブです。
  • rules は、ジョブの実行条件を定義します。
    今回は、feature/ から始まるブランチにコミットされた場合にジョブが実行されるように設定しています。

3-4. Cloud Run へのデプロイ


# Deploy to Cloud Run
  - component:  gitlab.com/google-gitlab-components/cloud-sdk/run-gcloud@main
    inputs:
      stage: deploy
      project_id: $GOOGLE_PROJECT
      commands: |
          gcloud run deploy hello-world --image=$GOOGLE_AR_REPO/hello-world:$CI_COMMIT_SHORT_SHA --region=$GOOGLE_REGION --platform=managed --project=$GOOGLE_PROJECT

run-gcloud:
  rules:
    - if: '$CI_COMMIT_REF_NAME =~ /^feature\/.*/'

詳細
  • component は、読み込む YAML ファイルのパスを指定します。今回は、Cloud Run にデプロイするためのYAML ファイルを参考にしています。
  • inputs は、読み込んだ YAML ファイルの入力を定義します。今回は、Cloud Run にデプロイするための情報である、stageproject_idcommands 、を定義しています。
  • run-gcloud は、ジョブの名前を定義します。これは、Cloud Run にデプロイするジョブです。
  • rules は、ジョブの実行条件を定義します。今回は、feature/ から始まるブランチにコミットされた場合にジョブが実行されるように設定しています。

3-5. 完成した .gitlab-ci.yml ファイル

以下が完成した「.gitlab-ci.yml」ファイルの全体像です。

.gitlab-ci.yml
stages:
  - build
  - push
  - deploy

variables:
  GITLAB_IMAGE: $CI_REGISTRY_IMAGE/hello-world:$CI_COMMIT_SHORT_SHA
  GOOGLE_AR_REPO: GOOGLE_CLOUD_ARTIFACTS_REPOSITORY_FULL_PATH
  GOOGLE_PROJECT: PROJECT_ID
  GOOGLE_REGION: asia-northeast1
  CLOUD_RUN_SERVICE: hello-world

# Image build and push to GitLab container registry
image-build:
  image: docker:24.0.5
  stage: build
  services:
    - docker:24.0.5-dind
  rules:
    - if: '$CI_COMMIT_REF_NAME =~ /^feature\//'
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    - docker build -t $GITLAB_IMAGE app/
    - docker push $GITLAB_IMAGE
    - docker logout

include:
  # Upload to Artifact Registry
  - component: gitlab.com/google-gitlab-components/artifact-registry/upload-artifact-registry@0.1.1
    inputs:
      stage: push
      source: $GITLAB_IMAGE
      target: $GOOGLE_AR_REPO/hello-world:$CI_COMMIT_SHORT_SHA

  # Deploy to Cloud Run
  - component: gitlab.com/google-gitlab-components/cloud-sdk/run-gcloud@main
    inputs:
      stage: deploy
      project_id: $GOOGLE_PROJECT
      commands: |
        gcloud run deploy hello-world --image=$GOOGLE_AR_REPO/hello-world:$CI_COMMIT_SHORT_SHA --region=$GOOGLE_REGION --platform=managed --project=$GOOGLE_PROJECT

upload-artifact-registry:
  rules:
    - if: '$CI_COMMIT_REF_NAME =~ /^feature\/.*/'

run-gcloud:
  rules:
    - if: '$CI_COMMIT_REF_NAME =~ /^feature\/.*/'

4. CI/CD パイプラインの実行

では、作成した CI/CD パイプラインを実行してみましょう。
「.gitlab-ci.yml」ファイルを feature/001 ブランチにコミットします。
すると、GitLab で CI/CD パイプラインが実行されます。
CI/CD パイプラインの実行ログは、Build > Pipelines > Status をクリックすることで確認できます。
4-1

CI/CD パイプラインが正常に完了すると、Artifact Registry に Docker イメージがプッシュされ、Cloud Run にデプロイされます。

【 Artifact Registry に保存された Docker イメージ 】
4-2

【 Cloud Run に作成されたサービス 】
4-3

【 Cloud Run にデプロイされたアプリケーション 】
4-4

まとめ

GitLab と Google Cloud を連携して CI/CD パイプラインを構築する方法をご紹介しました。
今回は最小限の構成でのデモを行いましたが、実際のプロジェクトでは、より複雑な CI/CD パイプラインを構築することができます。
GitLab と Google Cloud の連携を活用して、DevSecOps の実現を目指しましょう。
最後までお読みいただき、ありがとうございました。

Discussion