Gitサーバーサイドフックのデプロイ戦略

こんにちは。Backlog のソフトウェアエンジニアの中村です。
Backlog の Git 機能の開発と運用を担当しています。

過去にGitサービスの構成についてご紹介しましたが、その中の「Git Hook」部分の実装について現在、PerlからGo言語へのリプレースを進めています。
この記事では、このリプレース作業の中で遭遇した課題と、それを解決した工夫をご紹介します。

Git Hookの場所と入れ替えの課題

Git Hookには様々な種類があります。開発者の方はpre-commitpost-commitなどを利用したことがあるかもしれません。

Backlogでは、git pushの受け入れチェックや後処理等のために、pre-receivepost-receiveといったサーバーサイドフックをカスタマイズして利用しています。
post-receiveなどの「フックスクリプト(Gitから直接呼ばれるファイル)」の中から、PerlまたはGo製の「フックコマンド(実際のロジックを担う実行ファイル)」を呼び出す構成をとっています。

フックスクリプトはデフォルトでは、各ベアリポジトリ直下のhooksディレクトリに格納されています。Backlog Gitにおけるフックスクリプトも、以前は各ベアリポジトリに直接配置されていました。

そのため、移行を行うには全てのリポジトリ内のフックスクリプトを書き換える必要がありました。これは、更新の漏れや失敗のリスクを伴う、非常に重い作業です。

core.hooksPath による一元化

Backlog Gitは今では数十万のリポジトリをホスティングしています。これら全てに対して書き換えを行う作業は時間がかかります。作業中に新規作成されたリポジトリに対する考慮も必要です。また、問題発生時の切り戻しも大変になるでしょう。

非常にリスクがあるため、発想を変える必要がありました。
もっと効率的な解決方法が必ずあるはずだと信じ、私たちは git-config の奥地に迫りました。

その結果 core.hooksPath という設定を見つけました。
これはGit 2.9から導入されたオプションで、Gitのフックスクリプトに任意のパスを指定できるというものです。

Backlog GitのコアサービスはGit HTTP・Git SSHを経由したgit pushのデータをgit receive-packという配管コマンドで受けとります。この際、下記のように-c core.hooksPathオプションを使って最新のGit Hookのパスを指定するようにしました。

cmd := exec.Command(r.GitBinPath, "-c", "core.hooksPath="+hooksPath, "receive-pack", ".")
cmd.Dir = repositoryPath
cmd.Start()

これにより、移行作業のために数十万個のスクリプトを書き換える必要がなくなりました。また、デプロイ対象を1つのディレクトリだけに集約できるようになりました。
さらに、特定のテナントには別のパスを指定できるようにし、本番環境での事前検証にも対応しました。これにより段階的なリリースや、特定のサーバーでのみ発生する挙動の調査などが可能になりました。

また、フックスクリプトがリポジトリの外になったため、デプロイの最中にリポジトリが作成された場合についての考慮も不要になりました。

スクリプトの並行稼働と検証

デプロイ対象が減り、試行錯誤が格段にやりやすくなりました。
私たちはこの状況を活用し、新旧のフックコマンドの並行稼働を実施しました。

フックスクリプトの入力は標準入力、出力は標準出力と標準エラー出力、そして終了コードです。
これらを活用し、新旧のフックコマンドを同時に実行するための以下のようシェルスクリプトを作成しました。

#!/bin/bash

set -e
stdin=$(cat)
echo "$stdin" | 新フックコマンド || true
echo "$stdin" | 旧フックコマンド

新フックコマンドに問題があったとしても旧フックコマンドが実行されるようにしています。この構成により、本番トラフィックを維持したままログ比較による差分検証を行い、安心して Go 版への切り替えを進めることができました。

まとめ

Gitのcore.hooksPathオプションを利用することで、Gitのサーバーサイドフックを共通化することができました。
この仕組みにより、頻繁なリリースや、新旧処理の並行稼働といったデプロイ戦略を実現することが可能となりました。

これからも安全かつ効率的に、プロダクトを成長させていきます。

開発メンバー募集中

より良いチームワークを生み出す

チームの創造力を高めるコラボレーションツール

製品をみる