目的と条件
- コンフィグファイルをgit管理したい
- pushされたらdeployまで自動でやりたい
- レポジトリにpushされる前にvalidationをかけたい
- validationは強制したい
- validationツールとコンフィグは同じリポジトリで管理しない
- validationがOKだったら対象のサーバに自動でデプロイしたい
- コンフィグの編集者は必ずしもgitに精通しているわけではないので難しいことはさせない
動機
ネットワークやサーバの運用を行なっているとコンフィグファイルをgitで履歴管理して、リモートリポジトリにpushされたらリモートからサーバにデプロイする、みたいなことをやりたくなる。でも内容に誤りのあるコンフィグファイルをいきなりデプロイしてしまうとシステムに異常を来すので、リモートリポジトリにpushする前にかならずコンフィグ内容のvalidationを行なって、問題がなければ受け入れるようにしたい。
プログラムのコードであればテストが存在して、それらはプログラムの一部として扱われるので、同じリポジトリ内に置いて管理される。しかし管理したいのはコンフィグファイル、あくまでデータであって、validationのツールとは別に履歴を管理したい。ツールの改良履歴とコンフィグ内容の履歴が混ざるのが嫌。
また、コンフィグを編集する人は、プログラマよりはオペレータに近いので、gitに精通しているわけではない。なのでCVS以上に小難しいことをさせたくない。
やりかた
編集者の手元(editor)にvalidationツールを置けない。作業するサーバの違いやツールのインタープリタのバージョン(rbenv等)などが問題になるからだ。それに加えて、必ずvalidationを実施してあげる必要があるため、サーバ=リモートリポジトリ側でvalidationを行わなければならない。これにはupdateのhookが使える。また、pushが成功した後のデプロイにはpost-receiveのhookが使える。
環境
リモートリポジトリ
server1というサーバの/reposに--bare --sharedで作成してある
cd /repos/hoge.git
git init --bare --shared
ツール用アカウント
server1にツールのアカウントとしてhogeを作成してある。
/home/hoge/work/hogeにローカルリポジトリが作成してある。
cd /home/hoge/work/hoge
cat hogehoge > hoge.conf
git init
git remote add origin /repos/hoge.git
git add hoge.conf
git push origin master
オペレータの作業ディレクトリ
オペレータは任意のサーバの個人のアカウントでhoge.confの編集作業を行う。
cd /home/yuyarin
git clone hoge@server1:/repos/hoge.git
cd hoge
vim hoge.conf
git add hoge.conf
git commit -m "Hogehoge"
git push origin master
ここでvalidationされる
validationツール
まずvalidationのツールを用意する。このツールは標準入力からファイル内容を受け取れるようにしてある。
試しにコンフィグ内にhogeと書かれていたらinvalidとする。invalidである場合はエラーメッセージを表示して、exit 1する。
#!ruby
fd = ARGV[0] and File.exists?(ARGV[0]) ? File::open(ARGV[0], 'r') : STDIN
while line = fd.gets
if /hoge/ =~ line
puts "validation ERROR"
exit 1
end
end
puts "validation OK"
exit 0
deployツール
hogeのローカルリポジトリのファイルを各サーバにscpするスクリプトを設置。
必要があればsshでデーモンのreloadを行うなどする。
#!/bin/sh
FILE=hoge.conf
LOCAL_DIR=/home/hoge/work/hoge
REMOTE_DIR=/etc/hoged
REMOTE_USER=hoge
REMOTE_HOSTS="hoge1 hoge2 hoge3 hoge4"
for REMOTE_HOST in $REMOTE_HOSTS
do
CMD="scp ${LOCAL_DIR}/${FILE} ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}/${FILE}"
echo $CMD
eval $CMD
done
hookの作成
update
。
このスクリプトはhooks/updateとして設置し、0を返せばaccept、それ以外の値を返せばrejectとなる。rejectになるとリポジトリには反映されない。
#!/bin/sh
git show $3:hoge.conf | /usr/local/bin/validate_hoge
pushされてきたrevisionはシェルスクリプトであれば$3で取得できる。特定のファイル内容を確認するためには git showコマンドを使う。git show #{revision}:#{path}でファイル内容を取得することができるので、これをパイプでvalidationのツールに渡す。validationの結果、invalidだったら1が返ってくるので、pushはrejectされる。
post-receive
push内容がacceptされるとpost-receiveのhookが呼ばれるので、ここでreployツールを実行する。ここではhogeアカウントのローカルリポジトリで一度pullしたのち、別に用意した。deployツールを実行している。これでhoge.confがサーバにデプロイされる。
#!/bin/sh
cd /home/hoge/work/hoge
git --git-dir=.git pull /repos/hoge.git master
/usr/local/bin/deploy-hoge
git pullするのがダサければ、git showした内容をデプロイのツールに食わせるのもありかなぁ。
実行例
/home/yuyarin/hoge$ git commit -am 'Add string hoge'
[master 8519468] Add string hoge
1 file changed, 1 insertion(+)
/home/yuyarin/hoge$ git push origin master
Counting objects: 5, done.
Writing objects: 100% (3/3), 232 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: validation error
remote: error: hook declined to update refs/heads/master
To hoge@server1:/repos/hoge.git
! [remote rejected] master -> master (hook declined)
error: failed to push some refs to 'hoge@server1:/repos/hoge.git'
コンフィグ内容がinvalidだとrejectされる。
/home/yuyarin/hoge$ vim hoge.conf
/home/yuyarin/hoge$ git commit -am 'Remove strings hoge'
[master 3af7194] Remove strings hoge
1 file changed, 1 insertion(+), 2 deletions(-)
/home/yuyarin/hoge$ git push origin master
Counting objects: 8, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (6/6), 428 bytes | 0 bytes/s, done.
Total 6 (delta 0), reused 0 (delta 0)
remote: validation OK
remote: scp /home/hoge/work/hoge.conf hoge@hoge1:/etc/hoged/hoge.conf
remote: scp /home/hoge/work/hoge.conf hoge@hoge2:/etc/hoged/hoge.conf
remote: scp /home/hoge/work/hoge.conf hoge@hoge3:/etc/hoged/hoge.conf
remote: scp /home/hoge/work/hoge.conf hoge@hoge4:/etc/hoged/hoge.conf
To hoge@server1:/repos/hoge.git
e5aa890..3af7194 master -> master
コンフィグ内容に問題がないとコミット内容がacceptされて、post-receivedのhookで各サーバにファイルがデプロイされる。
悩みどころ
ゴミcommit
validationがcommitの後に行われるので、validationが通るまで誤った設定内容のゴミcommitが蓄積される。オペレータにgit rebaseとかやらせたくない。作業サーバを強制した上で、commit前にもvalidationツールを手動で実施するような手順にするという運用対処するしか無いのかなぁ。