🐧

GitBucket を使うことについて:Linux 使い(略)Advent Calendar 2024

2024/12/14に公開

はじめに

これは「Linux 使いになりたい人のための Advent Calendar 2024」の記事です。

筆者は、Web エンジニアを志望する人には、セルフホスト Git サービスを稼働させて利用することをオススメしています。もし Git を使ったことがないなら、Git を学ぶときに、セルフホスト Git サービスを稼働させることも視野に含めながら学習するのが効率的だと考えています。

GitBucket を使うことについて

前回はセルフホスト Git サービスを稼働させるにあたり、Gitea と Forgejo について使う場合について説明しました。今回は、候補にいれつつ紹介しなかった GiBucket について説明します。

GitBucket は Java の開発者なら馴染みのある技術を使って実装されています。また、実行にあたっては Java のランタイム環境が必要です。そのため、Java 開発者には推奨するのですが、そうでない場合は純粋に Gitea や Forgejo の機能と比較して選択するかしないかを判断することになります。

GitBucket については記事にしていないので、試用することを前提に、起動や停止をする方法について簡単に説明します。

GitBucket は下記の URL でコードが開発されているオープンソースプロジェクトでライセンスは Apache License Version 2.0 です。

Docker イメージ用のプロジェクトもあり、下記の URL で公開されています。

Docker で試用

試用には Docker を使うのが簡単です。

ここで用意するファイルは次のディレクトリー構成となっているとします。また、gitbucket-container ディレクトリーを ${CONTAINER_PROJ_DIR} と表記します。

gitbucket-container/
├── data/
└── script/
    ├── run.sh
    └── run_v.sh

GitBucket コンテナーの試用

単純に GitBucket を使ってみるだけなら 次のコマンドを実行します。

docker container run -d \
    -p 8080:8080 \
    -p 29418:29418 \
    ghcr.io/gitbucket/gitbucket:4.41.0

これで、http://localhost:8080 で Web UI が使えて、ssh://localhost:29418 で始まる URL の Git リモートリポジトリが使えるようになります。

初期の管理者アカウントが用意されていて、次の情報でサインインできます。

  • ID: root
  • Pass: root

管理者アカウントでサインインしたら、初期設定をして使えるように環境を用意します。ここでは使い方の説明は省略します。

停止するにはコンテナー ID かコンテナー名が必要です。次のコマンドで確認できます。

docker container ps | grep gitbucket

実行例は次のようになります。b0787c35f73d がコンテナー ID で、sleepy_hopper がコンテナー名です。

$ docker container ps | grep gitbucket
b0787c35f73d   ghcr.io/gitbucket/gitbucket:4.41.0 (略)sleepy_hopper

停止は docker container stop <コンテナー ID> のコマンドを実行します。

docker container stop b0787c35f73d

GitBucket コンテナー用スクリプト

起動用のコマンドについては、${CONTAINER_PROJ_DIR}/script/run.sh スクリプトにしておくと実行しやすくなります。

#!/bin/sh
docker container run -d \
    -p 8080:8080 \
    -p 29418:29418 \
    ghcr.io/gitbucket/gitbucket:4.41.0

実行するには次のようにします。

cd ${CONTAINER_PROJ_DIR}
sh script/run.sh

停止については、ワンライナーにすることもできます。そのときは awk コマンドも利用しつつ次のようなコマンドにします。

docker container stop \
    $(docker container ps | grep gitbucket | awk '{print $1}')

実行例は次のようになります。

$ docker container stop \
    "$(docker container ps | grep gitbucket | awk '{print $1}')"
b0787c35f73d

こちらも script/stop.sh スクリプトにしておくと使いやすくなります。実行前に、コンテナーが起動しているかの判定をするために if を使うようにしてあります。

#!/bin/sh

if docker container ps | grep gitbucket > /dev/null 2>&1; then
    CONTAINER_ID=$(docker container ps | grep gitbucket | awk '{print $1}')
    docker container stop "${CONTAINER_ID}"
fi

実行するときは次のようにします。

cd ${CONTAINER_PROJ_DIR}
sh script/stop.sh

GitBucket コンテナー削除

停止するだけでなく、コンテナーを削除したいときは docker compose rm コマンドを使います。停止時と同じようにスクリプト ${REPO_DIR}/script/down.sh として用意し、それを実行すると良いでしょう。

${REPO_DIR}/script/stop.sh とちがって、 docker compose rm コマンド実行時にコンテナーは停止している必要があるので、先に停止が必要です。

また、停止中のコンテナーについては docker container ps 実行時に -a オプションを追加しないと一覧に表示されません。停止中であることは、Status が Exit となっていてわかるので、この情報も使ってコンテナー ID を抽出します。

なお、停止中のコンテナーは複数存在することがあります。今回も試しに起動して、試しに停止だけしたコンテナーがあって、docker container ps -a |(略)grep Exited にヒットするものが複数あったりしました。そういった場合は、$(docker container ps -a |(略)) の結果が「コンテナー ID のリスト」となるので for を使って処理しておくと良いです。

整理すると、次のようになります。

#!/bin/sh

echo "stop"
SCRIPT_DIR=$(dirname "$0");
sh "${SCRIPT_DIR}/stop.sh"

echo "down"
if docker container ps -a | grep gitbucket | grep Exited > /dev/null 2>&1; then
    CONTAINER_ID_LIST=$(docker container ps -a | grep gitbucket | grep Exited | awk '{print $1}')
    for id in ${CONTAINER_ID_LIST}; do
        docker container rm "${id}"
    done
fi

GitBuckeet のデータ永続化

Docker ホストのファイルシステム上にデータの永続化をしたい場合は、データをおきたいディレクトリーをカレントにして次のように -v オプションでバインドマウントを指定して、docker container run コマンドを実行します。

cd ${CONTAINER_PROJ_DIR}
cd ./data
docker container run -d \
    -p 8080:8080 \
    -p 29418:29418 \
    -v "$(pwd)":/gitbucket \
    ghcr.io/gitbucket/gitbucket:4.41.0

${CONTAINER_PROJ_DIR}/data ディレクトリーには次のようなファイルが作成されます。

$ ls
activity.log  data.mv.db  database.conf  gist  plugins  tmp

${CONTAINER_PROJ_DIR}/data ディレクトリーに移動してコマンド実行したり、data ディレクトリーの存在チェックしたりする処理はまとめてスクリプトにしておいた方が使いやすいので、次のような ${CONTAINER_PROJ_DIR}/script/run_v.sh を用意します。

#!/bin/sh
SCRIPT_DIR=$(dirname "$0");
DATA_DIR=$(cd "${SCRIPT_DIR}/../data" || exit 0; pwd)

if [ ! -e "${DATA_DIR}" ]; then
    echo "mkdir \"${DATA_DIR}\""
    mkdir -p "${DATA_DIR}"
fi

docker container run -d \
    -p 8080:8080 \
    -p 29418:29418 \
    -v "${DATA_DIR}":/gitbucket \
    ghcr.io/gitbucket/gitbucket:4.41.0

これを実行します。

cd ${CONTAINER_PROJ_DIR}
sh script/run_v.sh

コンテナー停止は ${CONTAINER_PROJ_DIR}/script/stop.sh、コンテナー削除は ${CONTAINER_PROJ_DIR}/script/down.sh が使えます。

Docker Compose で試用

docker container コマンドで使う方法はわかりましたが、ここで紹介しているスクリプトはエラー処理を考慮しておらず、そこまで対応を考えると大変です。docker compose コマンドが使える環境なら、もっとわかりやすい compose.yaml ファイルでコンテナーを定義できます。

ここで用意するファイルは次のディレクトリー構成となっているとします。また、gitbucket ディレクトリーを ${PROJ_DIR} と表記します。

gitbucket/
├── compose.yaml
└── script/
    ├── down.sh
    └── run.sh

最初に説明したとおり、docker compose コマンドが使える環境なら、docker container コマンドで複雑なオプションを指定してするより、compose.yaml ファイルで宣言的に表現した方がわかりやすいです。

また、永続化データについては、バインドマウントを使うと性能問題やファイルシステムのオーナー権限問題が発生しやすいので、Docker ボリュームを使うようにした方が良いです。

ネットワーク設定については、ポート番号だけの指定だと、実は Docker ホストで使えるすべてのネットワークインタフェースについてポートを開いてしまいます。IP アドレスで使用するネットワークの指定ができるので、ここでは 127.0.0.1 だけにして制限をきつくします。

これらを考慮すると次のような gitbucket/compose.yaml ファイルを作成することになります。

name: gitbucket
services:
  gitbucket:
    image: ghcr.io/gitbucket/gitbucket:4.41.0
    container_name: gitbucket
    hostname: gitbucket
    tty: true
    ports:
        - 127.0.0.1:8080:8080
        - 127.0.0.1:29418:29418
    volumes:
      - type: volume
        source: gitbucket-data
        target: /gitbucket

volumes:
  gitbucket-data:
    name: gitbucket-data

実行するには次のように docker compose コマンドで -f オプションで使用する compose.yaml ファイルを指定し、サブコマンドに up を指定します。デーモン起動するために -d オプションも指定します。

これを script/run.sh で用意します。

#!/bin/sh

SCRIPT_DIR=$(dirname "$0");
DC_DIR=$(cd "${SCRIPT_DIR}/.." || exit 0; pwd)
DC_FILE="${DC_DIR}/compose.yaml"

docker compose -f "${DC_FILE}" up -d

停止は docker compose down コマンドを使います。このとき、-p <プロジェクト名> オプションで停止する Docker Compose プロジェクトを指定します。

これを script/down.sh で用意します。スクリプトでは basename コマンドを使って、プロジェクト名を compose.yaml を含むディレクトリー名から取得しています。このため、このスクリプトを使う場合は、プロジェクト名を compose.yaml を含むディレクトリー名と一緒にする必要があります。

#!/bin/sh
SCRIPT_DIR=$(dirname "$0");
DC_DIR=$(cd "${SCRIPT_DIR}/.." || exit 0; pwd)
DC_PROJ_NAME=$(basename "${DC_DIR}")

docker compose -p "${DC_PROJ_NAME}" down

以上の環境で gitbucket のコンテナー起動は次のようになります。

cd ${PROJ_DIR}
sh script/run.sh

gitbucket のコンテナー停止は次のようになります。

cd ${PROJ_DIR}
sh script/down.sh

以上で docker container コマンドをベースとするスクリプトを使うのと基本的には同じ環境が用意できました。ディレクトリーの準備などについては、スクリプトで用意しておけばこちらの方が使いやすそうですね。

Java ランタイム環境で試用

ここで、Java ランタイム環境がある場合は、わざわざ Docker を使って GitBucket を稼働させる必要はありません。GitBucket の本体である gitbucket.war ファイルを入手して、これを java コマンドで実行すれば良いです。

Java のランタイムについては種類が多くあり、どれを使うと良いかわかりにくいかと思います。いまなら Java 17 を使えば良いでしょう。ここでは Java ランタイム環境の構築については省略します。おそらく、Java を使っていない人は Docker で動かすでしょうし、すでに Java を使っている人にはわざわざ説明する必要もないはずだからです。

ここでは、次のディレクトリー構成でファイルを用意するとします。また、gitbucket-jar ディレクトリーは ${GITBUCKET_JAR_DIR} と表記することにします。

また、「Docker Compose で試用」で用意した compose.yaml を用意してあるディレクトリーも利用します。そちらは、${GITBUCKET_DIR} と表記することにします。これは「Docker Compose で試用」では ${PROJ_DIR} と表記したディレクトリーと同じ値となるとします。

gitbucket-jar/
└── script/
    ├── down.sh
    ├── init.sh
    └── up.sh

JAR の入手

JAR の入手については、Web サイトや Maven リポジトリから可能ですが、Docker 環境があって、gibtucket のコンテナーを起動できる comppose.yaml ファイルがあるなら、docker compose cp コマンドを使うのが簡単です。手動なら次のような手順になります。

cd ${GITBUCKET_DIR}
sh script/run.sh
cd ${GITBUCKET_JAR_DIR}
docker compose -p gitbucket cp gitbucket:/opt/gitbucket.war .
cd ${GITBUCKET_DIR}
sh script/down.sh

スクリプトにすると、次のようになります。

#!/bin/sh

SCRIPT_DIR=$(dirname "$0");
GITBUCKET_JAR_DIR=$(cd "${SCRIPT_DIR}/.." || exit 0; pwd)

# GITBUCKET_DIR の指定をしない場合は、
# gitbucket-jar ディレクトリーと gitbucket ディレクトリーは
# 同じディレクトリーに置くこと
if [ -z "${GITBUCKET_DIR}" ]; then
    GITBUCKET_DIR=$(cd "${GITBUCKET_JAR_DIR}/../gitbucket" || exit 0; pwd)
fi

# スリープする秒数を指定
SLEEP_NUMBER=5

if [ ! -e "${GITBUCKET_DIR}/script/run.sh" ]; then
    echo "not found: ${GITBUCKET_DIR}/script/run.sh"
    exit 1
fi
sh "${GITBUCKET_DIR}/script/run.sh"

# 起動するまで待機
sleep "${SLEEP_NUMBER}"
if docker compose ls | grep gitbucket | grep running > /dev/null; then
    # コピー
    docker compose -p gitbucket \
        cp gitbucket:/opt/gitbucket.war "${GITBUCKET_JAR_DIR}/"
else
    # ${SLEEP_NUMBER} 秒では起動しなかったので、ここで終了。
    # 手動で "${GITBUCKET_DIR}/script/stop" 実行後、
    # SLEEP_NUMBER の値を大きくして再実行が必要。
    echo "not running: gitbucket"
    exit 1
fi

# 停止
if [ ! -e "${GITBUCKET_DIR}/script/down.sh" ]; then
    echo "not found: ${GITBUCKET_DIR}/script/down.sh"
    exit 1
fi
sh "${GITBUCKET_DIR}/script/down.sh"

実行するには次のようにします。

cd ${GITBUCKET_JAR_DIR}
sh script/init.sh

Java で GitBucket 起動

入手した JAR ファイルを使って GitBucket を実行するには次のように java コマンドの -jar オプションで gitbucket.war ファイルを指定するだけdす。

cd ${GITBUCKET_JAR_DIR}
java -jar gitbucket.war

これで ${HOME}/.gitbucket に GitBucket 用のデータが用意されます。

ここで、個人利用のときは、ホームディレクトリーに出力が便利で良いのですが、システムとして使いたいときは /var/local/gitbucket などにしたいことでしょう。その場合は、--gitbucket.home オプションで GitBucket のデータを置くディレクトリーを指定します。

そういった対応ができるような ${GITBUCKET_JAR_DIR}/script/run.sh を用意すると、次のようになります。ここでは、${GITBUCKET_JAR_DIR}/data に GitBucket のデータを置くようにしてあります。

#!/bin/sh

SCRIPT_DIR=$(dirname "$0");
GITBUCKET_JAR_DIR=$(cd "${SCRIPT_DIR}/.." || exit 0; pwd)
DATA_DIR="${GITBUCKET_JAR_DIR}/data"

if [ ! -e "${DATA_DIR}" ]; then
    echo "mkdir \"${DATA_DIR}\""
    mkdir -p "${DATA_DIR}"
fi

if [ ! -e "${GITBUCKET_JAR_DIR}/gitbucket.war" ]; then
    sh "${SCRIPT_DIR}/init.sh"
fi

java -jar "${GITBUCKET_JAR_DIR}/gitbucket.war" \
    --gitbucket.home="${DATA_DIR}"

実行するには次のようにします。

cd ${GITBUCKET_JAR_DIR}
sh script/run.sh

Java で起動した GitBucket の停止

停止については、${GITBUCKET_JAR_DIR}/script/run.sh を実行しているターミナルで Ctrl+C を入力するか、kill コマンドを使います。スクリプトで用意する場合は、次の内容で ${GITBUCKET_JAR_DIR}/script/down.sh を作成します。

#!/bin/sh
# shellcheck disable=SC2009

if ps ax | grep "[g]itbucket.war" > /dev/null 2>&1 ; then
    pid=$(ps ax | grep "[g]itbucket-jar/gitbucket.war" | awk '{print $1}')
    kill "${pid}"
fi

これを使って GitBucket を停止には次のコマンドを実行します。

cd ${GITBUCKET_JAR_DIR}
sh script/down.sh

こちらは、コンテナーと違って、コンテナーの削除に相当するものはありません。初期化をしたい場合は、次のように ${GITBUCKET_JAR_DIR}/gitbucket.war ファイルと ${GITBUCKET_JAR_DIR}/data ディレクトリーを削除します。

cd ${GITBUCKET_JAR_DIR}
rm gitbucket.war
rm -fr data

おわりに

今回は GitBucket 環境を試用する方法について紹介しました。docker compose を使えるなら、それを使うのが簡単そうだと思ったのではないでしょうか。

ただ、Java ランタイム環境があるなら、性能的には直接 java コマンドで実行した方が有利です。Docker イメージ内でも java コマンドで GitBucket のプログラムを実行しています。Docker は仮想環境となるので、Windows や macOS では OS 上で直接動作する Java VM を使った方が Docker 環境よりも性能はでるはずです。Linux だと Docker は同じカーネルで動作するので、性能差はほとんどないはずです。

Docker ホストの環境をクリーンにしておきたいなら、Java ランタイム環境を使うより Docker 環境を使いたいと思うことでしょう。運用もしたい場合で Java ランタイム環境を用意するのが負担でないなら、Java ランタイム環境を使いたいと思うはずです。このあたりは、どのレベルで GitBucket を動かしたいと思うかで変わってきます。

個人的には、セルフホスト Git サービスを稼働させるにあたって、GitBucket を検討したこともあり、少人数のプロジェクトで実際に使ったこともあります。当時はまだ Docker もここまで普及しておらず、その頃は Java 実装のものを使っておけば Windows、macOS、Linux のどれでも稼働できて便利だったということもあり、結構人気がありました。日本で開発されているというのも大きいです。

ということで、今回は「GitBucket も良いですよ」という話でした。

Discussion