どうも、シローです。
ここ最近は個人サービスの開発をしてました。
作ったのはこちら=>Emovee(https://emovee.org)
そこで今回は、GithubのActionを使ったCI/CDについてのお話をしようと思います。
GithubのActionsとは
ブランチに対するpushやPR(pull request)を送ったのをトリガーとして、
- ソースコードのビルドやテスト
- 運用環境に対するデプロイ
を行なってくれます。
ちなみに、このような機能をCI/CDと言われます。
公式(https://github.co.jp/features/actions)
Actionsのワークフローの書き方
ビルドやデプロイをまとめた一連の処理の流れをワークフローと呼びます。
ワークフローの設定方法は
- プロジェクトの「Actions」をクリック
- 「New Workflow」をクリック
- テンプレートを選択するか、自分で一から記述したい場合は「Set up a workflow yourself」をクリック
- 「Start Commit」を選択してプロジェクトのディレクトリの該当ブランチに「.github/workflows/xxx.yml」ファイルを作成する
- ローカル環境でブランチを最新にして「.github/workflows/xxx.yml」を編集する
もしくは、直接プロジェクトのディレクトリに「.github/workflows/xxx.yml」というファイルを作成してそれを編集することになります。
公式 => (https://docs.github.com/ja/actions/quickstart)
今回のCI/CDの対象となるプロジェクトの構成
リリースしたEmoveeというサービスは
- サーバサイド:Laravel6
- フロントサイド:Next.js
- データベース:MySQL5.8
- リバースプロキシ:Nginx
という構成で動かしてます。
ちなみ、LaravelとNext.jsの環境構築のリポジトリはこちらです=>(https://github.com/smithshiro/docker-adramelech)
もしよければこちらもご参考までに🙌
構成図
ワークフローの流れ
上記のアプリケーションをさくらVPSにデプロイするまでの流れをまとめると次のようになりました。
- CI/CDで使うPHPのバージョンをコンテナ(PHP-fpm)で使っているバージョンに合わせる
- docker-compose.yml、Next.js、Laravelで使用している環境変数ファイル「.env」を本番用に差し替える
- Laravelのソース配下でcomposerパッケージを更新して、vendorフォルダを生成する
- Next.jsのソース配下でnpmパッケージを更新して、node_modulesを最新にしてソースコードをビルドする
- デプロイ先のサーバに接続するためのSSHキーを取得する
- rsyncコマンドを使用して、2,3,4でビルドしたソースコードをデプロイ先のサーバに転送する
- デプロイ先のサーバでdocker-compose build + runを実行するためのスクリプトを起動させる
ワークフローのソースコードの中身
実際に今回僕が記述したワークフローのソースコードはこちらです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# This is a basic workflow to help you get started with Actions name: CI # Controls when the workflow will run on: # Triggers the workflow on push or pull request events but only for the master branch push: branches: [ master ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "build" build: # The type of runner that the job will run on runs-on: ubuntu-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v2 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: '7.4.22' - name: set env file run: | cp ./config/docker_prod_env ./.env cp ./config/laravel_prod_env ./src/server/.env cp ./config/next_prod_env ./src/front/.env - name: composer run: | composer validate composer install --no-dev composer dumpa working-directory: ./src/server - name: npm run: | yarn yarn build working-directory: ./src/front - name: Install SSH key uses: shimataro/ssh-key-action@v2 with: key: ${{ secrets.SSH_PRIVATE_KEY }} name: id_rsa known_hosts: ${{ secrets.KNOWN_HOSTS }} if_key_exists: replace - name: deploy run: | echo "${SSH_EMOVEE_PROD_USER}" echo "${SSH_EMOVEE_PROD_HOST}" rsync -rlOtcv -e 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' --exclude='docker/mysql/data/*' --exclude='node_modules' ./ ${SSH_EMOVEE_PROD_USER}@${SSH_EMOVEE_PROD_HOST}:/home/service-user/projects/emovee env: SSH_EMOVEE_PROD_USER: ${{ secrets.SSH_EMOVEE_PROD_USER }} SSH_EMOVEE_PROD_HOST: ${{ secrets.SSH_EMOVEE_PROD_HOST }} - name: execute start scripts run: | ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ${SSH_EMOVEE_PROD_USER}@${SSH_EMOVEE_PROD_HOST} "/bin/bash /home/service-user/projects/emovee/deploy_scripts/prod_deploy.sh" env: SSH_EMOVEE_PROD_USER: ${{ secrets.SSH_EMOVEE_PROD_USER }} SSH_EMOVEE_PROD_HOST: ${{ secrets.SSH_EMOVEE_PROD_HOST }} |
PHPのバージョンをDockerのコンテナ内で使用しているバージョン(7.4.22)に合わせる
composerでパッケージをインストールするときにcomposer.lock、composer.jsonで指定されているPHPのバージョンとずれていると「composer install」でエラーが起きますので、
「Setup PHP」で実行するPHPのバージョンを"7.4.22"に設定しました。
ワークフローの個々のステップは次のような構文になりまして、今回は第三者が作ったステップを利用するため「uses: shivammathur/setup-php@v2」としています。
ステップの構文
1 2 3 4 5 6 7 8 9 10 11 12 |
===1行のコマンドを実行するケース=== name: xxx run: xxx ===複数行のコマンドを実行するケース=== name: xxx run: | xxx xxx xxx ===第三者が作成したものを利用するケース=== name: xxx uses: xxx |
環境変数ファイルを本番用にセットする
このプロジェクトでは
docker-compose
- MySQLのパスワード
Next.js
- ホスティングしているURLのホスト
Laravel
- MySQLの接続情報
- 外部API接続のキー情報
などを開発環境と本番環境で違うため、
本番用の環境変数を「config」ディレクトリに格納して、デプロイ時に本番用の「.env」ファイルを生成しています。(.gitigoreで.envはソース管理されないようにしています)
そのため、「set env file」のステップではそれらの環境変数をセットするための記述をしています。
Laravelの「vendor」フォルダ、Next.jsのビルド用の「.next」フォルダの生成
Laravelの「vendor」フォルダ、Next.jsの「.next」フォルダは.gitignoreに追加されていないため、
デプロイ先で生成されている必要があります。
ここでは、CI/CDの段階でそれらのフォルダを生成するようにしています。
理由としては主に、サーバにデプロイ後に生成したすると実運用している環境でビルドに失敗すると利用できなくなる状態になってしまうリスクがあるためです。
そのため、ワークフロー内でビルドを成功させたものを後の「rsync」でデプロイ先のサーバに転送するようにしました。
デプロイ先のサーバに接続するための情報をSecretsから読み取る
デプロイ先のサーバにはSSHで接続します。
そのため、該当サーバにアクセスするためのIPアドレスや、プライベートキーをGithubの「Settings」=> 「Secrets」に設定した内容を読み込みます。
読み込み方は ${{ secrets.環境引数名 }}
とすれば良いです。
この例では「Install SSH Key」というステップでSSHキーを読み込んで、以降のステップで利用できるようにしています。
設定箇所
1 2 3 4 5 6 7 |
- name: Install SSH key uses: shimataro/ssh-key-action@v2 with: key: ${{ secrets.SSH_PRIVATE_KEY }} name: id_rsa known_hosts: ${{ secrets.KNOWN_HOSTS }} if_key_exists: replace |
rsyncで生成したファイル群をデプロイ先のサーバに転送する
rsyncコマンドを使って前のステップで環境変数ファイル「.env」やLaravelの「vendor」、Next.jsの「.next」をまとめたソースコードをデプロイ先のサーバに転送します。
1 |
rsync -rlOtcv -e 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' --exclude='docker/mysql/data/*' --exclude='node_modules' ./ ${SSH_EMOVEE_PROD_USER}@${SSH_EMOVEE_PROD_HOST}:/home/service-user/projects/emovee |
rsyncで転送するときに、
- 転送から除外するディレクトリの指定
- 転送するときのオプション指定
でつまずきました。
”転送から除外するディレクトリの指定”ではMySQLのデータベースの中身(docker/mysql/data*)、node_modulesの中身を除外するようにしています。
特にnode_modulesのディレクトリをそのまま転送しますと、時間が非常にかかりますので個人的には指定必須です。
また、オプションですが色々あって「-rlOtcv」となりました。詳しい意味はちょっと忘れましたがこれでうまく行ったのです。
デプロイ先のサーバにSSHして、「docker-compose build」、「docker-compose up -d」を実行する
ここまでの流れでソースコードをビルドしたものをデプロイ先のサーバに転送はできました。
なので最終ステップとして、最新になったDocker環境とソースコードでプロジェクトを再起動する必要があります。
その一連の流れをスクリプトとして「deploy_scripts/prod_deploy.sh」に記述して、SSHで接続した先でこれを実行するようにします。
deploy_scripts/prod_deploy.sh
1 2 3 4 5 6 7 8 9 |
#!/bin/bash cd /home/service-user/projects/emovee # ビルド時にパーミッションエラーになるため chmod -R 777 docker/mysql/data # イメージビルド&コンテナ起動 docker-compose down docker-compose build docker-compose up -d |
SSHでスクリプトを実行
1 |
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ${SSH_EMOVEE_PROD_USER}@${SSH_EMOVEE_PROD_HOST} "/bin/bash /home/service-user/projects/emovee/deploy_scripts/prod_deploy.sh" |
以上の流れでdocker-composeで構築したローカルの環境をGithubのActionsでデプロイ先のサーバで動かすことができました。
おっしまい^^
まとめ
- GithubのActionsではソースへのプッシュやPRをトリガーとしてソースのビルドやデプロイができる
- ビルドやデプロイの流れをワークフローという
- デプロイ先のサーバにソースを反映させるためには、ソースのビルド => rsyncで転送 => 再起動用のスクリプトを起動 という手順で可能