GitHub Actions が正式リリースされましたね。
これで外部サービスを使用しなくても GitHub 単体で CI/CD などのワークフローを自動化できるようになりました。
https://github.com/features/actions
弊社は社内の GitLab でソースコード管理+ CI/CD していますが、ちょうど担当していた案件の納品先が GitHub ということもあり、Laravel + Vue アプリケーションをビルドし本番サーバにデプロイするところまでを実装してみました。
ゴール
特定のブランチに push すると自動で本番環境にデプロイする
流れ
ワークフローとして実行するタスクはこんな感じです。
- 特定のブランチ(master)へのプッシュ(or プルリク) をトリガーにワークフローを起動
- GitHub 上で docker コンテナを起動
- 以下コンテナ上で
- git clone (ソースコード取得)
- composer install (PHP環境構築)
- npm install (node環境構築)
- npm run prod (フロントエンドビルド)
- rsync でコンテナ上で構築したファイルを本番サーバへ転送
秘匿情報をいかにセキュアに管理するか
今回の案件ではフロントエンド(Vue.js)=>バックエンド(Laravel)間の API 通信の認証に Laravel Passport を使用していました。Laravel Passport では認証用のトークンをフロントエンドのコードに含めてビルドする必要があるため、トークンをコンテナ内に持ち込む必要がありますが、他にも DB のパスワードや、AWS のトークンなど、またビルドした成果物を rsync + ssh で本番サーバに同期する際の秘密鍵、などなど、知られてはいけない情報が多々あり、当然これら セキュアな情報を記載したコードをリポジトリにコミット出来ない問題 に直面します。
秘匿情報は Secrets に保存
これを解決するために、GitHub のリポジトリ設定画面には Secrets というメニューが追加されており、セキュアな情報に名前を付けて保存できます。これは GitHub Actions だけに使用する目的で追加された機能で、
Secrets are environment variables that are encrypted and only exposed to selected actions. Secrets are not passed to workflows that are triggered by a pull request from a fork of this repository.
とある通り、情報は暗号化され、選択されたアクションにのみ使用されれます。リポジトリのフォークで継承されることもなく、また、他のコントリビューターからも閲覧されることはありません。(そもそも登録した本人でさえ一度登録した内容は閲覧できません)
Secrets は、GitHub のリポジトリメニューの「Settings」からサイドメニューの「Secrets」より遷移し、「Add a new secret」をクリックして、Name と Value を登録します。
今回はここに、Laravel Passport の認証用トークン OAUTH_CLIENT_SECRET
と rsync で使用する SSH の秘密鍵 SSH_PRIVATE_KEY
を登録しました。これらの Name はワークフローの定義時に変数として使用することができるので後述の定義ファイル自体はセキュアな記述となります。
MIX_OAUTH_CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }}
ワークフローの作成
それではワークフローを作っていきましょう。リポジトリのタブメニューにある Actions をクリックすると予め用意されたワークフローが表示されます。これから作成するワークフローに近いものがあればそれをテンプレートとして使用しても良いですが、今回は使用しません。実は画面から作成しなくても、定義ファイルを直接リポジトリに追加しプッシュすればワークフローとして認識します。
定義ファイルは下記のパスになります。
.github/workflows/main.yml
拡張子からも分かる通り、GitHub Actions ではワークフローを YAML 形式で定義します。
name: 本番サーバへのデプロイ
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: バックエンドの準備
run: composer install
- name: フロントエンドのビルド
run: npm install && npm run prod
env:
MIX_OAUTH_CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }}
APP_ENV: "production"
APP_DEBUG: "false"
APP_URL: "https://xxxxxx.test"
- name: 秘密鍵のコピー
run: echo "$SSH_PRIVATE_KEY" > id_rsa && chmod 600 id_rsa
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
- name: ファイルをサーバに同期
run: rsync -rlOtcv --delete --exclude-from=.rsyncignore -e "ssh -i id_rsa -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" ./ deploy@xxxxxxx.test:/var/www/vhost/xxxxxxxx/
このファイルをpushするだけで指定したブランチに更新があった際にワークフローが開始されます。
ファイルの解説
簡単に定義ファイルの中を見ていきましょう。
name: (ワークフローの名称)
name: 本番サーバへのデプロイ
このワークフローの名前を定義します。GitHub のサイト上から見えるためわかりやすいものにしましょう。日本語も可能です。
on: (アクション起動条件)
on:
push:
branches:
- master
トリガーとなる条件を記述します。ここでは master ブランチに push があった場合の条件を指定しています。
runs-on: (コンテナの指定)
runs-on: ubuntu-latest
使用するコンテナを指定します。windows や macos も指定できるのでネイティブアプリのビルドなども可能。
steps: (アクションの定義)
steps:
ここからワークフローをステップごとに定義します。
uses: (既存のアクションの使用)
- uses: actions/checkout@v1
GitHub Actions は既に用意されたアクションや、GitHub Marketplace に公開されている自作アクションを部分的に使用することができます。ここでは actions/checkout と言うアクションを使用し、リポジトリから最新のソースを clone しています。
バックエンドの準備
- name: バックエンドの準備
run: composer install
このステップでは run
アクションで composer install
コマンドを実行しています。
フロントエンドのビルド
- name: フロントエンドのビルド
run: npm install && npm run prod
env:
MIX_OAUTH_CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }}
APP_ENV: "production"
APP_DEBUG: "false"
ここではフロントエンドのビルドを実行しています。run
アクションで npm install
と npm run prod
を実行し、Vue.js のソースをトランスパイルしています。
また、前述のトークンや環境ごとの依存情報などは、本来 .env に記述しますが、リポジトリには追加したくないため環境変数経由で Secrets の値を渡しています。
秘密鍵のコピー
Secrets に保存した SSH プライベートキーを環境変数経由でファイルに書き出しています。パーミッションも忘れずに。
- name: 秘密鍵のコピー
run: echo "$SSH_PRIVATE_KEY" > id_rsa && chmod 600 id_rsa
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
ファイルをサーバに同期
あとは成果物をサーバに rsync+ssh でコピーするだけです。転送量を節約するため .rsyncignore に不要なファイルを定義し、いくつかのフォルダを除外しています。
- name: ファイルをサーバに同期
run: rsync -rlOtcv --delete --exclude-from=.rsyncignore -e "ssh -i id_rsa -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" ./ deploy@xxxxxxx.test:/var/www/vhost/xxxxxxxx/
#####.rsyncignore
.env
.git
.github
node_modules/
storage/
いざ実行
ワークフローの実行は on
で指定したタイミングでの自動起動なので、master ブランチに git push するだけです。
GitHub の Actions タブをクリックすると実行中のタスクをリアルタイムにチェックできます。
まとめ
社内の GitLab では、CI/CD をフル活用しておりユニットテストやLintチェックなどを常に自動化していますが、自社サーバに構築しているので環境を自前で構築する必要があったりスペックに悩まされてきましたが、GitHub Actions ではいとも簡単にできてしまいました。Marketplace での Action も充実してくると思うので今後さらに期待ができますね。非常に楽しみです。