DockerfileやLaravelプロジェクトのコードを変更された時に毎度手動でテストするのはとても時間がかかってしまいます。
Dockerビルド以外にも、Composerのインストールがうまくいくか、マイグレーションやロールバック処理やシーダーが壊れてないか。
Laravelのテストコードがうまく実行されるか。確認したいことがたくさんあります。
環境
パターン1: まとめてテストする
name: Laravel Testing
on:
pull_request:
jobs:
laravel-testing:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Ubuntu Version
run: cat /etc/os-release
- name: Docker Version
run: docker version
- name: Cache Composer dependencies
uses: actions/cache@v2
id: cache
with:
path: ./backend/vendor
key: ${{ runner.os }}-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Docker Compose Build and Up
run: |
docker-compose build
docker-compose up -d
- name: Docker Compose Process
run: docker-compose ps -a
- name: PHP, Composer Version
run: |
docker-compose exec -T app php --version
docker-compose exec -T app composer --version
- name: Composer Install
if: steps.cache.outputs.cache-hit != 'true'
run: docker-compose exec -T app composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist
- name: Composer Dump Autoload
run: docker-compose exec -T app composer dump-autoload -q
- name: Laravel Settings
run: |
docker-compose exec -T app cp .env.example .env
docker-compose exec -T app php artisan key:generate
docker-compose exec -T app php artisan optimize
docker-compose exec -T app chmod -R 777 storage bootstrap/cache
- name: Laravel Version
run: docker-compose exec -T app php artisan --version
- name: Laravel Migrate Testing
run: docker-compose exec -T app php artisan migrate
- name: Laravel Rollback Testing
run: docker-compose exec -T app php artisan migrate:refresh
- name: Laravel Seeding Testing
run: docker-compose exec -T app php artisan db:seed
- name: Laravel PHPUnit Testing
run: |
docker-compose exec -T app php artisan config:clear
docker-compose exec -T app php artisan test
パターン1の特徴
Laravel Testing: 2m 35s
(この2分13秒はDockerビルドの時間です。)
愚直にDockerビルドしてDockerイメージを作成してコンテナを作成し、そのコンテナ上でLaravelのテストを実行してます。
よくない点としては、毎回Dockerビルドが実行されるので時間がもったいない感じがあります。
(PHPのファイル変更に比べてDockerfileの変更が入る機会が少ないので)
パターン2: テストを分割する
name: Docker Testing
on:
pull_request:
paths:
- 'infra/*'
jobs:
docker-testing:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Ubuntu Version
run: cat /etc/os-release
- name: Docker Version
run: docker version
- name: Docker Compose Build
run: docker-compose build
name: Laravel Testing
on:
pull_request:
paths:
- 'backend/*'
jobs:
laravel-testing:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
ports:
- 3306:3306
env:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: laravel_local
options: >-
--health-cmd "mysqladmin ping -h localhost"
--health-interval 20s
--health-timeout 10s
--health-retries 10
env:
DB_CONNECTION: mysql
DB_HOST: 127.0.0.1
DB_PORT: 3306
DB_DATABASE: laravel_local
DB_USERNAME: root
DB_PASSWORD: secret
defaults:
run:
working-directory: backend
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.0'
- name: Ubuntu Version
run: cat /etc/os-release
- name: PHP, Composer Version
run: |
php --version
composer --version
- name: Cache Composer dependencies
uses: actions/cache@v2
id: cache
with:
path: ./backend/vendor
key: ${{ runner.os }}-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Composer Install
if: steps.cache.outputs.cache-hit != 'true'
run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist
- name: Composer Dump Autoload
run: composer dump-autoload -q
- name: Laravel Settings
run: |
cp .env.example .env
php artisan key:generate
php artisan optimize
chmod -R 777 storage bootstrap/cache
- name: Laravel Version
run: php artisan --version
- name: Laravel Migrate Testing
run: php artisan migrate
- name: Laravel Rollback Testing
run: php artisan migrate:refresh
- name: Laravel Seeding Testing
run: php artisan db:seed
- name: Laravel PHPUnit Testing
run: |
php artisan config:clear
php artisan test
パターン2の特徴
Laravel Testing: 59s
Docker Testing: 1m 57s
Laravel Testing
が1分以内に終わっているので、開発効率はとても上がります。
Docker Testing
はとりあえずDockerビルドが通るかどうかのテストまで行ってます。
on.<push|pull_request>.paths
で指定したパスに一致するファイルが変更された場合にワークフローが実行されるように設定してます。
jobs.<job_id>.services
ワークフロー中のジョブのためのサービスコンテナを構築できます。
デメリットとしてはCI上でPHPやMySQLの実行環境を作って実行させているので、Dockerfileの内容と合わせて両方メンテしていく必要があります。
パターン3: Dockerイメージを登録する
name: Docker Image Register
on:
pull_request:
paths:
- 'infra/*'
jobs:
docker-image-register:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
registry: docker.io
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build & Push app Container
uses: docker/build-push-action@v2
with:
context: .
file: ./infra/docker/php/Dockerfile
push: true
tags: ucanlab/docker-laravel-github-actions-app:latest
- name: Build & Push nginx Container
uses: docker/build-push-action@v2
with:
context: .
file: ./infra/docker/nginx/Dockerfile
push: true
tags: ucanlab/docker-laravel-github-actions-web:latest
- name: Build & Push db Container
uses: docker/build-push-action@v2
with:
context: .
file: ./infra/docker/mysql/Dockerfile
push: true
tags: ucanlab/docker-laravel-github-actions-db:latest
name: Laravel Testing
on:
pull_request:
jobs:
laravel-testing:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Ubuntu Version
run: cat /etc/os-release
- name: Docker Version
run: docker version
- name: Cache Composer dependencies
uses: actions/cache@v2
id: cache
with:
path: ./backend/vendor
key: ${{ runner.os }}-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Docker Compose Build and Up
run: |
docker-compose build
docker-compose up -d
- name: Docker Compose Process
run: docker-compose ps -a
- name: PHP, Composer Version
run: |
docker-compose exec -T app php --version
docker-compose exec -T app composer --version
- name: Composer Install
if: steps.cache.outputs.cache-hit != 'true'
run: docker-compose exec -T app composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist
- name: Composer Dump Autoload
run: docker-compose exec -T app composer dump-autoload -q
- name: Laravel Settings
run: |
docker-compose exec -T app cp .env.example .env
docker-compose exec -T app php artisan key:generate
docker-compose exec -T app php artisan optimize
docker-compose exec -T app chmod -R 777 storage bootstrap/cache
- name: Laravel Version
run: docker-compose exec -T app php artisan --version
- name: Laravel Migrate Testing
run: docker-compose exec -T app php artisan migrate
- name: Laravel Rollback Testing
run: docker-compose exec -T app php artisan migrate:refresh
- name: Laravel Seeding Testing
run: docker-compose exec -T app php artisan db:seed
- name: Laravel PHPUnit Testing
run: |
docker-compose exec -T app php artisan config:clear
docker-compose exec -T app php artisan test
services:
app:
image: ucanlab/docker-laravel-github-actions-app:latest
# ...
web:
image: ucanlab/docker-laravel-github-actions-web:latest
# ...
db:
image: ucanlab/docker-laravel-github-actions-db:latest
# ...
パターン3の特徴
Laravel Testing: 1m 0s
Docker Image Register: 2m 40s
DockerイメージをDockerレジストリへ登録します。
今回のレジストリは docker.io
を使用します。
-
https://hub.docker.com/settings/security
- Docker Hubへのアクセストークンを取得します。
-
https://github.com/<オーナー>/<リポジトリ>/settings/secrets/actions
- GitHub のシークレットへ
DOCKERHUB_USERNAME
,DOCKERHUB_TOKEN
を登録します。
- GitHub のシークレットへ
Dockerレジストリへ登録するためあらかじめDockerアカウントを作ったり、アクセストークンを発行してGitHubシークレットへ登録しておくなど準備が必要です。
タグ指定でバージョンを設定したり等改良の余地やプロジェクトによってレジストリを変更する場合もありそうです。
ここまで来るとinfraとbackendのGitHubリポジトリも分けて管理した方が良さそうです。
こちらもDockerの変更とLaravelのコード変更と分けてるので、開発しやすくなると思います。
また、本番環境も同じDockerイメージを利用できるので、エコな気がします。
本格的にやる場合はこのパターン3の方法がベストかなと思います。
しかし、プロジェクトによって様々設定が必要になると思うのでパターン3は参考程度にご利用ください。
まとめ
ComposerのCache周りで少しハマりました。
キャッシュファイルが利用されるときはcomposer dump-autoload
が実行されないので、別途ステップを作ってあげる必要がありました。
あとCI周り詳しくないので、もっと良い書き方とかあれば教えてください><。