🐧

Docker で GitLab と mailpit を使う:Linux 使い(略)Advent Calendar 2024

2024/12/12に公開

はじめに

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

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

Docker で GitLab と mailpit を使う

前回はセルフホスト Git サービスを使うにあたり、OpenSSH を使うことが多いといった説明の流れから、Dev Container の sshd フィーチャーを使う方法について紹介しました。

Docker や OpenSSH も使えるようになったところで、そろそろ、実際にセルフホスト Git サービスで使えそうなソフトウェアを試してみたいと思っているところではないでしょうか。

今回は GitLab を Docker で動かしてみます。また、セルフホスト Git サービスを使うときはメール送信機能をどうやって用意するかも気にする必要がでてきます。メールサーバーは用意するのがそこそこ面倒なので、ここでは開発時によく使われている mailpit というメール送信機能と Web UI のメーラー機能を持つソフトウェアの Docker イメージを利用します。

OS は Ubuntu Desktop で動作確認していますが、基本的には Docker を使っているので Windows + Git Bash や macOS でも動くはずです。

本記事では tree コマンドを使うので、インストールしていない場合はインストールします。Ubuntu Desktop では apt コマンドで tree パッケージをインストールすれば使えるようになります。

sudo apt -y install tree

GitLab と mailpit 用 の compose.yaml

ここで使用する GitLab と mailpit 用 の compose.yaml は次のようになります。細かい説明はしませんが、非常に重たいので、CPU 利用率の制限や、使用可能メモリの制限緩和といったことをしています。また、GITLAB_OMNIBUS_CONFIG 環境変数でメール送信関連の設定もしています。

name: gitlab-ce
services:
  gitlab-ce:
    # ---- バージョン固定時は下記のようにバージョン指定し、固定しない場合は latest
    # image: 'gitlab/gitlab-ce:17.6.1-ce.0'
    image: 'gitlab/gitlab-ce:latest'
    restart: always
    container_name: 'gitlab-ce'
    hostname: 'gitlab-ce'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'https://${HOST_NAME:-localhost}:${HTTPS_PORT:-8443}'
        gitlab_rails['gitlab_shell_ssh_port'] = ${SSH_SHELL_PORT:-2424}
        gitlab_rails['smtp_enable'] = true
        gitlab_rails['smtp_address'] = 'mailpit'
        gitlab_rails['smtp_port'] = 1025
        gitlab_rails['smtp_domain'] = 'localhost'
        gitlab_rails['smtp_authentication'] = 'false'
        gitlab_rails['smtp_enable_starttls_auto'] = false
        gitlab_rails['smtp_tls'] = false
        gitlab_rails['smtp_openssl_verify_mode'] = 'none'
        gitlab_rails['gitlab_email_enabled'] = true
        gitlab_rails['gitlab_email_from'] = 'mailpit@localhost'
        gitlab_rails['gitlab_email_display_name'] = 'mailpit@localhost'
        gitlab_rails['gitlab_email_reply_to'] = 'mailpit@localhost'
    ports:
      # - '80:80'
      - '${HTTPS_IP_PORT:-127.0.0.1:8443}:8443'
      - '${SSH_IP_PORT:-127.0.0.1:2424}:22'
    volumes:
      # バインドマウントすると root ユーザー所有でファイルが作成される
      - '${GITLAB_HOME:-./srv/gitlab}/config:/etc/gitlab'
      - '${GITLAB_HOME:-./srv/gitlab}/logs:/var/log/gitlab'
      - '${GITLAB_HOME:-./srv/gitlab}/data:/var/opt/gitlab'
    shm_size: '256m'
    cpu_quota: 60000 # コンテナが100ミリ秒あたり60ミリ秒CPUを利用可能とする設定
    deploy:
      resources:
        limits:
          # cpus: "4"
          memory: 6g
    # journald が使える環境では有効化
    # logging:
    #   driver: journald
    #   options:
    #     tag: gitlab-ce
    healthcheck:
      test: 'curl --insecure https://127.0.0.1:${HTTPS_PORT:-8443}/-/health'
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 60s
    # ---- privilege 権限が必要なとき 
    # privileged: true
    # ---- ホストのメールサーバへアクセスするのに gateway.docker.internal を使う場合
    # extra_hosts:
    #   - gateway.docker.internal:host-gateway

  mailpit:
    image: axllent/mailpit:v1.21.6
    container_name: 'mailpit'
    hostname: 'mailpit'
    ports:
      - '127.0.0.1:8025:8025'
      - '127.0.0.1:1025:1025'
    # ---- mailpit のメールを永続化したい場合
    # volumes:
    #   - mailpit-data:/data
    # environment:
      # - MP_DATA_FILE=/data/mailpit.db
      # ---- UI で認証したいときに使用(ファイルは別途用意が必要)
      # - MP_UI_AUTH_FILE=/data/authfile
      # ---- UI でHTTPS を使いたい場合に使用(ファイルは別途用意が必要)
      # - MP_UI_TLS_CERT=/data/server.crt
      # - MP_UI_TLS_KEY=/data/private.key

# ---- mailpit のメールを永続化したい場合はこちらも有効化
# volumes:
#   mailpit-data:

環境変数でカスタマイズができます。ホスト名変更やポート番号などを変更したい場合は compose.yaml ファイルと同じディレクトリーに .env ファイルを用意します。サンプルは次のような内容になります。

GITLAB_HOME=./srv/gitlab
HOST_NAME=localhost
HTTPS_IP_PORT=127.0.0.1:8443
HTTPS_PORT=8443
SSH_IP_PORT=127.0.0.1:2424
SSH_SHELL_PORT=2424

compose.yaml には、バインドマウントで使用するディレクトリーがあります。これを作成するスクリプト init.sh は次のようになります。

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

for t in config data logs; do
    if [ ! -e "${SCRIPT_DIR}/srv/gitlab/${t}" ]; then
        mkdir -p "${SCRIPT_DIR}/srv/gitlab/${t}";
    fi
done

必要なディレクトリーを用意するため、init.sh を実行します。

sh init.sh

.env で環境変数をカスタマイズしている場合は特に設定を先に確認しておいたほうが良いです。次のコマンドを実行して、環境変数が正しい値に展開されることを確認してください。

docker compose config

問題なければ起動します。

docker compose up -d

GitLab の動作確認

GitLab の動作確認をするには、ログの確認やステータスの確認をします。

ログの確認は docker compose logs コマンドで可能です。

docker compose -p gitlab-ce logs -f

試用時ではこれで良いのですが、実際に運用する場合だと、デフォルトのログ用ドライバではずっとファイル出力がされてローテーションなどもされません。そのため、ログは journald などへ流した方が良いです。journald のログの確認は Ubuntu Desktop では journalctl でします。

sudo journalctl -t gitlab-ce

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

$ docker compose -p gitlab-ce logs -f
(略)
gitlab-ce  | Recipe: gitlab::gitlab-rails

コンテナーが起動したかの確認は docker compose ls コマンドでします。STATUS が running となっていれば、コンテナーは動いています。

$ docker compose ls
NAME                STATUS              CONFIG FILES
gitlab-ce           running(1)          (略)/gitlab-ce/compose.yaml

コンテナー内で Web サーバーが動作しているかを確認するために compose.yamlhealthcheck: の指定をしてあります。これが healthy となっていたら Web サーバーは起動しているということになります。これを確認したい場合は、docker container ps コマンドを使います。

$ docker container ps
CONTAINER ID   IMAGE                   (略)   STATUS                   PORTS                                  (略)   NAMES
bfe333e93e8e   gitlab/gitlab-ce:latest (略)   Up 4 minutes (healthy)   80/tcp, 443/tcp, 0.0.0.0:8443->8443/tcp(略)   gitlab-ce

docker inspect コマンドの出力について Status を含む行を grep で抽出することでも healthy 状態かの確認をすることもできます。

$ docker inspect gitlab-ce | grep Status
            "Status": "running",
                "Status": "healthy",

GitLab へのサインイン

GitLab の準備ができると、最初から用意されている管理者用アカウントである root のパスワードが確認できるようになります。次のようにコマンドを実行します。

$ docker compose -p gitlab-ce exec -it gitlab-ce grep 'Password:' /etc/gitlab/initial_root_password
Password: 1nNluyAheS4rffsRSNIKAgw2kw8aU9rLZxBqFtPCVLE=

それから、Docker ホストで Web ブラウザを起動して次のサインインの画面へアクセスします。

このとき HTTP 502: Waiting for GitLab to boot といったメッセージが出る場合もありますが、その場合は、サインインの画面になるまでしばらく待機します。

画面が表示されたら次の認証情報でログインします。

  • ユーザー名に root
  • パスワードに Password: の値 (ここの例だと 1nNluyAheS4rffsRSNIKAgw2kw8aU9rLZxBqFtPCVLE=

ログインができたら、GitLab が使えるようになります。GitLab の使い方は説明をすると長くなるので、ここでは以上で GitLab については、おしまいとします。

mailpit の画面

GitLab が送信するメールの確認をするためには、mailpit の Web 画面を表示します。

そのためには、Docker ホストで Web ブラウザの新しいウィンドウかタブを開いて、次の URL を開きます。

これで、GitLab から mailpit が受信したメールの確認ができます。GitLab を使っていると、パスワードの変更通知やメールアドレスの検証などのメールが流れてくるので、内容を確認して対応が必要な場合はします。

GitLab のアップグレード

GitLab を実際に運用するときは、アップグレードの方法も気になることでしょう。ここではアップグレードの手順を確認しておきます。

最初にバックアップを取ります。最低限、下記のものが必要です。

  • データベース
  • GitLab の シークレットファイル

もしフルバックアップをするなら次のコマンドを実行します。

CONTAINER_NAME=gitlab-ce
docker exec -it ${CONTAINER_NAME} \
    gitlab-backup create

データベースのバックアップだけで良いなら次のコマンドを実行します。

CONTAINER_NAME=gitlab-ce
docker exec -it ${CONTAINER_NAME} \
    gitlab-backup create SKIP=artifacts,repositories,registry,uploads,builds,pages,lfs,packages,terraform_state

これらのコマンドで作成されたバックアップはコンテナ内部の /var/opt/gitlab/backups に tar フォーマットで作成されます。ファイルを確認するには次のようにします。

CONTAINER_NAME=gitlab-ce
docker exec -it ${CONTAINER_NAME} \
    ls -l /var/opt/gitlab/backups

このコマンドの実行例は次のようになります。

$ CONTAINER_NAME=gitlab-ce
docker exec -it ${CONTAINER_NAME} \
    ls -l /var/opt/gitlab/backups
total 540
-rw------- 1 git git 552960 Dec 12 17:41 1733971265_2024_12_12_17.6.2_gitlab_backup.tar

シークレットファイルはコンテナ内部の /etc/gitlab/gitlab-secrets.json にあります。これらを Docker ホストへコピーすることで、バックアップができます。

これらを実行するスクリプト backup.sh を次のように作成します。

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

echo "---- backup gitlab-ce"
CONTAINER_NAME=gitlab-ce
docker exec -it ${CONTAINER_NAME} \
    gitlab-backup create SKIP=artifacts,repositories,registry,uploads,builds,pages,lfs,packages,terraform_state

if [ ! -e "${SCRIPT_DIR}/backup/" ]; then
    mkdir "${SCRIPT_DIR}/backup";
fi
for t in /etc/gitlab/gitlab-secrets.json /var/opt/gitlab/backups; do
    docker compose -p gitlab-ce cp gitlab-ce:"${t}" "${SCRIPT_DIR}/backup/"
done

echo "---- done"
tree "${SCRIPT_DIR}/backup/"

このコマンドの実行結果例は次のようになります。

$ sh backup.sh
---- backup gitlab-ce
(略)
---- done
/workspace/gitlab-ce/backup
├── backups
│   └── 1733971927_2024_12_12_17.6.2_gitlab_backup.tar
└── gitlab-secrets.json

本当は、バックアップからリストアができるかの確認もした方が良いのですが、ここでは省略します。GitLab のリストア手順は参考資料の URL の方にあるので興味がある人は確認してください。

バックアップが取れたら、docker compose pull で最新リリースのイメージをダウンロードしてから起動します。これで GitLab インスタンスがアップグレードされます。

docker compose pull
docker compose up -d

インスタンスアップグレード時は DB の構造が変更されたりするので、それなりに時間がかかります。

おわりに

このように GitLab を動作させること自体は Docker で簡単にできます。GitLab は高性能でメンテナンスもしっかりされているので、アップデート作業なども安心して行うことができます。資料も多く利用者もたくさんいるため、利用情報が入手しやすいです。そのため、サーバーマシンを用意できるならセルフホストで運用しやすいものになります。

ただし、動かしてみるとわかるはずですが、相当に重たいです。専用マシンを用意して動かすなら良いですが、開発しているマシンへ同居させて利用するというのは躊躇する人がほとんどでしょう。

筆者は、GitLab はそれなりの性能の Ubuntu サーバーマシンでセルフホストしていますが、Linux 初心者がそういった運用をするところまでいくまでのハードルはそれなりにあると考えています。世の中には、もっと軽量な Git システムもあるので、そちらから入門していくのが良いと考えています。

このように個人利用だと厳しい部分がありますが、中小企業などでセルフホスト Git サービスを用意しようということになったら、GitLab が最有力候補となります。そのため GitLab をローカルマシンで動かせるようになっておくことは意味があります。

また、実際に GitLab を使っている開発現場にいる場合は、「GitLab のある機能を使ってみたいけど、会社で使っている GitLab で環境を壊したらいけない。まずはローカルマシンで試してみてから導入の提案をしたい」といった要望を持つこともあるでしょう。そういったときに、こういった Docker 版の GitLab で試せるスキルを持っていたら、それは強みになるはずです。

ということで、サーバーマシンがある人は、セルフホスト Git サービスとして GitLab を動かしてみてもらいたいと思います。

参考資料

Discussion