アカベコマイリ

HEAR NOTHING SEE NOTHING SAY NOTHING

Redmine 4.2 と Gitolite (gitolite3) 連携

Redmine 4.2 移行の続き。今回は Git サーバー構築と Redmine 連携を実施する。

サーバーのドメインは xxxx.vs.sakura.ne.jp、作業用ユーザーは akabeko としておく。本記事を参考にする場合、この箇所を自身のドメインへ置き換えること。

Gitolite

Git 公式サーバー Gitolite 環境を構築してゆく。基本手的に以下の記事を踏襲。

はじめにローカル環境で Gitolite 用の公開鍵認証ファイルを生成。

$ ssh-keygen -f gitolite

これで秘密鍵 gitolite と公開鍵 gitolite.pub ファイルを得られる。秘密鍵を ~/.ssh 内へ移動したら ~/.ssh/config に以下の設定を追加。HOSTNAME 部分はサーバーに割り当てたドメインか IP アドレスにすること。この例ではドメインにしている。

HOST gitolite-admin
    HOSTNAME     xxxx.vs.sakura.ne.jp
    USER         gituser
    PORT         22
    IDENTITYFILE ~/.ssh/gitolite

公開鍵を Redmine/Git サーバーにアップロードしておく。場所は作業用ユーザーのホーム。これでサーバー側に ~/gitolite.pub が置かれた状態となるはず。

Gitolite 管理ユーザーを追加。名前は gituser とした。

$ sudo useradd --shell /bin/bash --home /home/gituser gituser

アップロードしておいた SSH 接続用の公開鍵を gituser の HOME へ移動して所有者とパーミッションを変更。

$ cd
$ sudo mv gitolite.pub /home/gituser
$ sudo chown gituser:gituser /home/gituser/gitolite.pub
$ sudo chmod 644 /home/gituser/gitolite.pub
$ sudo ls -l /home/gituser/
total 4
-rw-r--r-- 1 gituser gituser 405 Aug 19 15:03 gitolite.pub

Gitolite のインストールと初期設定。dnf を利用するが CentOS 8 Stream の標準リポジトリーには存在しない。

$ sudo dnf search gitolite
Last metadata expiration check: 1:13:18 ago on Thu 19 Aug 2021 02:05:00 PM JST.
No matches found.

そのため EPEL リポジトリーを追加してからインストールする。前回の記事で済ませていると思われるが、念の為にここでも追加コマンドを掲載しておく。

Gitolite のパッケージ名は gitolite ではなく gitolite3 なので注意すること。

$ sudo dnf install epel-release
$ sudo dnf --enablerepo=epel install gitolite3

Gitoite の初期化。

ユーザーを gituser に変更してから gitolite setup コマンドに公開鍵ファイルを指定して実行。

$ sudo su - gituser
$ gitolite setup -pk gitolite.pub
Initialized empty Git repository in /home/gituser/repositories/gitolite-admin.git/
Initialized empty Git repository in /home/gituser/repositories/testing.git/
WARNING: /home/gituser/.ssh missing; creating a new one
    (this is normal on a brand new install)
WARNING: /home/gituser/.ssh/authorized_keys missing; creating a new one
    (this is normal on a brand new install)

表示されている警告は .ssh ディレクトリーが存在しないため、公開鍵と一緒に作成しましたというもの。実際に vi~/.ssh/authorized_keys を開くと、公開鍵の内容が転載されていることを確認できるはず。

公開鍵はもう必要ないので消しておく。

$ cd
$ rm gitolite.pub

gituser から抜ける。

$ exit

ローカルから Redmine/Git サーバーの Gitolite へ SSH 接続するため、設定ファイルを開く。

$ sudo vi /etc/ssh/sshd_config

設定ファイルの AllowUsersgituser を追加。もしこの設定がなければ項目ごとファイル末尾へ追加しておく。内容は SSH 接続したいユーザーを半角スペース区切りで列挙。いつも SSH 接続してログインしているユーザーを akabeko として gituser を追加した場合は以下のようになる。

# AllowUsers
AllowUsers akabeko gituser

編集が完了したらファイルを保存して SSH デーモン再起動。

$ sudo systemctl restart sshd

実験としてリポジトリーをローカルに clone してみる。Gitolite はテスト用に testing というリポジトリーを用意しているのでこれを対象とした。リポジトリーのサーバーとして指定するのはローカルの ~/.ssh/config に設定した名前になるので注意すること。この名前に続けて :リポジトリー名 としたものが clone 元となる。

$ git clone gitolite-admin:testing
Cloning into 'testing'...

エラーが出る場合はここまでの設定を見直すこと。

リポジトリー移行、失敗編

事前に新サーバーの作業ユーザー HOME へバックアップしておいた旧サーバーの repositories.zip を転送してから展開済しておくこと。これはリポジトリーの実体となる。

$ unzip repositories.zip

ローカルに新 Gitlolite の gitolite-admingit clone してから、旧 Gitolite の gitolite-admin にある conf/keydir/ の中身を gitolite.pub 以外、新 Gitolite 側へコピー。これで新 Gitolite 側に管理しているリポジトリーとユーザー情報の設定が移行されたので、このまま commit してから push

ユーザーを gituser に切り替えて中身を確認。

$ sudo su gituser
$ cd
$ ls -l repositories/
...ここに空のリポジトリー一覧が表示されるはず

リポジトリーのディレクトリーをリネームしてから gituser を抜ける。

$ mv repositories/ _repositories
$ exit

作業ユーザーでリポジトリーの実体を移動してからパーミッションを変更。

$ sudo mv repositories/ /home/gituser/
$ sudo chown -R gituser:gituser /home/gituser/repositories

これでいけるかと思ったのだが、試しに testing を改めて clone するとエラーになった。

FATAL: split conf set, gl-conf not present for 'testing'
fatal: Could not read from remote repository.

どうやら Gitolite v2 と v3 間で破壊的な変更がおこなわれたようだ。公式サイトに移行方法を掲載したページが公開されている。

手順を読むとかなり面倒。危険そうな手動のファイル操作もある。なので一旦、新 Gitolite のリポジトリーに戻す。

$ sudo su gituser
$ mv repositories/ __repositories
$ mv _repositories/ repositories

これで gitolite-admin に初設定が push された状態となった。

リポジトリー移行、成功編

失敗編では旧リポジトリーの実データをそのままサーバー上で置き換えようとした。これがダメだったので正攻法というか標準の git コマンド操作でリポジトリーを移行してみる。

まずは対象リポジトリーをメモ。さきほど戻した gituserrepositories 内にあるものがそれにあたるので ls -1 で名前だけ縦に並べてコピペしておく。リポジトリーのディレクトリー末尾には .git が付いている。これは後述する git clone ではあってもなくてもよいのだが、私としてはいつも無しで指定しているため除去しておいた。これに加えて以下の準備が済んでいることを前提とする。

  • ローカルの~/.ssh/config に新旧 Gitolite サーバーの SSH 接続設定を登録すみ
    • ここではわかりやすくそれぞれ gitolite-oldgitolite-new としておく
  • ローカルで git コマンドを利用可能

ローカルに適当なディレクトリーを作成して、そこで移行作業をしてゆく。例えば対象リポジトリーが sample なら以下のようにコマンドを実行。

$ git clone --mirror gitolite-old:sample sample
$ cd sample
$ git remote set-url --push origin gitolite-new:sample
$ git push --mirror
$ cd ../
$ rm -rf sample

順番に解説する。

  1. --mirror として旧サーバーからリポジトリーを git clone
  2. リポジトリーのリモート URL を git remote set-url で新サーバーに変更
  3. リモートが新サーバーを指すようになったので git push により全履歴を送信

これを繰り返してゆけばよい。もしもリポジトリーの数が多くて面倒ならシュエル スクリプトで処理するのもありだ。新サーバー側から git clone し直してみて全履歴があれば成功。

Redmine 連携の準備

サーバーに SSH 接続後、Gitolite 管理下のリポジトリ本体からミラーリングして Redmine から参照するための Git リポジトリ用ディレクトリーを作成して移動。

$ sudo mkdir /var/lib/git
$ sudo cd /var/lib/git

リポジトリーを clone してゆく。

$ sudo git clone --mirror /home/gituser/repositories/testing

オーナー設定。Gitolite ユーザーを設定しておく。面倒なので /var/lib/git ごと変更してから、このディレクトリーを root に戻している。

$ sudo chown -R gituser:gituser /var/lib/git
$ sudo chown root:root /var/lib/git

この時点で clone された各リポジトリーのパーミッションは 755 のはず。もしそうなっていないとしたら変更しておくこと。

$ sudo chmod -R 755 /var/lib/git/testing.git/

Git サーバーへ push された際に上記リポジトリーへ同期するための設定。作業用ユーザーをユーザー グループ gituser へ追加。id コマンドで gituser へ所属していることを確認。

$ sudo gpasswd -a akabeko gituser
Adding user akabeko to group gituser

$ id akabeko
uid=1000(akabeko) gid=1000(akabeko) groups=1000(akabeko),1001(gituser)

これで Redmine 稼働ユーザーを作業用ユーザー akabeko にすれば、ここを参照可能になったはず。ただしミラーリング元からこのリポジトリに対して git push --mirror が実行された場合 testing.git/objects などにディレクトリが追加されるのだがパーミッションは 700 になる。つまり所有者しかアクセスできない。というわけで以下の記事を参考にリポジトリー毎の config ファイルの設定を変更する。

$ cd /var/lib/git/testing.git
$ sudo git config core.sharedRepository group

push をフックしてミラーへ同期

Git フックを利用して Gitolite 上のリポジトリに push がおこなわれたらミラーリング リポジトリ側にも反映されるようにする。

はじめに hook 時のパーミッション設定を変更。gituser の HOME にある .gitolite.rc の REPO_UMASK を編集する。gituser になってからファイルを開く。

$ sudo su gituser
$ cd
$ vi .gitolite.rc

かつて REPO_UMASK だった設定は gitolite3 だと UMASK になっているのでこれを探す。デフォルトのパーミッション 00770027 に変更してからファイルを保存。この作業は一度だけ実施すればよい。

    # default umask gives you perms of '0700'; see the rc file docs for
    # how/why you might change this
    UMASK                           =>  0027,

リポジトリー毎にフックを設定してゆく。gituser で例えば testing.git 内の hooks ディレクトリに post-receive というファイルを新規作成。

$ sudo su - gituser
$ cd repositories/testing.git/hooks
$ vi post-receive

このファイルにはシェル スクリプトとして記述できる。今回はミラーリング リポジトリとなる /var/lib/git/testing.git に変更を git push --mirror として反映する処理を書いて保存。

...とゆきたいところだが gitolite3 では UMASK0027 にしても mirror 側のパーミッションが共有にならず、Redmine から参照すると 404 になるようだ。そのためスクリプトからパーミッションを明示的に変更する。

#!/bin/sh
/usr/bin/git push --mirror /var/lib/git/testing.git
find /var/lib/git/testing.git/ -type d -print | xargs chmod 755
find /var/lib/git/testing.git/ -type f -print | xargs chmod 644

/var/lib/git は所有権を gituser:gituser に設定しているため、その配下なら gituser が実行するスクリプトで自由にパーミッション設定可能。これを利用して mirror 側のリポジトリーについて、ディレクトリーとファイルすべてを全共有にしている。もっと細かく厳密に権限を設定したければスクリプトをいじってもよい。

スクリプトに実行属性を付けておく。

$ chmod 700 post-receive

正しく設定できているなら testing.gitpush が行われるたびにミラー側へも変更が反映されるはず。私の環境では Redmine 上のリポジトリー画面で push した結果を確認できた。

おわりに

これにて Redmine/Git サーバーの移行は完了。2022/3 現在も特に問題なく動作している。

最近は Linux 系ミドルウェアを Docker 利用で済ませているが、たまにはこうして素のミドルウェアへ触れてみるのも楽しいものだ。次に Redmine/Git サーバーを移行するのは相当に先となりそうだが、その際に今回の記事が参考になればと願っている。

Copyright © 2009 - 2023 akabeko.me All Rights Reserved.