[CI/CD] GitHub ActionsからLaravel8をCloud Run、Cloud SQLに自動デプロイ
この記事は筆者が以下で投稿したものの日本語版です。
今回の記事のゴール
GitHub Actionsを使って、Google Cloud Run上のLaravel8アプリケーションに自動でデプロイすることが目的です。以下の流れでデプロイを試みます。
- Docker composeでLaravelを起動(ローカル開発用)
- DockerイメージをContainer Registryにプッシュ
- Google Cloud Runデプロイ & Google Cloud SQLに接続
- 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の初期画面が表示されることを確認しましょう。
マイグレーションはどうでしょう。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 install
とmigrate
コマンドがここで実行されます。
#!/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
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
でビルドした時と同様に、ローカルページが正しく動くことを確認しましょう。
2-4. DockerイメージをContainer Registryにプッシュ
$ gcloud auth configure-docker
docker push asia.gcr.io/${PROJECT_ID}/${SERVICE_NAME}
docker-laravel8という名前のリポジトリが登録されていることを確認します。
2-5. Cloud SQL Admin APIを有効化する
Google Cloud RunとGoogle Cloud SQLを連携させるためには、Cloud SQL Admin APIを有効にする必要があります。
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
- How to securely connect to Cloud SQL from Cloud Run? - Stack Overflow
- How do I connect to Cloud SQL from a Laravel project running on Cloud Run? - Stack Overflow
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
デプロイ後、URLが生成されます。Laravel8用のページが正しく表示されることを確認してください。
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の環境変数を以下のように入力します。
TEST_GCP_EMAILは、Google Cloud Runのページから取得することができます。
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
マスターリポジトリをプッシュした後、自動的にリモートリポジトリにデプロイを開始します。成功するかどうか確認してみましょう。
やったぜ!
Discussion