こんにちはjunです。皆さんはVueやReact、Nuxtなどなどフロントエンドフレームワークやライブラリを使っていますでしょうか?これらのライブラリはフロントの構築が楽になりますが、一度Node.jsを用いてビルドする必要があります。そしてビルドしたファイルを読み込ませることで動作します。
ローカルの環境ではNode.jsがあるので問題ないですが、デプロイする本番環境になくて困ったということはありませんでしょうか?サーバー要件などで本番環境にNode.jsを入れられない、無い場合は予めどこかでビルドして転送する必要があります。
一番手っ取り早いのはローカルでビルドしてFTPなりrsyncすることです。しかし何人もプロジェクトに関わっていたり、属人化したり、環境が統一されていないなど色々とデメリットがあります。
私はLaravel+Nuxt.jsなプロジェクトを開発し、Xserver(レンタルサーバー)に配置したことがあります。Laravelのアセットファイルと、Nuxt.jsはNode.jsでビルドする必要がありますが、レンタルサーバー にはNode.jsがありません。(Xserverには気合で入れらるらしいですが、、パフォーマンスなどの都合でやめました。)
そこで前から気になっていたGithub Actionsを用いてGithub上でビルドを行い、本番環境でrsyncすることでなんとかアセットファイル系がデプロイできました。今回はこの方法について解説します。前提やGithub Actionsの説明から行いますで、さっさと内部コードを知りたい方は「ワークフローを書いていく」へ移動してください。
GitHub Actionsを使用すると、ワールドクラスのCI / CDですべてのソフトウェアワークフローを簡単に自動化できます。 GitHubから直接コードをビルド、テスト、デプロイでき、コードレビュー、ブランチ管理、問題のトリアージを希望どおりに機能させます。(https://github.co.jp/features/actions)
Github ActionsはGithubでビルド、テスト、デプロイ作業ができる環境です。Github上のコードを用いてすぐにビルドなどができます。例えばLaravelのVueファイルをビルドする際にはLaravelのプロジェクトルートで
npm run prod
とnode.jsのコマンドを打って、node.jsを動かしてビルドファイルを作成します。そしてビルド後にはcss,jsディレクトリが作成されます。このビルド操作をGithubの環境でも行えるようにします。
以下のようなymlファイルをGithub上で作成して、ビルド・やりたいコマンドを記述します。
name: Deploy
on: [ workflow_dispatch ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
ref: release
- uses: actions/setup-node@v2
with:
node-version: '14'
cache: 'npm'
- name: public build
run: |
npm install
npm run prod
rsync -av --delete \
./public/css ./public/js ./public/images \
deploy:$LARAVEL_PATH/public/
scp ./public/mix-manifest.json deploy:$LARAVEL_PATH/public/mix-manifest.json
env:
LARAVEL_PATH : ${{ secrets.LARAVEL_PATH }}
Dokcerファイルやバッチファイルと似た感じです。Node.jsの環境などはGithubが用意してくれます。
結構なんでもいけます。Node.jsはしかり、PHP/Python/Ruby/Java/Power Shellなど色々あります。
パブリックリポジトリの場合は何分使おうが無料です。しかしプライベートの場合は無料枠があり、フリーは毎月2000分までとなっています。(2022年1月時点)
参照:https://github.co.jp/features/actions
私のプロジェクトの場合、大体3分ぐらいで終わりますし、頻繁にビルドしないので基本無料で使えそうです。
今回ビルドするプロジェクトはLaravelとNuxtが連携されたプロジェクトです。
css/
,js/
に吐き出されるdist/
というディレクトリが生成される。.
├── README.md
├── app
├── artisan
├── bootstrap
├── composer.json
├── composer.lock
├── config
├── database
├── nuxt # nuxtはここ
├── package-lock.json
├── package.json
├── phpunit.xml
├── public # ここにLaravelのcss,jsが吐き出される
├── resources
├── routes
├── server.php
├── storage
├── tests
├── tinker_test.php
└── webpack.mix.js
まあとりあえず、Laravelルートでnpm run prod
そして、nuxt/
にてnpm run generate
してnode.jsを動かす必要があります。
そして生成されてたcss/
,js/
,images/
,mix-manifest.json
,dist/
ディレクトリ・ファイルを本番サーバーに転送します。
転送の際にはrsyncを使用し、SSHの鍵認証で接続します。またこのアクションは手動で行うようにします。一応、masterブランチにプッシュされた時に自動で実行なんてこともできます。ただし今回はビルドする環境が欲しいだけなので、処理の実行は手動で行います。以上がActionの概要です。
まずSSHやビルドで使用する.env
など環境変数を定義しておきます。Github Actionsでも環境変数を定義できます。
リポジトリのSettingsからSecretsの画面で定義できます。
「New repository secret」をクリックしてキー名と値を入力します。
SSH_KEY:SSHに使用する鍵ファイルの中身です。.pem
、.key
などを開いて記述された文字をすべてコピペしてください。
SSH_HOST:接続先のホスト名です。
SSH_PORT:接続先のポートです。
SSH_USER:接続先のユーザーです。
LARAEL_PATH:本番サーバーでのLaravelが置かれている絶対パスです。
GOOGLE_MAP_API_KEY:NuxtでGoogleMapのAPI(フロントに出してもOKなやつ)を使っているので定義。あとで使います。
以上のSSHに関連する値と、.env
の記述で必要であれば書いておきます。それではアクションの内容を書いていきましょう。
メニューの「Actions」をクリックしたのち、「New Workflow」をクリックします。
するとworkflowを選択する画面にて、テンプレートをいくつか用意してくれています。
今回はNode.jsのビルドしかないので「Node.js」を選択します。するとある程度の記述が書かれた状態で、yamlが表示されます。
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Node.js CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x, 14.x, 16.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm run build --if-present
- run: npm test
最初は上記の構成となっています。name
はワークフローの名前になります。わかりやすいものに変えておきましょう。
まず最初にLaravelのアセットファイルを作成してrsyncするとこまで記述します。なお登場する記述に関してはこちらの公式ドキュメントを参考にしてください。ワークフロー構文
最初は実行条件などを変更します。
name: Deploy
on: [ workflow_dispatch ]
on:
はこのワークフローの実行条件です。デフォルトではmaster
ブランチにpushされることが条件ですが、ここではworkflow_dispatch
として、手動で実行できるようにします。
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
ref: release
- uses: actions/setup-node@v2
with:
node-version: '14'
cache: 'npm'
このリポジトリの場合、本番環境は常にrelease
ブランチをプルするのでビルド対象ファイルもrelease
のものを使用します。そのため- uses: actions/checkout@v2
というブランチのチェックアウトが処理を行う記述をします。
- uses: actions/checkout@v2
with:
ref: release
これでリリースブランチにチェックアウトしてビルドできるようになります。
- uses: actions/setup-node@v2
with:
node-version: '14'
cache: 'npm'
これでNode.js14の環境を使用できるようになり、npmコマンドも使用できるようになります。それではstep:
配下に実行するコマンドを書いていきましょう。
実行コードはname:
を用いて区分けできます。長いと何がなんだか分からなくなるので、書いておくといいです。
そして実行内容はrun:
に記述します。
- run: npm ci
- run: npm run build --if-present
- run: npm test
のように1つづつ書いてもいいですが、ここでは以下のようにまとめて書くことにします。
- name: ssh key generate
run: |
echo "$SSH_KEY" > id_rsa
mkdir ~/.ssh
chmod 700 ~/.ssh
そんでは最初にSSHの設定を行います。毎回、鍵のパスとかを記述するのは面倒なのでSSHのconfigファイルを作ってエイリアスで呼べるようにしましょう。
- name: ssh key generate
run: |
echo "$SSH_KEY" > id_rsa
mkdir ~/.ssh
chmod 700 ~/.ssh
mv id_rsa ~/.ssh/
chmod 600 ~/.ssh/id_rsa
echo "HOST deploy" >> ~/.ssh/config
echo "HostName $SSH_HOST" >> ~/.ssh/config
echo "user $SSH_USER" >> ~/.ssh/config
echo "Port $SSH_PORT" >> ~/.ssh/config
echo "IdentityFile $HOME/.ssh/id_rsa" >> ~/.ssh/config
echo "StrictHostKeyChecking no" >> ~/.ssh/config
echo "UserKnownHostsFile=/dev/null" >> ~/.ssh/config
chmod 644 ~/.ssh/config
env:
SSH_KEY: ${{ secrets.SSH_KEY }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_USER: ${{ secrets.SSH_USER }}
SSH_PORT: ${{ secrets.SSH_PORT }}
まずenv:
にて使用する環境変数をコマンド変数に渡します。こうすることでコマンド内で$SSH_KEY
として値を使用できます。キー、ホスト、ユーザー、ポートを出します。
ちなみに${{ secrets.SSH_KEY }}
の記述はコンテキストと呼ばれています。ワークフローに関する情報やsecretsに保存した値にアクセスできます。
echo "$SSH_KEY" > id_rsa
mkdir ~/.ssh
chmod 700 ~/.ssh
mv id_rsa ~/.ssh/
chmod 600 ~/.ssh/id_rsa
まず$SSH_KEY
をid_rsa
としてファイルに出力。そして~/.ssh
ディレクトリを作成してその配下に置いておきます。鍵と.ssh
ディレクトリの権限変更を忘れないようにしてください。
echo "HOST deploy" >> ~/.ssh/config
echo "HostName $SSH_HOST" >> ~/.ssh/config
echo "user $SSH_USER" >> ~/.ssh/config
echo "Port $SSH_PORT" >> ~/.ssh/config
echo "IdentityFile $HOME/.ssh/id_rsa" >> ~/.ssh/config
echo "StrictHostKeyChecking no" >> ~/.ssh/config
echo "UserKnownHostsFile=/dev/null" >> ~/.ssh/config
chmod 644 ~/.ssh/config
~/.ssh/config
ファイルにエイリアスの記述を書いておきます。SSHは初回接続時に警告をだすのでStrictHostKeyChecking no
を設定し、known_hostsを出さないようにUserKnownHostsFile=/dev/null
としておきます。
最後に権限をきちんと設定すれば、deploy
というSSHエイリアスが使える用意なります。手動で.ssh/config
の設定をしていたのを自動化した感じです。
SSHの設定はできたのでLaravelのアセットビルドをするコードを書きます。
- name: public build
run: |
npm install
npm run prod
rsync -av --delete \
./public/css ./public/js ./public/images \
deploy:$LARAVEL_PATH/public/
scp ./public/mix-manifest.json deploy:$LARAVEL_PATH/public/mix-manifest.json
env:
LARAVEL_PATH : ${{ secrets.LARAVEL_PATH }}
ワークフローの初期位置はリポジトリルートと対応しています。最初にライブラリなどをインストールしてからビルドします。
終わったらrsyncを行います。エイリアスを定義しておいたのでdeploy:$LARAVEL_PATH/public/
と簡単な記述で済みます。
次にnuxt/
に移動してnuxt.jsのビルド処理を記述します。
- name: nuxt build
run: |
cd nuxt
touch .env
echo "GOOGLE_MAP_API_KEY=${{ secrets.GOOGLE_MAP_API_KEY }}" >> .env
npm install
npm run generate
rsync -av --delete ./dist deploy:$LARAVEL_PATH/nuxt/
env:
LARAVEL_PATH : ${{ secrets.LARAVEL_PATH }}
プロジェクトによっては.env
ファイルを使用して端末ごとに環境変数を定義していると思います。.envは大体gitignore
されてバージョン管理されていないので、ワークフローないで作成します。
run: |
cd nuxt
touch .env
echo "GOOGLE_MAP_API_KEY=${{ secrets.GOOGLE_MAP_API_KEY }}" >> .env
npm install
npm run generate
rsync -av --delete ./dist deploy:$LARAVEL_PATH/nuxt/
env:
LARAVEL_PATH : ${{ secrets.LARAVEL_PATH }}
と必要な箇所で.env
ファイルを作って、echo "GOOGLE_MAP_API_KEY=${{ secrets.GOOGLE_MAP_API_KEY }}" >> .env
とGithubの環境変数内容を出力します。これでOKです。
nuxtは静的書出するとdist
が作成されるので、rsyncで転送します。
記述が終わったら画面右上の「Start Commit」をおして内容をコミットします。ちなみにワークフローファイルはリポジトリの.github/workflows
というディレクトリが作られ、そこに保存されます。
ではビルドしましょう。Actionsで対象のデプロイ名を選択して「Run Workflow」を押して、対象ブランチを選択して実行します。
ビルド中の様子やログは随時確認することができます。ビルドが無事に終了すると以下のように全てチェックマークとなり、処理が終了します。どこかエラーが起きた場合はそこで処理が中止されます。
終わったら本番サーバーで対象のファイルが作られているかなどを確認してみましょう。
少人数でこれぐらいであればローカルPCで誰でもできそうですが、ボタンひとつでビルドできるようになることや手違いもなくなるのでとてもおすすめです。色々自動化できるようにGithub Actionsを色々探ってみます。