【Xserver】Github Actionsを利用してLaravelを自動デプロイする

【Xserver】Github Actionsを利用してLaravelを自動デプロイする

はじめに

本記事では、Github Actions を利用して Xserver に Laravel を自動デプロイする流れを説明しています。

WSL 環境化で作業をしていることや、SSH キーを作成していることを前提としているので初心者向けの記事ではありません。

作業環境

  • Windows11: 22H2(22621.1105)
  • WSL: Ubuntu-20.04 Version 2
  • Laravel: v9.19

前提条件

  • Xserver に SSH 接続ができる
  • GitHub アカウントを持っている

SSH 接続の設定はマニュアルがあるのでそれを参考にしてください。注意点としてパスワードフレーズ無しで SSH キーを生成して下さい。

パスフレーズ有りの SSH キーを使用すると、今回作成する GitHub Actions のワークフローの SSH 接続時にエラーになります。

ダウンロードした秘密鍵はデフォルトではXserver のユーザー名.keyという名前でダウンロードされます。その秘密鍵を WSL の.ssh/ディレクトリ配下に配置しています。

今回使用するリポジトリ

リポジトリのディレクトリ構成は以下のようになっています。Laravel のプロジェクトが格納されているsrcディレクトリをサーバにデプロイしていきます。

Docker を使用した開発環境で実施していますが、自動デプロイのワークフロー自体は開発環境に依存していませんのでご自身の環境に合わせて変更して下さい。

laravel-demo-app
├── .devcontainer
│   ├── Dockerfile
│   ├── devcontainer.json
│   ├── docker-compose.yml
│   ├── mysql
│   └── web
├── .github
│   └── workflows
│       └── deploy.yml # ←今回作成していくワークフロー
├── .vscode
│   └── launch.json
└── src # ← デプロイするLaravelプロジェクト
    ├── .editorconfig
    ├── .env
    ├── .env.example
    ├── .gitattributes
    ├── .gitignore
    ├── .prettierignore
    ├── .prettierrc
    ├── README.md
    ├── app
    ├── artisan
    ├── bootstrap
    ├── composer.json
    ├── composer.lock
    ├── config
    ├── database
    ├── lang
    ├── package.json
    ├── phpstan.neon
    ├── phpunit.xml
    ├── public
    ├── resources
    ├── routes
    ├── storage
    ├── tests
    ├── vendor
    └── vite.config.js

ワークフローの作成

該当のリポジトリに.github/workflowsというディレクトリを作成します。そのディレクトリ配下に、ワークフローの設定を定義するために yml ファイルを作成します。

今回はdeploy.ymlと言う名前にしました。

".github/workflows/deploy.yml"
name: deploy to production-xserver

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    defaults:
      run:
        working-directory: ./src

    steps:
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: "8.1.12"
      - name: Checkout repository
        uses: actions/checkout@v3
      - name: Copy .env
        run: php -r "file_exists('.env') || copy('.env.example', '.env');"
      - name: Composer Install
        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: Deploy to Server
        uses: burnett01/rsync-deployments@5.2.1
        with:
          switches: -avzr --delete
          path: src/
          remote_path: ${{ secrets.PRODUCTION_DEPLOY_REMOTE_PATH }}
          remote_host: ${{ secrets.DEPLOY_HOST }}
          remote_port: ${{ secrets.DEPLOY_PORT }}
          remote_user: ${{ secrets.DEPLOY_USER }}
          remote_key: ${{ secrets.DEPLOY_KEY }}

基本的な設定や設定の意味など、公式ドキュメントで詳しく説明されているので興味がある方は一度目を通してみて下さい。ここでは自動デプロイするための設定に絞って説明していこうと思います。

PHP のバージョン指定

shivammathur/setup-phpというアクションを使用して PHP のバージョンを指定しています。今回は Xserver の PHP のバージョンに合わせています。

- name: Setup PHP
  uses: shivammathur/setup-php@v2
  with:
    php-version: '8.1.12'

Composer のインストールまで

actions/checkoutはリポジトリをチェックアウトし、ワークフローがそのリポジトリにアクセスできるようにしています。ほぼどのワークフローでも使用するアクションだと思います。

詳細な設定は README に記述されています。特に複雑な処理はしないのでここでは割愛します。

- name: Checkout repository
  uses: actions/checkout@v3

ここでは PHP のfile_exists メソッドを使用して.envファイルがリポジトリ内に存在しているか確認しています。ファイルが存在すればtrueを返し、そうでなければfalseを返すメソッドです。

.envファイルを git で管理することは無いと思うので、常に.env.exampleから.envファイルがコピーされる処理が実行されると思います。

- name: Copy .env
  run: php -r "file_exists('.env') || copy('.env.example', '.env');"

ここでは composer install を実行して Laravel の初期設定を実行しています。

- name: Composer Install
  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

composer のオプションに関しては以下の表にまとめました。

オプション意味
-q (--quiet)実行時のメッセージを出力しない
--no-ansiANSI カラーを使用せずにメッセージを出力する
-n (--no-interaction)対話型のメッセージを表示しない
--no-scriptscomposer.json で指定されたスクリプトの実行を飛ばす
--no-progressダウンロードの進行状況を表示させない
--prefer-distインストールするパッケージを、zip 形式でダウンロードして展開する。
--prefer-sourceインストールするパッケージを、ソースから clone する。--prefer-distオプションの方が高速

自動デプロイ

- name: Deploy to Server
  uses: burnett01/rsync-deployments@5.2.1
  with:
    switches: -avzr --delete # rsyncコマンドのオプションを指定
    path: src/ # デプロイするディレクトリを指定
    remote_path: ${{ secrets.PRODUCTION_DEPLOY_REMOTE_PATH }}
    remote_host: ${{ secrets.DEPLOY_HOST }}
    remote_port: ${{ secrets.DEPLOY_PORT }}
    remote_user: ${{ secrets.DEPLOY_USER }}
    remote_key: ${{ secrets.DEPLOY_KEY }}

burnett01/rsync-deploymentsというアクションを使用して、Xserver にデプロイする処理を実行します。このアクションはファイルを ssh 経由の rsync でリモートフォルダにデプロイします。

${{ }}で指定している内容は、リポジトリの環境変数に登録したデプロイ先のサーバの情報や秘密鍵の情報を呼び出しています。

環境変数はリポジトリの SettingsSecrets and variablesActions で設定します。

action-secrets-and-variables

New repository secret ボタンをクリックして環境変数を指定していきます。

オプション意味
DEPLOY_HOSTホスト名
DEPLOY_KEYXserver の SSH 秘密鍵(テキスト)
DEPLOY_PORTポート番号
DEPLOY_USERユーザー名
PRODUCTION_DEPLOY_REMOTE_PATHデプロイ先のディレクトリ

デプロイ先のディレクトリはドメインの公開ディレクトリ直下に配置するのではなく、Xserver に SSH 接続した際のホームディレクトリ配下にproduction/laravel-demo-appと言うディレクトリを作成して、そこを指定しています。

なので、PRODUCTION_DEPLOY_REMOTE_PATHには$HOME/production/laravel-demo-appを指定しています。$HOMEはユーザーのホームディレクトリの環境変数ですので、契約したサーバ毎に環境は異なってきます。

コマンドから確認することも出来ます。

$ echo $HOME
/home/ユーザー名

秘密鍵の登録

DEPLOY_KEY の設定では作成した秘密鍵の内容を指定します。

秘密鍵のコピーはコマンドから実行すると不要な空白など含まれないので便利です。WSL 上から Windows 上のクリップボードにコピーするには以下のコマンドを実行します。

cat ~/.ssh/xs010410.key | clip.exe

ブランチに push する

ワークフローを作成したら main ブランチに push して正常に動作するか確認します。エラーなく実行が完了すると下記の画像のよう表示になります。

execute-actions

Xserver で公開設定

Xserver 側で$HOME/production/laravel-demo-appを公開する設定をします。前提として以下のことを実施しておいて下さい。

  • ドメイン、もしくはサブドメインを取得して Web サイトを公開できる領域を確保しておく

今回はサブドメインとしてdemo-app.hn-pgtech.comを作成しているので、そこにシンボリックリンクを作成していきます。シンボリックリンクとは Windows で言うところのショートカットのようなものでhttps://demo-app.hn-pgtech.com/laravel-demo-app/にアクセスすると、$HOME/production/laravel-demo-app/publicを参照する設定を行います。

$ ln -s $HOME/production/laravel-demo-app/public $HOME/hn-pgtech.com/public_html/demo-app.hn-pgtech.com/laravel-demo-app

https://demo-app.hn-pgtech.com/laravel-demo-app/ にアクセスして Laravel のトップページが表示されたら正常に動作しています。

laravel-top-page

データベース接続設定

.envファイルをワークフロー内で.env.exampleから作成していますが、データベースへの接続やデバッグをfalseにする設定を行っていないので本番環境用の設定をします。

.envファイルの内容も Secrets 環境変数に指定していきます。

Xserver の管理画面で今回使用するデータベースは作成しておいて下さい。ユーザー名とパスワードは.envファイルに指定するので控えておいてください。

管理画面からデータベースを作成する方法は以下のマニュアルを参照して下さい。

base64 でエンコードした.env の内容を登録する

本番環境用の.envファイルの内容を Secrets 環境変数に登録して、ワークフロー中でその内容を出力すれば実現できると考えていたのですが、改行が空白に変換されておりphp artisan key:generate実行時にエラーとなっていました。

encountered-unexpected-whitespace-at

Failed to parse dotenv file. Encountered unexpected whitespace at

色々検索していたところ、.envファイルの内容を base64 でエンコードして Secrets 環境変数に登録し、ワークフロー内でデコードすれば改行も含まれた内容を登録できました。以下の記事を参考にさせてもらいました。

base64 に関してここでは深く触れませんが、データを 64 種類の英数字a~z, A~zと一部の記号+-を用いてエンコードする方式です。以下の記事が大変参考になったので、もっと深く知りたい方は読んでみて下さい。

.envファイルの内容のエンコードはbase64 エンコード/デコードツールを使用しました。

エンコードしたい.envファイルの内容を貼り付けて base64 に変換します。

env-encode-base64

変換されたコードを Secrets 環境変数に登録して下さい。

env-add-secrets

yml ファイルの修正

yml ファイルに.envに関する記述を追記します。

".github/workflows/deploy.yml"
name: deploy to production-xserver

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    defaults:
      run:
        working-directory: ./src

    steps:
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: "8.1.12"
      - name: Checkout repository
        uses: actions/checkout@v3
+     - name: Setting .env
+       env:
+         PRODUCTION_LARAVEL_ENV: ${{ secrets.PRODUCTION_LARAVEL_ENV }}
+       run: |
          php -r "file_exists('.env') || copy('.env.example', '.env');"
+         echo $PRODUCTION_LARAVEL_ENV | base64 --decode > .env
      - name: Composer Install
        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: Deploy to Server
        uses: burnett01/rsync-deployments@5.2.1
        with:
          switches: -avzr --delete
          path: src/
          remote_path: ${{ secrets.PRODUCTION_DEPLOY_REMOTE_PATH }}
          remote_host: ${{ secrets.DEPLOY_HOST }}
          remote_port: ${{ secrets.DEPLOY_PORT }}
          remote_user: ${{ secrets.DEPLOY_USER }}
          remote_key: ${{ secrets.DEPLOY_KEY }}

修正した内容を説明していきます。

- name: Setting .env

ステップの名前をCopy .envから変更しました。

env:
  PRODUCTION_LARAVEL_ENV: ${{ secrets.PRODUCTION_LARAVEL_ENV }}

ステップごとに使用する環境変数を設定しています。設定した環境変数をecho $PRODUCTION_LARAVEL_ENVのようにステップ内で展開することが出来ます。

ここで指定している値は先程 base64 に変換した.envファイルの内容になります。

run: |
  php -r "file_exists('.env') || copy('.env.example', '.env');"
  echo $PRODUCTION_LARAVEL_ENV | base64 --decode > .env

出力した環境変数の値(標準出力)を bash のパイプ機能を使用してデコード(base64 から復元)した後、.envファイルに出力しています。

リダイレクトやパイプなど初めて見た方は、bash 入門 というサイトに目を通しておくと良いかもしれません。

再びワークフローを実行語、Xserver に SSH 接続して本番環境の設定が記載された.envファイルが作成されていることを確認して下さい。

その後php artisan migrateを実行して正常にデータベースと接続できることを確認して下さい。

注意点

Laravel の認証機能で Laravel Breeze をインストールした場合は npm コマンドでビルドする必要があります。

Xserver 側に Node.js をインストールして SSH 接続した後に npm を実行できるように環境を整えても良いのですが、めちゃくちゃ面倒なので出来るだけそんなことはしたくありません。

ワークフロー内で npm ビルドも実行出来るようにします。

ワークフローに Node.js をインストールする処理を追加する

actions/setup-node というアクションを使用してワークフロー内で使用する Node.js のバージョンを指定します。

その後、package.json内のscriptsのコマンドを実行します。

name: deploy to production-xserver

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    defaults:
      run:
        working-directory: ./src

    steps:
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: "8.1.12"
      - name: Checkout repository
        uses: actions/checkout@v3
      - name: Setting .env
        env:
          PRODUCTION_LARAVEL_ENV: ${{ secrets.PRODUCTION_LARAVEL_ENV }}
        run: |
          php -r "file_exists('.env') || copy('.env.example', '.env');"
          echo $PRODUCTION_LARAVEL_ENV | base64 --decode > .env
      - name: Composer Install
        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: Use Node.js ${{ matrix.node-version }}
+       uses: actions/setup-node@v3
+       with:
+         node-version: 16.x # 開発環境のバージョンと合わせて下さい
+     - name: npm build
+       run: npm install && npm run build
      - name: Deploy to Server
        uses: burnett01/rsync-deployments@5.2.1
        with:
          switches: -avzr --delete
          path: src/
          remote_path: ${{ secrets.PRODUCTION_DEPLOY_REMOTE_PATH }}
          remote_host: ${{ secrets.DEPLOY_HOST }}
          remote_port: ${{ secrets.DEPLOY_PORT }}
          remote_user: ${{ secrets.DEPLOY_USER }}
          remote_key: ${{ secrets.DEPLOY_KEY }}

最後に

Github Actions を利用して Laravel を Xserver に自動デプロイする方法についてまとめました。今回は Xserver でしたが、SSH 接続出来るプランなら他のサーバでも利用可能だと思います。

その他、ワークフロー中に自動テストを走らせてテストが通らなければワークフロー中止したり、デプロイ後にマイグレーションコマンドを実行したりすることも出来ます。

今回の記事ではそこまで紹介していませんが、興味がある方は是非実践してみて下さい。