🦊

Cloud Run へのデプロイに GitLab Runner を使う

2023/03/30に公開

はじめに

昨今ソースコードの管理には git を使っている人が大多数かと思うのですが、リモートには GitHub を使用するケースが多いのではないでしょうか。
GitHub はとても良いサービスなのですが、業務で使用したいと思うとほぼ有料サービス加入必須であり、維持費がかかってきます。(必要経費ではありますが)

GitLab は自分でサーバーを立ち上げる事が出来、CE版であれば基本的に無料で使用する事が出来ます。設定次第では完全プライベートな状態で運用でき、さらに維持費もサーバー運用コストのみです。

今回は、GitLab をセットアップして、CIからクラウド (今回はGCP) にデプロイするまでの一連の流れを紹介したいと思います。

GitLab CE を docker-compose で立ち上げる

まずは GitLab サーバーを立ち上げるのですが、docker-compose を使うと拍子抜けするほど簡単に立ち上げる事が出来ます。
以前にQiitaで記事にしましたので、参照してみてください。

https://qiita.com/soumi/items/baaa35b37f6c90a66c0c

GitLab に Runner を追加する

GitLab にも CI/CD があり、GitHubGitHub Actions と基本的には同じ役割を持つものですが、少し毛色が違います。
GitHub ActionsGitHub が用意した実行環境の中でコマンドを実行していきますが、GitLabCI/CDRunner と呼ばれる実行環境を用意するところからスタートします。

自分で用意しないといけないとなると面倒な気がしてきますが、実はこのおかげでとても柔軟性の高い CI/CD の環境が用意できます。
RunnerLinuxMacWindows用の各バイナリ、さらには Docker のイメージや k8s 上で動かす Helm チャートまであります。

https://docs.gitlab.com/runner/install/

これを利用して、例えば MacRunner を用意したら Windows で開発していても MaciOS 向けのアプリ書き出しが出来るし、複数の環境を用意したらそれぞれの環境用のアプリの書き出しが出来ます。

以前プロジェクトで RaspberryPI 向けのアプリを Electron で作成する事になった際、 RaspberryPIRunner をインストールして使用する事で簡単に CI と連動した書き出し環境を作る事が出来、とても便利でした。

Runner の追加場所

GitLab では、Runner をどのレベルで共有するか選ぶ事が出来ます。

Shared Runner

GitLab インスタンス全体で共有される Runner です。
Adminエリアの「CI/CD」->「Runners」から登録でします。

Group Runner

グループの中でのみ使用できる Runner です。
グループの「Settings」->「CI/CD」->「Runners」から登録します。

Project Runner

そのプロジェクトでのみ使用できる Runner です。
プロジェクトの「Settings」->「CI/CD」->「Runners」から登録します。

Docker Runner を追加する

GitLab 本体と同じように、Ubuntu 上に docker-composeDocker Runner を追加してみます。

docker-compose が使用できる環境で設定ファイルを作成し、

docker-compose.yml
version: '3'

services:
   runner:
      image: gitlab/gitlab-runner:v15.10.0
      restart: always
      volumes:
         - ./gitlab-runner/config:/etc/gitlab-runner
         - /var/run/docker.sock:/var/run/docker.sock

コマンドを実行します。

docker compose up -d
# もしくは docker-compose up -d

これで Runner 自体は立ち上がるのですが、 GitLab 本体に Runner として登録する必要があります。

docker compose exec runner gitlab-runner register

対話式でコマンドが進行していくので、適宜入力していきます。
トークンは、登録する場所に合わせて前項を参照して取得して下さい。

Enter the GitLab instance URL (for example, https://gitlab.com/):
<URL>
Enter the registration token:
<TOKEN>
Enter a description for the runner:
[31c0105f5395]: test docker runner
Enter tags for the runner (comma-separated):
docker-runner
Enter optional maintenance note for the runner:

Registering runner... succeeded                     runner=TxvRhK_X
Enter an executor: parallels, docker+machine, instance, custom, docker-ssh, shell, ssh, virtualbox, docker-ssh+machine, kubernetes, docker:
docker
Enter the default Docker image (for example, ruby:2.7):
docker:dind
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

Configuration (with the authentication token) was saved in "/etc/gitlab-runner/config.toml"

ここで大事になるのが、以下3点だと思っています。

executor

インストールした環境に合わせて設定しますが、今回は docker を選択します。

https://docs.gitlab.com/runner/executors/

tags

後述しますが、このタグを使用して CI に使用する Runner を選択します。
複数の Runner があった場合、指定された全てのタグを持つ Runner の中から実際に使用される Runner が選択されます。

今回は Docker Runner なので docker-runner 位しか設定しようがないですが、例えば複数の Windows Runner を追加した時、ある端末には Unity の開発環境が入っていて、また別の端末には Unreal は入っていたとしたら、それぞれをタグにしておく事で CI 実行時に適切な Runner を選択する事が出来ます。

default docker image

Docker Runner なので、デフォルトで何のイメージで実行するか聞かれます。環境に合わせて適宜設定ですが、僕は dind (Docker in Docker、Dockerが使えるDockerイメージ)にしました。

初期化が終わったら config.toml を編集

初期化が終わったらホストの ./gitlab-runner/config の中に config.toml ができます。
Docker Runner を使用するためには config.toml の中にある privileged の項目を true にする必要がある ので、変更しておいてください。

(おまけ) Windows Runner を追加する

以前 Qiita で書いた記事がありますので、こちらも参考になれば。
実行ユーザーの関係で躓きポイントがありましたので、ご注意ください。

https://qiita.com/soumi/items/3344dc2fa9538929390b

リポジトリを作る

GitLab 上で適当なリポジトリを作成します。既に CI を使ってみたいプロジェクトがあれば、そのプロジェクトでもいいと思います。

CI の設定をする

Project Runner を追加した場合は不要なのですが、あるプロジェクトで Shared Runner あるいは Group Runner を使用したい場合はプロジェクトの設定 -> CI/CD -> Runners から Enable shared runners for this projectON にする必要があります。

GCP のプロジェクトを用意する

テスト用の新しい GCP のプロジェクトを作ります。使えるものがあれば、既存のプロジェクトでも大丈夫です。

Artifact Registry でリポジトリを作成

Cloud Run はコンテナをデプロイするサービスなので、コンテナイメージをホストするためのリポジトリを用意する必要があります。
GCP には Artifact Registry というレジストリサービスがあるので、そちらを利用します。

Artifact Registryから、「リポジトリを作成」と進み、必要事項を入力してリポジトリを作成します。形式は docker としておいてください。

ここで作ったリポジトリ名と、選択したリージョン名は後で使用します。

API を有効にする

今回は Cloud Run へのデプロイなのですが、以下の API が必要です。
「APIとサービス」から「ライブラリ」を選択し、以下の API を有効にします。

  • Artifact Registry API
  • Cloud Run API

サービスアカウントを用意

Cloud Run へ実際にサービスをデプロイするサービスアカウントを作成します。
「IAM」から「サービスアカウント」を選択し、新規サービスアカウントを作成します。
ロールは、今回の場合は以下の物が必要です。

  • Artifact Registry 書き込み
  • Cloud Run 管理者
  • サービスアカウントユーザー

作成したサービスアカウントのメニューから「鍵を管理」->「鍵を追加」->「新しい鍵を作成」と進み、json ファイルをDLします。これがデプロイのための認証鍵になります。

コードを用意する

今回はサンプルとして、素の nginx コンテナをデプロイする事にします。
Clour Run へデプロイするアプリはポート8080で待ち受けている必要があるのですが、nginx デフォルトでは80番になっているので、これを8080にします。

参考
https://cloud.google.com/community/tutorials/deploy-react-nginx-cloud-run

Dockerfile
FROM nginx:alpine
COPY nginx.conf /etc/nginx/conf.d/configfile.template
ENV PORT 8080
ENV HOST 0.0.0.0
EXPOSE 8080
CMD sh -c "envsubst '\$PORT' < /etc/nginx/conf.d/configfile.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
nginx.conf
server {
    listen       $PORT;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri /index.html;
    }

    gzip on;
    gzip_vary on;
    gzip_min_length 10240;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
    gzip_disable "MSIE [1-6]\.";
}

CI ファイルを書く

GitLab では、.gitlab-ci.yml というファイルが CI 設定用のファイルになります。

.gitlab-ci.yml
# 指定しなければデフォルトの docker:dind になる
# image: docker:19.03.12-dind
services:
  - docker:19.03.12-dind

stages:
  - deploy
variables:
  OPS: production
  DOCKER_DRIVER: overlay2
  DOCKER_TLS_CERTDIR: ""
  DOCKER_HOST: tcp://docker:2375
  RUN_REGION: asia-northeast2 # Cloud Runでサービスを実行するリージョン
  REGISTRY_REGION: asia-northeast2 # Artifact Registry のリージョン
  SERVICE: test-service # Cloud Run にデプロイする際のサービス名
  IMAGE_TAG: ${REGISTRY_REGION}-docker.pkg.dev/${PROJECT_ID}/test/${SERVICE}
deploy:
  stage: deploy
  tags:
    - docker-runner
  script:
    # install
    - apk add --update --no-cache curl git bash python3
    # gcloud
    - curl -sSL https://sdk.cloud.google.com | bash
    - echo ${GCP_SA_KEY} > ./gcp-key.json
    - export PATH="$PATH:/root/google-cloud-sdk/bin"
    - gcloud auth activate-service-account --key-file=./gcp-key.json
    - gcloud config set project ${PROJECT_ID}
    # registry
    - gcloud auth configure-docker asia-northeast2-docker.pkg.dev
    # build
    - docker build -t ${IMAGE_TAG} .
    - docker push ${IMAGE_TAG}
    # deploy
    - gcloud run deploy ${SERVICE} --image ${IMAGE_TAG} --region ${RUN_REGION} --platform managed --allow-unauthenticated
  only:
    refs:
      - main

設定ファイル内にある変数のいくつかはファイル内の variables 内に定義してありますが、 GCP_SA_KEY 等の機密性の高い変数は別で定義します。

変数(シークレット)を設定する

前項であった「機密性の高い変数」ですが、グループやプロジェクトの「Settings」->「CI/CD」-> 「Variables」で設定する事が可能です。

この変数もプロジェクトやグループといった単位で設定でき、上位階層で設定されている変数は下位階層でも使用できます。
例えばAというグループにBというプロジェクトがあった場合、Aで設定した変数はBでも参照できます。

ここでは、以下の変数を設定します。

名称
PROJECT_ID プロジェクトのID
GCP_SA_KEY 事前にDLしておいたサービスアカウントの鍵となるjson

※GCP_SA_KEYは、ファイルの中身をコピペして設定します。

注意点

GitHub の場合は入力したシークレットは暗号化され、たとえ入力した本人でも復元する事は出来ませんが、GitLab の場合はそれが出来てしまいます。
グループやプロジェクトに共同作業メンバーを招待する場合は、よりロールに気を付ける必要があります。

push して CI を実行する

ここまでの作業を終えたら、ファイルを commit してリモートの GitLabpush します。
設定ファイル内で main ブランチに push されたら CI が実行されるように書いてあるので、push と同時に CI プロセスが走り出します。

進行状況はプロジェクトの「CI/CD」->「Pipelines」、あるいは「Jobs」から確認できます。

デプロイの完了を確認する

デプロイが完了したら、実際にサービスにアクセスしてみましょう。
アドレスは前項のログ最後の方にも表示されていますし、GCP のコンソールでも確認する事が出来ます。

nginx の初期画面が表示されていれば成功です。

おわりに

GitLab の構築からスタートしたので全体的に長くなってしまいましたが、一つ一つの手順はそんなに難しくなかったのではないかと思います。

GitLab に限りませんが、CI/CDは一度設定してしまえば後はリモートに push するだけで自動的に処理が走るので、自分の端末をデプロイで専有する時間をゼロに出来ます。
また、インフラの知識がない人でもデプロイプロセスを走らせる事が出来るので、そういう人が「試しに開発環境にデプロイしたい!」というケースでもインフラ担当者の手を止めずに済みます。

僕自身最初に構築した時は少し手間取ったのですが、この記事が同じような事をしたい方の助けになれば幸いです。

Discussion