GitHub Actions上でDeployerを使ってPHPアプリケーションを自動デプロイする

# はじめに


今まで [仕事](https://tech.quartetcom.co.jp) ではCircleCIを使ってCI/CDを構成してきたのですが、 [副業](https://www.wantedly.com/projects/475929) ではGitHub Actionsのほうを利用することになったので、色々調べながら試してみました。
要件としてはこんな感じです。

- PHPアプリケーションなのでデプロイには [Deployer](https://deployer.org/) を使う
- Linux系の普通のWebサーバーにコードのみデプロイ（ECRにコンテナイメージを登録、みたいなユースケースではない）
- mainにpushされたらステージングへ、releaseにpushされたら本番へデプロイする
- デプロイはテストが通ってから実行する

試行錯誤の末、なんとか動くようになったので、完成品のyamlをみながら気をつけるポイントをメモしてみました。


# .github/workflows/cd.yml のサンプル

```yaml

jobs:
  run-test:
    # 省略
  deploy-staging: # ★1
    if: github.ref == 'refs/heads/main' # ★2
    needs: run-test # ★3
    runs-on: ubuntu-latest # ★4
    steps:
      - uses: actions/checkout@v2 # ★5
      - name: Setup SSH for staging 
        run: mkdir -p ~/.ssh && echo "${{secrets.STAGING_KEY}}" > ~/.ssh/id_rsa && chmod 0600 ~/.ssh/id_rsa # ★6
      - name: Setup Deployer
        run: curl -LO https://deployer.org/deployer.phar && mv deployer.phar ./dep  && chmod +x ./dep # ★7
      - name: deploy to staging
        run: ./dep deploy staging -vvv
        env:
          DEPLOYER_SSH_USER: foobarstaging # ★8
          OAUTH_TOKEN_GITHUB: ${{secrets.OAUTH_TOKEN_GITHUB}} # ★9
  deploy-production: # ★10
    if: github.ref == 'refs/heads/release' # ★11
    needs: run-test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Setup SSH for production
        run: mkdir -p ~/.ssh && echo "${{secrets.PRODUCTION_KEY}}" > ~/.ssh/id_rsa && chmod 0600 ~/.ssh/id_rsa # ★12
      - name: Setup Deployer
        run: curl -LO https://deployer.org/deployer.phar && mv deployer.phar ./dep  && chmod +x ./dep
      - name: deploy to prod
        run: ./dep deploy production -vvv # ★13
        env:
          DEPLOYER_SSH_USER: foobarprod
          OAUTH_TOKEN_GITHUB: ${{secrets.OAUTH_TOKEN_GITHUB}}
```

★をつけたところが気になるところかと思います。
以下、一項目ずつメモしていきます。

## ★1 stagingにデプロイするジョブとして名前をつける

実行ジョブのログを見るときに、どこにデプロイしたものか後で見るためにもわかりやすい名前をつけます。

## ★2 mainにマージされたときだけ発動する

ifがtrueにならない場合はデプロイジョブは実行されません。

## ★3 テストが通ってからデプロイに入る

needsで指定したジョブが成功しない場合はデプロイジョブは実行されません。

## ★4 ubuntu-latestイメージでOK

テストを実行するジョブと違い、デプロイジョブではDeployerだけを動かすので、自分のアプリケーションが利用しているバージョンに縛られることはありません。
GitHub Actions提供のubuntu-latestイメージのPHPのバージョンは調べてないので知りませんが、Deployerが動くには十分でした。

## ★5 checkoutは必要

Deployer用の設定ファイル `deploy.php` は通常のPHPファイルと同じくレポジトリにコミットされているので、checkoutは必要です。

## ★6 Secretsにデプロイ先サーバーにログインできる秘密鍵を置いておき、鍵ファイルに書き込む

普通にDeployerを使うとSSH接続を利用することになると思うので、デプロイ先サーバーにログインできる秘密鍵をGitHub Actionsの実行時に持たせておく必要があります。
ローカルでSSH用の鍵を新たに作成し、GitHubレポジトリの `Secrets` に秘密鍵・デプロイ先サーバーでデプロイ時に使うユーザーのauthorized_keysに公開鍵を登録しておきます。
※ 人間がログインするユーザー・鍵と同じにすることはオススメしません。（問題があったときにデプロイ先サーバー側のログできりわけられないので）

鍵ファイルのパーミッションを変え忘れるとエラーになるので気をつけましょう。

## ★7 Deployerのpharをダウンロードして実行可能にする

予めpharを取得したものをレポジトリにコミットしておいてもいいかもしれません。
一度レポジトリにコミットしてしまうと最新版にupdateするのが面倒なのと、大した実行時間がかからんだろうという見込みのもとに、今回は直接ダウンロードすることにしています。

## ★8 秘密じゃない環境変数が必要なら直接envを書いても良い

SSHユーザー名を設定したのはサンプルです。
そこまで厳密に秘密にしなくても良さそうな情報を環境変数経由でDeployerに渡したいときはここで直接設定することもできます。

## ★9 秘密にしたい情報をdeployerに渡したいときは一回envを経由する

`getenv('secrets.OAUTH_TOKEN_GITHUB')` の名前ではdeploy.phpにうまく値が渡りませんでした。
ちなみに、 `GITHUB_` から始まる名前では `Secrets` として登録できないよう（何度やっても登録失敗しました。予約語的なやつと思われます）なので命名は注意しましょう。

## ★10 productionにデプロイするジョブとして名前をつける

★1と同様、productionにデプロイすることがわかる名前をつけます。

## ★11 releaseブランチにpushされたとときのみ発動

本番にデプロイしたいのはreleaseブランチにpushされたときだけなので、忘れず指定します。

## ★12 production用の鍵をセット

ステージングのときと同様、productionサーバーにログインできる鍵をセットします。
パーミッション変更も忘れずに。

## ★13 deployerの向き先をproductionにしている

Deployer用の設定ファイル `deploy.php` に指定したstage名を本番用のものにしています。