🎃

[CI/CD] GitHub ActionsからLaravel8をCloud Run、Cloud SQLに自動デプロイ

2022/03/13に公開約12,000字

この記事は筆者が以下で投稿したものの日本語版です。

https://dev.to/xxxuutaxxx/beginners-cicd-guide-deploy-laravel8-to-google-cloud-run-and-cloud-sql-via-github-actions-40oj

今回の記事のゴール

GitHub Actionsを使って、Google Cloud Run上のLaravel8アプリケーションに自動でデプロイすることが目的です。以下の流れでデプロイを試みます。

  1. Docker composeでLaravelを起動(ローカル開発用)
  2. DockerイメージをContainer Registryにプッシュ
  3. Google Cloud Runデプロイ & Google Cloud SQLに接続
  4. GitHub Actionsからデプロイ自動化

ディレクトリ構造

以下は今回使用するリポジトリの構造です。

.
├── .github/
│   └── workflows
│       └── deploy.yml # GitHub Actions用のymlファイル
├── env/
├── docker/
│   ├── 000-default.conf
│   ├── Dockerfile
│   └── php.ini
├── sh/ # ビルド後に使用するシェルスクリプト用のディレクトリ
├── src/ # Laravelが格納されているディレクトリ
└── docker-compose.yml

1. Docker composeでLaravelを動かす

ローカル環境での開発を考慮し、docker composeでコンテナを立ち上げることができるようにリポジトリを準備しました。説明しやすいよう、/src直下にLaravel8のファイル群を入れていますが、おそらく他のバージョンのLaravelでも動くと思います。

1-1. GitHubからリポジトリをクローン

GitHubからリポジトリをクローンしましょう。

$ git clone git@github.com:uuta/cloud-run-laravel8.git
$ cd cloud-run-laravel8

Docker composeでコンテナを起動します。

$ cp env/.env.example env/.env.local
$ docker-compose up -d --build
...
...
...
Creating cloud-run-laravel8_db_1  ... done
Creating cloud-run-laravel8_app_1 ... done
Time: 0h:00m:24s

src/.envファイル内のAPP_KEYが空になっているので、appコンテナにログインし、KEYを生成します。

$ docker-compose exec app bash
$ php artisan route:clear && \
php artisan cache:clear && \
php artisan config:clear && \
php artisan view:clear && \
php artisan key:generate

APP_KEYが以下のように生成されると思います。

# before
APP_KEY=
# after
APP_KEY=base64:<key>

それではローカルホストに接続してLaravelの初期画面が表示されることを確認しましょう。

Image description

マイグレーションはどうでしょう。appコンテナからマイグレーションを走らせると、以下のメッセージが表示されます。

$ docker-compose exec app bash
$ php artisan migrate
Nothing to migrate.

実はDocker image構築の際にマイグレーションを実行しているので、Nothing to migrateというメッセージが表示されます。リポジトリ内のDockerfile.localを見てみましょう。

FROM composer:latest as build
WORKDIR /app
COPY . /app

FROM php:8.0-apache
COPY docker/php.ini /usr/local/etc/php/
RUN apt update
RUN apt install -y git
RUN apt install -y vim
RUN apt install -y zip unzip
RUN docker-php-ext-install bcmath pdo_mysql

# composer install
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
EXPOSE 8080
COPY --from=build /app /var/www
COPY docker/000-default.conf /etc/apache2/sites-available/000-default.conf
RUN chmod 777 -R /var/www

WORKDIR /
RUN echo "Listen 8080" >> /etc/apache2/ports.conf
RUN chown -R www-data:www-data /var/www
RUN a2enmod rewrite

# Make the file executable, or use "chmod 777" instead of "chmod +x"
RUN chmod +x /var/www/sh/laravel/laravel.local.sh

# This will run the shell file at the time when container is up-and-running successfully (and NOT at the BUILD time)
ENTRYPOINT ["/var/www/sh/laravel/laravel.local.sh"]

ファイルの最後で、sh/laravel/laravel.local.shを介してシェルスクリプトを実行しています。

RUN chmod +x /var/www/sh/laravel/laravel.local.sh
...
ENTRYPOINT ["/var/www/sh/laravel/laravel.local.sh"]

具体的に見てみます。composer installmigrateコマンドがここで実行されます。

#!/bin/bash

# initialize laravel
cd /var/www/src
composer install --optimize-autoloader
php artisan config:cache
php artisan route:cache
php artisan view:cache

# Run Laravel migration
php artisan migrate

# Run Apache in "foreground" mode (the default mode that runs in Docker)
apache2-foreground

マイグレーションコマンド等はDockerfileにまとめて書きたいものです。しかし、Buildの段階ではGoogle Cloud SQLに接続できず、Buildに成功した後にこれらのコマンドを実行しなければならないようです。したがって、あえてシェルスクリプトを実行する形にしています。

なお、ローカル環境では、Google Cloud SQLではなく、ローカルのデータベースと接続します。

1-2. Dockerfileの中身を見てみよう

もう一度、Dockerfile.localを見てみましょう。簡単に説明します。Google Cloud Runでイメージを構築するために、シェルスクリプトで8080のポートを公開しています。

EXPOSE 8080
...
RUN echo "Listen 8080" >> /etc/apache2/ports.conf

This command copies 000-default.conf to configure the Apache WEB server.

COPY docker/000-default.conf /etc/apache2/sites-available/000-default.conf

2. DockerイメージをContainer Registryにプッシュ

では、ローカル側からLaravelアプリケーションをデプロイしてみましょう。まず、dockerコンテナを停止します。

$ docker-compose down

2-1. コンソールからGCPをセットアップする

GCPのプロジェクト名を確認した上で、以下のコマンドを実行してください。

$ gcloud auth login
$ PROJECT_NAME=(<Project name in GCP>)
PROJECT_ID=$(gcloud projects list --format 'value(projectId)' --filter name=$PROJECT_NAME)
export PROJECT_ID
gcloud config set project $PROJECT_ID
gcloud services enable \
    containerregistry.googleapis.com \
    cloudresourcemanager.googleapis.com \
    iam.googleapis.com

Image description

2-2. サービスアカウントを作成する

サービスアカウントを作成し、オーナー権限を付与します。鍵をダウンロードしてlaravel8_google_cloud_run_key.jsonとして保存し、環境変数に設定し、サービスアカウントとして認証します。以下のコマンドで可能です。

$ gcloud iam service-accounts create deployer \
    --display-name "deployer"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:deployer@${PROJECT_ID}.iam.gserviceaccount.com \
  --role roles/owner
export GOOGLE_APPLICATION_CREDENTIALS=credentials/laravel8_google_cloud_run_key.json
gcloud iam service-accounts keys create $GOOGLE_APPLICATION_CREDENTIALS \
  --iam-account deployer@${PROJECT_ID}.iam.gserviceaccount.com
gcloud auth activate-service-account --key-file=$GOOGLE_APPLICATION_CREDENTIALS

上記のコマンド例では、credentialsディレクトリに laravel8_google_cloud_run_key.json が格納されています。

export GOOGLE_APPLICATION_CREDENTIALS=~/credentials/laravel8_google_cloud_run_key.json

2-3. Docker imageをビルドする

docker-compose コマンドを使わずに、docker イメージをビルドします。

$ export SERVICE_NAME=docker-laravel8-run
docker build -f docker/Dockerfile.prod -t asia.gcr.io/${PROJECT_ID}/${SERVICE_NAME} .

docker runで動かしてみましょう。

$ docker run --init -d -e PORT=8080 -p 8080:8080 asia.gcr.io/${PROJECT_ID}/${SERVICE_NAME}

Docker composeでビルドした時と同様に、ローカルページが正しく動くことを確認しましょう。

Image description

2-4. DockerイメージをContainer Registryにプッシュ

$ gcloud auth configure-docker
docker push asia.gcr.io/${PROJECT_ID}/${SERVICE_NAME}

docker-laravel8という名前のリポジトリが登録されていることを確認します。

Image description

2-5. Cloud SQL Admin APIを有効化する

Google Cloud RunとGoogle Cloud SQLを連携させるためには、Cloud SQL Admin APIを有効にする必要があります。

Image description

3. Google Cloud Runデプロイ & Google Cloud SQLに接続

テスト用に一時的にGoogle Cloud SQLインスタンスを作成します。このサンプルでは以下の例のようなインスタンスを作成しますが、ご自分の環境に合わせて設定を変更してください。この作業は時間がかかるかもしれません。

$ DATABASE_NAME=(docker-laravel8-run)
gcloud sql instances create $DATABASE_NAME \
  --database-version=MYSQL_8_0 \
  --region=us-central1 \
  --storage-size=100 \
  --storage-type=HDD \
  --tier=db-f1-micro \
  --root-password=homestead

Image description

Laravelという名前のデータベースを作成しておきましょう。

$ gcloud sql databases create laravel \
--instance=$DATABASE_NAME

3-1. Google Cloud Runへのデプロイ

Google Cloud Runにデプロイしてみます。Google Cloud SQLのConnection nameを<Connection name>に置き換えて、以下のコマンドを実行してください。

$ SQL_CONNECTION_NAME=(<Connection name>)
gcloud run deploy ${SERVICE_NAME} \
--image asia.gcr.io/"${PROJECT_ID}"/"${SERVICE_NAME}" \
--region asia-east1 \
--platform=managed \
--add-cloudsql-instances ${SQL_CONNECTION_NAME} \
--allow-unauthenticated

Image description

デプロイ後、URLが生成されます。Laravel8用のページが正しく表示されることを確認してください。

Image description

Image description

4. GitHub Actionsからデプロイを自動化する!

4-1. 簡単な説明

これで、Local環境からLaravelアプリケーションを正常にデプロイできました。続いて、GitHub Actionsからのデプロイを考えてみましょう。GitHub Actionsでは、masterやmainブランチにコミットがpushされた際に、デプロイするためのコマンドを実行することを想定しています。この例では、デプロイコマンドは .github/workflows/deploy.yml ファイルに定義されています。そして、デプロイのトリガーは master にプッシュした時に設定されています。

name: cloud-run-laravel8-deploy
on:
  push:
    branches:
      - master

もう少し見てみましょう。このリモートリポジトリには、.gitignoreファイルによってLaravelアプリケーションを設定するための.envファイルがありません。そのため、デプロイするときだけ、.envファイルを配置する必要があります。そして、ローカルにある.envファイルをbase64でデコードした環境変数をエンコードすることで、デプロイできるようになります。

- name: Decode .env file
  run: |
    echo ${{ secrets.TEST_ENV_FILE }} | base64 --decode > src/.env

.github/workflows/deploy.yml` ファイルには、6つの環境変数が用意されています。

  • secrets.TEST_GCP_EMAIL: deploy email
  • secrets.TEST_GCP_CREDENTIALS: the content of credentials/laravel8_google_cloud_run_key.json in your local environment
  • secrets.TEST_ENV_FILE: env/.env.prod
  • secrets.TEST_GCP_PROJECT: project id
  • secrets.TEST_GCP_APPLICATION: service name
  • secrets.TEST_SQL_CONNECTION_NAME: SQL connection name

4-2. リモートリポジトリを自分のものに変更する

次に、リモートリポジトリを test-cloud-run に変更します。名前は好きなものをつけてください。

$ git config remote.origin.url
git@github.com:uuta/cloud-run-laravel8.git
$ git remote set-url origin git@github.com:uuta/test-cloud-run.git
$ git config remote.origin.url

4-3. 環境変数をGitHubに入力する

GitHubの環境変数を以下のように入力します。

Image description

TEST_GCP_EMAILは、Google Cloud Runのページから取得することができます。

Image description

TEST_ENV_FILEを変更するのは少々やっかいです。まず、.env.example ファイルを .env.prod としてコピーします。

$ cp env/.env.local env/.env.prod

.env.prod ファイルを以下のように修正します。DB_SOCKETを忘れずに修正しましょう。

APP_NAME=Laravel
APP_ENV=production
APP_KEY=<your app key>
APP_DEBUG=false
APP_URL=<your app url>

LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug

DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=homestead
DB_SOCKET=/cloudsql/<connection name to Google Cloud SQL>

以下のコマンドを実行すると、env ファイル内の値が Base64 エンコードされた文字列として転送されます。そのため、TEST_ENV_FILEの値としてコピー&ペーストすることができる。

$ cat env/.env.prod | base64 | pbcopy

4-4. GitHubにプッシュし、自動的にデプロイ

$ git push

マスターリポジトリをプッシュした後、自動的にリモートリポジトリにデプロイを開始します。成功するかどうか確認してみましょう。

Image description

やったぜ!

References

Discussion

ログインするとコメントできます