GitHub Actions で LaravelのCI/CD環境を構築する（MySQL, Deployer）

## 概要

GitHub Actionsを使って、LaravelのプロジェクトをテストしてからAWSのEC2上にデプロイする方法を書いていきます。

テストDBにはMySQLを使用し、デプロイにはDeployerを使用します。各々の細かい説明はしません。

## 設定ファイル

GitHub Actionsの設定はYMLファイルです。

`.github/workflows`ディレクトリに設定ファイルを置くとワークフローとして処理されます。

## テストのjob

まずはテストが実行されるようにファイルを書いていきます。

```yaml
on: push

jobs:
  test:
    name: phpunit test
    runs-on: ubuntu-latest

    services:
      mysql:
        image: mysql:8.0.19
        ports:
          - 3306:3306
        options: --health-cmd "mysqladmin ping -h localhost" --health-interval 20s --health-timeout 10s --health-retries 10
        env:
          MYSQL_ROOT_PASSWORD: pass
          MYSQL_DATABASE: test

    env:
      DB_CONNECTION: mysql
      DB_HOST: 127.0.0.1
      DB_PORT: 3306
      DB_DATABASE: test
      DB_USERNAME: root
      DB_PASSWORD: pass

    steps:
      - uses: actions/checkout@v2
      - name: cache vendor
        id: cache
        uses: actions/cache@v1
        with:
          path: ./vendor
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: |
            ${{ runner.os }}-composer-
      - name: composer install
        if: steps.cache.outputs.cache-hit != 'true'
        run: composer install -n --prefer-dist
      - name: copy .env
        run: cp .env.ci .env
      - name: generate key
        run: php artisan key:generate
      - name: migrate
        run: php artisan migrate
      - name: unit test
        run: ./vendor/bin/phpunit
```

### MySQL

今回はテストDBにMySQLを使用するのでMySQLを使いたいのですが、ワークフローが実行されるマシン(ランナー)であるubuntuには5系しか入っていないので、Dockerコンテナを立ててMySQLを使用します。

services内のimageでDockerのimageを指定でき、DockerHubからimageをpullできます。

執筆時点ではoptionを指定していないと、MySQLコンテナが立ち上がる前にPHPUnitが走ってしまいテストがコケてしまう現象がでたため、MySQLコンテナが立ち上がるまで待ちます。

envで環境変数を設定しています。`jobs.<id>.env`の位置に書くことによって、このjob内で使える環境変数として設定できます。

注意点としては、今回はランナー上でコンテナをたてているので`DB_HOST: 127.0.0.1`にしてください。コンテナ名にしても接続はできません。

### PHPUnit

毎回composer installをすると時間がかかってしまうので、キャッシュができるアクションがあるのでそれを指定しています。
使い方は[ここ](https://github.com/marketplace/actions/cache)に書いてあるコードを書いておけばとりあえず大丈夫です。

.envに関しては今回は雛形（.env.ci）をコピーしてますが、`APP_KEY`が設定できればどの方法でもOKです。

あとはmigrateなりphpunitなりのコマンドを叩けばテストが走るjobが完成します。

## デプロイのjob

次はデプロイに関して設定をしていきます。

さきほどと同じファイルの続きに書いていきます。

```yaml

jobs:

  //...

  deploy:
    name: deploy
    runs-on: ubuntu-latest
    needs: test
    if: github.ref == 'refs/heads/master'

    steps:
      - uses: actions/checkout@v2
      - name: cache vendor
        id: cache
        uses: actions/cache@v1
        with:
          path: ./vendor
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: |
            ${{ runner.os }}-composer-
      - name: composer install
        if: steps.cache.outputs.cache-hit != 'true'
        run: composer install -n --prefer-dist
      - name: ssh_key copy
        run: |
          mkdir -p /home/runner/.ssh
          touch /home/runner/.ssh/id_rsa
          echo "${{ secrets.SECRET_KEY }}" > /home/runner/.ssh/id_rsa
          chmod 600 /home/runner/.ssh/id_rsa
      - name: add known hosts
        run: ssh-keyscan 【 ip or host_name 】 >> ~/.ssh/known_hosts
      - name: deploy
        run: ./vendor/bin/dep deploy master

```

まずテストと大きく違うところはneedsとifです。

GitHub Actionsではjobは並列に実行されるのでそのまま書いてしまうとテストとデプロイが一緒に走ってしまうことになります。

テストをパスしてからデプロイをしたいのでneedsでどのjobが終わってから実行するかを指定します。

またデプロイはどのブランチでもデプロイするわけではないので、ifを使ってmasterブランチのときに実行するようにします。

### Deployer

Deployerでデプロイするには秘密鍵が必要になります。公開鍵はあらかじめサーバーにあげておいてください。

秘密鍵などの情報をそのまま書いてしまうとセキュリティ的にNGなので、GitHub ActionsではあらかじめGitHubに暗号化して登録しておきます。
(https://help.github.com/ja/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets)

登録した秘密鍵を適切な場所にコピーしてあげます。（Deployerだと`hosts.yml`に秘密鍵のファイルを指定できるオプションがあります）

このままssh接続をしてしまうと接続時にコンソールで`yes or no`を入力しないとすすめなくなってしまいエラーになってしまうので、`known_hosts`にあらかじめ記述しておくことでこれを回避することができます。

最後にdeployコマンドを叩くようにするとデプロイが開始されます。

## pushする

以上のファイルを保存してGitHubにpushすると、pushをトリガーにしてmasterだとテスト＆デプロイが、それ以外だとテストが走ります。

Circle CIのようにGitHub Actionsのテストが通ったらPRをマージできるようにするなどの設定も可能です。

## まとめ

Circle CIを使ったことがある人ならそこまで抵抗なくできると思います。

GitHub Actionsでは他の人が作ったものをActionとして利用できるので、それを利用することでより手軽に様々なことができるようになるかもしれません。
[GitHub Actionsの検索](https://github.com/marketplace?type=actions)

ちなみにSlackへの通知は[こちら](https://github.com/marketplace/actions/actions-slack)のアクションなどがあるので便利です。