個人サイトを作ろう(3) Git管理&Git Hookでデプロイしよう

前回はwebサーバーを立てるところまでやってみました。

サイトのデータがリモートリポジトリのmasterブランチにマージされたらNext.jsアプリをビルドして公開ディレクトリに同期というのをGitHub Actionsでやってる方を見てそれやりたいな~~と思いました。ただGitHubは性的な内容は駄目で同人サイトには向かないので、その辺の絡みでさくらVPSで同様の機能をやりたい感じです。

今回は仮想サーバー上にリモートリポジトリを作成してWindows側のVScodeからSSH接続でpushできるようにします。さらにリモートリポジトリにpushされたらGit HookでNext.jsアプリをビルドしてrsyncで公開フォルダに同期します。

何言ってるのかよくわかんないですが「サイトの更新準備が出来たらボタンポチーでサーバー上のデータが更新できて、弄った部分の変更履歴も取れる」みたいな感じ

続きを読む

リモートリポジトリの作成

SSH接続設定

Windowsの「~/.ssh/config」に公開鍵設定の以下を追記しておきます。前回はホストOSから楽に接続するためでしたがこちらも追記しておくと「192.168.56.101」でのアクセスにも公開鍵が適用されるため、VScodeでSSH接続した際パスワード入力が不要になります。

 Host 192.168.56.101
  HostName 192.168.56.101
  User ubuntu
  Port 22
  IdentityFile ~/.ssh/id_rsa_ubuntu

ゲストOS上にリモートリポジトリを作成する

ゲストOS(Ubuntu)に「~/git/」ディレクトリを作成し、さらにその内部に「ubugit.git」フォルダを作成して移動します。(名前は適当/本番ではディレクトリは違うところでもいいかも)

$ sudo mkdir git
$ cd git
$ sudo mkdir ubugit.git
$ cd ubugit.git

–bareオプションをつけてベアリポジトリとして初期化します。

$ sudo git init --bare

空のリモートリポジトリができました。さらに権限を追加します。

$ sudo chown -R ubuntu:ubuntu /home/ubuntu/git/ubugit.git

Next.jsアプリの作成

ホストOS(Windows)側でNext.jsアプリを作成します。なんとなく同じ「ubugit」で作成しました。

npx create-next-app ubugit

次にVScodeで作成した「ubugit」アプリのフォルダを開きます。

ターミナルを開いて下記を入力します。

Next.jsアプリはデフォルトでメインブランチがmainとなっているのでmainブランチでpushします。

$ git remote add origin ssh://[email protected]/home/ubuntu/git/ubugit.git
$ git add .
$ git commit -m "First commit"
$ git push -u origin main

あとは適当にNext.jsアプリに変更を加えてVScodeのメニューからコミット→push出来れば成功です。わ~い。

Git Hookでマージ時の挙動を設定する

Git Hookを使用してGitで特定のアクションが起きたときに特定のスクリプトを実行することが出来ます。

Git Hookの作成

リモートリポジトリのsrcフォルダにマージされたらゲストOS(Ubuntu)上でビルド→出来たファイルを公開フォルダに同期させます。

tempフォルダを作成し、そこでビルドしてからできた「/.next/server/app/」フォルダをrsyncで「/var/www/myapp/」に同期します。

Git Hookを利用するためリポジトリの/.git/hooks/ディレクトリに移動します。touchコマンドで「post-receive」ファイルを作成します。

$ cd ~/git/ubugit.git/hooks/
$ sudo touch post-receive
$ sudo chmod +x post-receive

「post-receive」フックファイルに以下を記述します。

#!/bin/bash

TARGET="/var/www/myapp"
GIT_DIR="/home/ubuntu/git/ubugit.git"
TEMP_WORK_TREE="/home/ubuntu/tmp/ubugit-worktree/"
LOG_FILE="/home/ubuntu/git/ubugit.git/hooks/post-receive.log"

log() {
    echo "$(date): $1" >> $LOG_FILE
}

error_exit() {
    log "An error occurred. Cleaning up..."
    rm -rf $TEMP_WORK_TREE
    exit 1
}

trap error_exit ERR

while read oldrev newrev refname
do
  if [[ $refname = "refs/heads/main" ]]
  then
    changed_files="$(git diff-tree -r --name-only --no-commit-id $oldrev $newrev)"
    
    check_run() {
      echo "$changed_files" | grep --quiet "$1" && eval "$2"
    }

    check_run src/ 'log "Changes detected in src/. Checking out and building..."; mkdir -p $TEMP_WORK_TREE; GIT_WORK_TREE=$TEMP_WORK_TREE git checkout -f $newrev 2>>$LOG_FILE; cd $TEMP_WORK_TREE; npm install 2>>$LOG_FILE; log "npm install complete."; npm run build 2>>$LOG_FILE; log "npm run build complete."; rsync -avz --delete $TEMP_WORK_TREE/.next/server/app/ $TARGET 2>>$LOG_FILE; log "rsync complete."; rm -rf $TEMP_WORK_TREE; log "Build and sync complete."'
  fi
done

logファイルを記述し、エラーが起きたら「error_exit()」を実行してtempファイルを削除します。

さらに各フォルダのパーミッションは755のまま運用したいので、書き込みを行うディレクトリに対しubuntuユーザーに権限を付与します。

該当フォルダがなければmkdirで作成しておきます。

$ sudo chown -R ubuntu:ubuntu /home/ubuntu/tmp/ubugit-worktree/
$ sudo chown -R ubuntu:ubuntu /var/www/myapp/

あとはNext.jsアプリをVScodeで変更してコミット→pushすると自動でサーバー上でビルドされてmyappフォルダに配置、nginxのルーティングでサイトに接続できます。お疲れ様でした…。

今回引っかかったところ

  • パーミッション755ディレクトリに対するubuntuユーザーの権限(リモートリポジトリにはpush出来てたのでGit hookの実行でできなくて引っかかった)
  • 改行コードがCFLFになってた(凡ミス!!!)

次回はforeverなどでNodeタスクの常駐化をするかNext.jsでサイト作っていくかその辺だと思います。サイト構成考えなきゃ~~

Git,UbuntuServer