EC2+Laravel+MySQL+Github Actions

# はじめに
Github Actions が簡単だよということらしいので試してみることにした。

# 追記
完成後に公開済みでないと、この設定の場合、gitが機能しないので、また記事をあげます。

# 下準備

- Laravelの初期画面を表示することができている
- git に上がっている

この2点だけ準備が必要だ。

<img width="1059" alt="スクリーンショット 2020-06-16 23.47.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563543/a8abe073-c3cb-e7d7-c697-98c6bc81742b.png">

# インスタンスの用意

EC2を作成する。とりあえずのAmazon Linux2で作ってみようかと思う。
試すだけなので構成は以下の通り。

| 指定したもの | 内容 |
| ---------- | ---- |
| AMI | Amazon Linux 2 |
| インスタンスタイプ | t2.micro |
| 自動割り当てパブリックIP | 有効 |
| Name | Laravel-ci |

| セキュリティグループ |  |
| ---- | ------|
| SSH | 0.0.0.0/0 |
| HTTP | マイIP |

作成がうまくいくったら、接続を元にSSH接続をする。
自分は今回、`test-keypair`という名前で鍵を作成した。その場合、`test-keypair.pem.txt`というファイルをダウンロードすることになるので、`test-keypair.pem`という名前に変更する

`ssh -i "test-keypair.pem" ec2-user@IPアドレス`

でSSH接続できる。

### 秘密鍵の作成

`exit`で一度接続を断つ。そうしたら鍵を作成しよう。

`ssh-keygen -t rsa -b 4096 -m pem` を叩いた後、Enter連打で完成する。保存先は、`~/.ssh`だ。また、同時に公開鍵が作成される。これをEC2へ送りつけよう。

インスタンス作成時に作った鍵が保存されているディレクトリに移動しておこう。


`scp -i "test-keypair.pem" ~/.ssh/id_rsa.pub ec2-user@IPアドレス:/home/ec2-user/.ssh`


で公開鍵をEC2へ送ることができる。

### 公開鍵の登録

送った公開鍵をEC2側で登録する。まずは、SSH接続しよう。

`ssh -i "test-keypair.pem" ec2-user@IPアドレス`

接続後は以下の通り。

```
$ cd .ssh
$ echo "$(<id_rsa.pub)" >> authorized_keys
```

これで登録完了だ。

# GitHub Action

やっと試すことができる。まずリポジトリのアクションのページに飛ぶ。

<img width="1062" alt="スクリーンショット 2020-06-17 00.51.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563543/cb934c7b-1de3-129c-ca0d-6fa9b8f6b61c.png">

そして、登録したてのLaravelアプリケーションの場合、SuggestedでLaravelが出てくるはずだ。

<img width="1061" alt="スクリーンショット 2020-06-17 00.54.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563543/ded96beb-8ce5-9f50-4de1-b39c34d13f22.png">

`Set up this workflow`へ進む。

すみません、、、ここで画像を撮り忘れました。
右上に、`Start Commit`のタブがあるので、クリックし、`Commit new file`をしてください。

自分は、MySQLでやろうとしていたためここでエラーとなりました。そして、以下のように`.github/workflow/laravel.yml`を修正しました。

```.github/workflow/laravel.yml
name: Laravel

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]


jobs:
  laravel-tests:
    runs-on: ubuntu-latest

    services:
      mysql:
        image: mysql:5.7
        ports:
          - 3306:3306
        env:
          MYSQL_DATABASE: homestead
          MYSQL_USER: homestead
          MYSQL_ROOT_PASSWORD: ${{ secrets.DB_PASSWORD }}
          MYSQL_PASSWORD: ${{ secrets.DB_PASSWORD }}
        options: >-
          --health-cmd="mysqladmin ping"
          --health-interval=10s
          --health-timeout=5s
          --health-retries=3
    
    steps:
    - uses: actions/checkout@v2
    - name: Copy .env
      run: php -r "file_exists('.env') || copy('.env.example', '.env');"
    - name: Install Dependencies
      run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
    - name: Generate key
      run: php artisan key:generate
    - name: Directory Permissions
      run: chmod -R 777 storage bootstrap/cache
    - name: Create Database
      run: |
        mkdir -p database
        touch database/database.sqlite
    - name: Execute tests (Unit and Feature tests) via PHPUnit
      env:
        DB_CONNECTION: mysql
        DB_HOST: 127.0.0.1
        DB_PORT: 3306
        DB_DATABASE: homestead
        DB_USERNAME: homestead
        DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
      run: |
        php artisan migrate
        vendor/bin/phpunit
```

そして、`${{ secrets.DB_PASSWORD }}`となっていた、データベースのパスワードを設定しにいきます。`Settings`を開いて、`New secret`から設定していきます。

<img width="1053" alt="スクリーンショット 2020-06-17 01.47.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563543/d488653e-af04-1db5-144a-9b6ebfea52ec.png">

データベースのパスワードが`secret`の場合の例

<img width="1057" alt="スクリーンショット 2020-06-17 01.46.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563543/d1f1af76-e891-33c3-5f2d-9a05afe7a34e.png">

変更が完了したら、`master`へ`push`してみてください。
そして、自分はこの時、以下のようなエラーが起こりました。

```
Process completed with exit code 1.
```

```
× Generate key
     92|     {
9
     93|         file_put_contents($this->laravel->environmentFilePath(), preg_replace(
10
     94|             $this->keyReplacementPattern(),
11
     95|             'APP_KEY='.$key,
12
  >  96|             file_get_contents($this->laravel->environmentFilePath())
13
     97|         ));
14
     98|     }
```

これは、リモートリポジトリに`.env.example`ファイルが上がっていなかったために起こりました。`push`しましょう。

```
$ git add .env.example
$ git commit -m "Add .env.example"
$ git push -u origin master
```

自分は、ここで1度テストが通りました。

# GitHub Actions でデプロイ

`.github/workflow/laravel.yml`を先に作成します。

```.github/workflow/laravel.yml
name: Laravel

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master, develop ]


jobs:
  laravel-tests:
    runs-on: ubuntu-latest

    services:
      mysql:
        image: mysql:5.7
        ports:
          - 3306:3306
        env:
          MYSQL_DATABASE: homestead
          MYSQL_USER: homestead
          MYSQL_ROOT_PASSWORD: ${{ secrets.DB_PASSWORD }}
          MYSQL_PASSWORD: ${{ secrets.DB_PASSWORD }}
        options: >-
          --health-cmd="mysqladmin ping"
          --health-interval=10s
          --health-timeout=5s
          --health-retries=3
    
    steps:
    - uses: actions/checkout@v2
    - name: Copy .env
      run: php -r "file_exists('.env') || copy('.env.example', '.env');"
    - name: Install Dependencies
      run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
    - name: Generate key
      run: php artisan key:generate
    - name: Directory Permissions
      run: chmod -R 777 storage bootstrap/cache
    - name: Create Database
      run: |
        mkdir -p database
        touch database/database.sqlite
    - name: Execute tests (Unit and Feature tests) via PHPUnit
      env:
        DB_CONNECTION: mysql
        DB_HOST: 127.0.0.1
        DB_PORT: 3306
        DB_DATABASE: homestead
        DB_USERNAME: homestead
        DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
      run: |
        php artisan migrate
        vendor/bin/phpunit

  deploy:
    if: github.ref == 'refs/heads/master'
    needs: laravel-tests
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Deploy
        env:
          PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
          USER_NAME: ${{ secrets.USER_NAME }}
          HOST_NAME: ${{ secrets.HOST_NAME }}
        run: |
          echo "$PRIVATE_KEY" > private_key && chmod 600 private_key
          ssh -o StrictHostKeyChecking=no -i private_key ${USER_NAME}@${HOST_NAME} 'cd /var/www/ci'
```

ここでは、`Deploy`で行うテスト項目と、サーバーやAWSアカウントについての設定が増えました。また、`pull_request`時にテストが`develop`ブランチでも行うことができるようになっています。

そうしたら、githubの`Setting`から`${{ secrets.** }}`としてものたちの設定をしていきましょう。

| 名称 | 中身 |
| --- | --- |
|HOST_NAME|インスタンスのIPアドレス|
|USER_NAME| ec2-user |
|PRIVATE_KEY| 作成した秘密鍵の中身 |
 
```
# 秘密鍵の中身の確認方
$ cat ~/.ssh/id_rsa
```

ここで自分は、以下のようなエラーにはまりました。

```
 Deploy 
12
##[error]Process completed with exit code 1.
1
Run echo "$PRIVATE_KEY" > private_key && chmod 600 private_key
10
Warning: Permanently added '***' (ECDSA) to the list of known hosts.
11
bash: line 0: cd: /var/www: No such file or directory
12
##[error]Process completed with exit code 1.
```

これの解決策はシンプルでEC2に`/var/www`のディレクトリを用意してあげることで解決できそうですね。

```
$ sudo mkdir -p /var/www/ci
```

そりゃ、デプロイ用なのだから、公開する先がないといけないのは当たり前ですね。

あと、gitがないと怒られました。

```
$ sudo yum install -y git
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
$ test -d ~/.linuxbrew && eval $(~/.linuxbrew/bin/brew shellenv)
$ test -d /home/linuxbrew/.linuxbrew && eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)
$ test -r ~/.bash_profile && echo "eval \$($(brew --prefix)/bin/brew shellenv)" >>~/.bash_profile
$ echo "eval \$($(brew --prefix)/bin/brew shellenv)" >>~/.profile

$ brew install git
$ sudo yum remove git -y
```

# おわりに
これ、最初にサーバーにアプリケーションをあげるところから自動化できないのだろうか？その方法も調べていきたい。

# 参考

・[Continuous Integration with GitHub Actions and Laravel 6](https://medium.com/@robertodev/continuous-integration-with-github-actions-and-laravel-6-e6cb9aa5aea9)
・[Test automation for Laravel 7 and MySQL with GitHub Actions](https://medium.com/swlh/test-automation-for-laravel-7-and-mysql-with-github-actions-467493c2f7ed)
・[GitHub Actions で LaravelのCI/CD環境を構築する（MySQL, Deployer）](https://qiita.com/wim/items/7eb8386672fd114c2576)
・[Github ActionsでLaravel（EC2）のデプロイ（deploy）自動化](https://noumenon-th.net/programming/2020/05/08/github-actions/)
・[AmazonLinux2のgitはbrewで管理すると簡単](http://blog.serverworks.co.jp/tech/2019/12/13/amznlinuxbrew/)
・[Homebrew Documentation](https://docs.brew.sh/Homebrew-on-Linux)