「PHPアプリをレンタルサーバーで運用しているんだけど、GitHubにコミットしたら自動で変更ソースをアップしてくれないかな」
こんにちは、カフーブログのタカフです。
このカフーブログはWordPressで作っていてWebエンジニアでもある僕はわりと独自のカスタムコードも入れたりしているのですが、
そのようにPHP側で新たに変更があったら手動でソースコードをサーバーにアップするのではなく、出来ればこのあたりは自動で変更コードがサーバーにアップされるようにしたいですよね。
僕はソース管理にGitHubを使っているのですが、例えばGitHubのmasterブランチに変更ソースがコミットされたら本番サーバーに自動でソースコードがアップロードされるのが理想です。
このあたりの一連の自動アップロードする流れは、CI/CD (継続的インテグレーション/継続的デリバリー)と言って JenkinsとかCircleCIとかを利用するのが主流でしたが、
僕も使っているGitHubにもちょっと前にGitHub Actionsなる機能が追加されこういったデプロイ処理が出来るようになったのでこのWordPressブログでもそれを組み込んでみることにしてみました。
本記事では、GitHub Actionsを使ってさくらのレンタルサーバーにSSHでソースをアップロードする方法の紹介となります。
僕はさくらサーバーを使っていますが、本記事を読めばXServerやその他SSHが使えるサーバーなら同様の事が出来るかと思います。
GitHub ActionsでSSHデプロイの設定手順
GitHub からPHPデプロイのサンプルコードを取得
まずはGitHub Actionsで使うサンプルコードを取得します。
GitHubのActionsのタブを開きますと、WordkflowsのサンプルとしてPHPがあるので「Set up this workflow」を押下します。
そうすると、GitHub Actionsで動かす為のPHP版のデプロイテンプレートコードが見えます。
とは言っても中身は軽く目を通してもらえればわかりますが、初期状態ではPHPプロジェクトにありがちなcomposerのインストールするだけとなっています。
name: PHP Composer
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Validate composer.json and composer.lock
run: composer validate
- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v2
with:
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-
- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer install --prefer-dist --no-progress --no-suggest
# Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit"
# Docs: https://getcomposer.org/doc/articles/scripts.md
# - name: Run test suite
# run: composer run-script test
ですが、GitHubから提供してくれているこのPHPのデプロイコードがある意味PHPデプロイの初期コードとも言えるので、これを元に自分のサーバーにデプロイする処理を追加していきましょう。
因みに上記の初期コードで便利なのがcomposerのキャッシュをしているところです。
毎回デプロイのたびにcomposerでライブラリを取ってくると時間もかかってしまいますが、このキャッシュする書き方によってその時間が短縮されcomposer installの箇所が速くなります。
GitHub Actionsにおいて「月あたりに利用できるジョブ実行時間上限」は無料版だと2000分と決まっているので実行時間は短くするにこしたことはありません。
さて、GitHub Actionsを動かすにはプロジェクト上の規定の位置にymlファイルを配置する必要があります。
それが、プロジェクトルートからの.github/workflows/[お好きなファイル名].yml
の場所です。
上記で取得したコードををそのまま、.github/workflows/deploy.yml
とでもしてプロジェクト内に配置しましょう。
SSHに関する情報をGitHubに登録
デプロイはSSHでリモートサーバーに対してrsyncを実行するのですが、SSHする時の秘密鍵情報はGitHubのリポジトリに入れるべきではありません。
そこで一般的にはGitHub上に秘密鍵情報を登録する機構があるのでそれを利用します。
対象リポジトリの「Settings」-「Secrets」の「New repository secret」からキーとその値を登録します。
このように登録しておけばGitHub Actionsの実行時にこれを変数として扱うことが出来ます。
そして、SSHが出来るサーバーならここを変えるだけでどこにでもデプロイ出来ることをも意味します。
ここでは、SSH_HOST
, SSH_PORT
, SSH_PRIVATE_KEY
, SSH_USERNAME
を登録しておきます。
デプロイコードにSSHでrsyncする処理を追記
まず、 masterブランチに変更コードが入った時だけキックされるようにしたいのでdeploy.ymlからは
pull_request:
branches: [ master ]
は消します。pushイベントだけで、普通のプッシュの時もプルリクマージの時もキックされます。要するにコミットされた時です。
次に、デプロイするymlファイルの配置とSSH情報が登録出来ているので、あとはSSHでrsyncする処理を追記するだけです。
今回の場合だと以下のようなコードをdeploy.ymlファイルに追記します。
# 秘密鍵を設置
- name: ssh key generate
run: |
mkdir -p ~/.ssh/
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
# ssh rsync実行
# -a コピー元のディレクトリを再帰的にオーナー・グループ・パーミッション・タイムスタンプをそのままコピーします。
# -h でファイルサイズの視認性をよくする。
# -v 詳細を出力する。
# -z 圧縮転送
# -e ssh指定
- name: Deploy
run: rsync -ahvz -e "ssh -i ~/.ssh/id_rsa -p ${{ secrets.SSH_PORT }} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" ./ ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }}:/var/www/html/ --include-from=".github/rsync_include.txt" --exclude-from=".github/rsync_exclude.txt"
最初に秘密鍵をGitHub Actionsで動かしているマシンのよくある.sshディレクトリに書き出して適切なパーミッションにします。
先程登録したSSH_PRIVATE_KEY
は${{ secrets.SSH_PRIVATE_KEY }}
という書式で取得出来ます。
次にrsyncコマンドの実行です。このようなリモートサーバーに対してrsyncする場合は上記のようなオプションがよいかと思います。オプションの説明も書いておきました。
ファイル削除も同期してくれる--delete
オプションは今回つけていません。こちらは案件に応じてつけてください。
また、-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no
はSSHで警告メッセージを出さないようにするオプションです。
今回は個人ブログに対してのデプロイだったのこのオプションをつけていますが、こちらも案件に応じてこのオプションがなくても良い記述をすべきです。
(でもググるとほとんどこのオプションはつけてますね。。)
そして、今回のrsyncのポイントとしては煩雑になりがちなデプロイ対象のディレクトリと対象でないディレクトリの設定を外部ファイルで記述しているところです。
コマンドラインでそれらを書いていくとどうしても管理しにくくなりますが、このように外部ファイルにデプロイ対象のファイルやディレクトリを書いて –include-from と –exclude-from のオプションで指定すると楽だしわかりやすいです。
以下に例を示します。
/app/
/conf/
/wordpress/
/vendor/
/*
/wordpress/wp-content/uploads/
rsync-include.txt
にプロジェクトルートからの指定で列挙します
次にrsync-exclude.txt
でデプロイを除外したいパスを指定していきます。
まず/*
でプロジェクトルートのファイルを全て除外しています。REAME.mdとかcomposer.jsonとかプロジェクトルートにありがちなファイルの除外しています。
そしてデプロイ対象ディレクトリの中でも除外するディレクトリを加えている形です。
GitHub ActionsではGitからファイルを新規でcheckoutしてるのでWordPressのuploadsのような動的ディレクトリはあるわけないのですが、ローカル環境からこのデプロイを試す時の為に記述しています。
あ、これは超重要ですが、このようにデプロイでrsync処理を書く時は絶対にローカル環境から開発環境などで試してちゃんと動くことを確認してコミットするようにしましょう。
予期せぬディレクトリを書き換えたり、予期せぬディレクトリを削除してしまわない為です。
(追記)デプロイするときのPHPバージョンを指定する
ここは運用していて気付いた章となります。
実際GitHub Actionsを使ってデプロイを実行していたらある時composer install時のエラーでデプロイが止まることがありました。
Error: Your lock file does not contain a compatible set of packages. Please run composer update.
Problem 1
- abraham/twitteroauth is locked to version 1.2.0 and an update of this package was not requested.
- abraham/twitteroauth 1.2.0 requires php ^7.2 || ^7.3 || ^7.4 -> your php version (8.0.0) does not satisfy that requirement.
ファッ!? PHP8.0!? いやそんな最新のPHPなんて使った覚えないんですが。。
どうやら、GitHub Actionsで動かすデプロイ時のPHPは最新バージョンを使うみたいですね。
レンタルサーバーがPHP7.4なのでここはデプロイ時のPHPバージョンも7.4を指定すればOKでしょう。
以下のページのようにすれば良いようです。
https://github.com/shivammathur/setup-php
このページに書いてあるコードを参考に以下のようにしました。
steps:
# まずはこのブランチのチェックアウトを行う
- uses: actions/checkout@v2
# このPHPアプリのPHP Versionの指定とcomposerの指定を行う
- name: Setup PHP with composer v2
uses: shivammathur/setup-php@v2
with:
php-version: '7.4'
tools: composer:v2
checkout後にPHPバージョンを指定しました。
無事PHPのバージョンが指定出来てcomposer installが通るようになりました。
GitHubでmasterにコミットされるとデプロイ実行
deploy.ymlをプロジェクトに含めて実際にmasterまでコミットされるとデプロイが実行されます。
これは何回か動かした時のGitHub Actionsの画像ですが composer install周りはキャッシュが効いて一瞬で終わっていますね。
そしてDeployのところは44秒で完了しています。
これで本番サーバーまでデプロイされることを確認出来ました。
まとめ
今回はGitHubにコミットされたらGitHub Actionsがキックされて自動でそのソースコードをアップする仕組みの説明でした。
こういった自動化はセットアップするまでは大変ですが、一度やってしまえばその後ずっと楽できることとなり、結果的に開発速度を加速させることとなります。
それは最終的な収益に直結するので是非やっていきましょう!
現場からは以上です!