Docker 版 GitLab と mailpit の HTTPS 対応:Linux 使い(略)Advent Calendar 2024
はじめに
これは「Linux 使いになりたい人のための Advent Calendar 2024」の記事です。
筆者は、Web エンジニアを志望する人には、セルフホスト Git サービスを稼働させて利用することをオススメしています。もし Git を使ったことがないなら、Git を学ぶときに、セルフホスト Git サービスを稼働させることも視野に含めながら学習するのが効率的だと考えています。
Docker 版 GitLab と Mailpit の HTTPS 対応
前回はセルフホスト Git サービスを稼働させるにあたり、HTTPS 対応もできるようにしたいということから、cloudflare/cfssl
を使って用意したサーバー証明書を Docker 版 GitLab と Mailpit へ設置するところまで説明しました。
今回は、HTTPS 対応した Docker 版 GitLab と Mailpit を、Docker ホストの Web ブラウザや、他のコンテナーから使って動作確認してみます。
ディレクトリー構成
今回、作業で使用するディレクトリー構成は次のようになります。
./
├── cfssl/ca/ca.pem ... 自己認証局の証明書
└── gitlab-ce-https/ ... HTTPS 対応の GitLab 用
├── backup/ ... バックアップ用
├── init/gitlab-ce-https/ ... 前回用意した初期化用
├── script/ ... 今回使用するスクリプト
│ ├── backup.sh
│ ├── down.sh
│ └── run.sh
├── srv/gitlab/ ... 前回初期化時に作成した GitLab のバインドマウント用
├── sample.env ... .env のサンプル
├── compose-gitlab-ce-https-net.yaml ... Docker ネットワーク用
└── compose.yaml ... HTTPS 対応の GitLab コンテナー用
前々回に用意した自己認証局の証明書である cfssl/ca/ca.pem
を使います。
なお、ここでは cfssl
ディレクトリーを ${CFSSL_DIR}
と表記ます。また、${CFSSL_DIR}
と同じ階層にある gitlab-ce-https
ディレクトリーを ${GITLAB_CE_HTTPS_DIR}
と表記します。
HTTPS 対応の GitLab コンテナー用 compose.yaml
HTTPS 対応の GitLab コンテナー用 compose.yaml
は次のようにします。
name: gitlab-ce-https
services:
gitlab-ce-https:
# ---- バージョン固定時は下記のようにバージョン指定し、固定しない場合は latest
# image: 'gitlab/gitlab-ce:17.6.1-ce.0'
image: 'gitlab/gitlab-ce:latest'
restart: always
container_name: 'gitlab-ce-https'
hostname: '${HOST_NAME:-gitlab-ce-https.local.internal}'
ports:
# - '80:80'
- '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'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://${HOST_NAME:-gitlab-ce-https.local.internal}:${HTTPS_PORT:-8443}'
gitlab_rails['gitlab_shell_ssh_port'] = ${SSH_SHELL_PORT:-2424}
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = 'mailpit.local.internal'
gitlab_rails['smtp_port'] = 1025
gitlab_rails['smtp_domain'] = 'local.internal'
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@local.internal'
gitlab_rails['gitlab_email_display_name'] = 'mailpit'
gitlab_rails['gitlab_email_reply_to'] = 'no-reply@local.internal'
letsencrypt['enable'] = false
shm_size: '256m'
cpu_quota: 60000 # コンテナが100ミリ秒あたり60ミリ秒CPUを利用可能とする設定
deploy:
resources:
limits:
# cpus: "4"
memory: 6g
logging:
driver: journald
options:
tag: gitlab-ce-https
healthcheck:
test: 'curl --insecure https://127.0.0.1:${HTTPS_PORT:-8443}/-/health'
interval: 60s
timeout: 5s
retries: 5
start_period: 120s
# ---- 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.local.internal'
ports:
- '${MAILPIT_UI_IP_PORT:-127.0.0.1:8025}:8025'
- '${MAILPIT_IP_PORT:-127.0.0.1:1025}:1025'
# ---- mailpit のメールを永続化したい場合
volumes:
- mailpit-data:/data
environment:
# ---- mailpit のメールを永続化したい場合の DB ファイル名指定
- 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
volumes:
# ---- mailpit のメールを永続化したい場合はこちらも有効化
mailpit-data:
name: gitlab-ce-https-mailpit-data
初期化が済んでいるので、Let's encrypt はもう使いません。GITLAB_OMNIBUS_CONFIG
に letsencrypt['enable'] = false
の指定を追加します。抜粋すると次の部分です。
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://${HOST_NAME:-gitlab-ce-https.local.internal}:${HTTPS_PORT:-8443}'
(略)
letsencrypt['enable'] = false
Mailpit については、IP アドレスとポート番号を .env
ファイルで変更可能とするために、次の環境変数を用意して使うようにしました。
MAILPIT_UI_IP_PORT
MAILPIT_IP_PORT
.env
のサンプルである sample.env
は次のようになります。
GITLAB_HOME=./srv/gitlab
HOST_NAME=gitlab-ce-https.local.internal
HTTPS_IP_PORT=127.0.0.1:8443
HTTPS_PORT=8443
SSH_IP_PORT=127.0.0.1:2424
SSH_SHELL_PORT=2424
MAILPIT_UI_IP_PORT=127.0.0.1:8025
MAILPIT_IP_PORT=127.0.0.1:1025
gitlab-ce-https-net ネットワーク
また、後で GitLab Runner を起動するときに、同じ Docker ネットワークで稼働させたいので、そのための gitlab-ce-https-net
ネットワークを追加します。
方法としては compose.yaml
へ直接追加することもできますが、ここでは別ファイルで用意して、後で用意する run.sh
で起動時にこれも指定する方法にします。
compose-gitlab-ce-https-net.yaml
name: gitlab-ce-https
services:
gitlab-ce-https:
networks:
gitlab-ce-https-net:
mailpit:
networks:
gitlab-ce-https-net:
networks:
gitlab-ce-https-net:
name: gitlab-ce-https-net
複数の compose.yaml
を使う場合は docker compose config
コマンドで設定を確認しておくと間違いがありません。
docker compose config
HTTPS 対応の GitLab コンテナー用スクリプト
起動時に複数の compose.yaml
を使うので、起動用の script/run.sh
では次のような処理をすることになります。
DC_OPT="-f ${PROJECT_DIR}/compose-gitlab-ce-https-net.yaml"
DC_OPT="-f ${PROJECT_DIR}/compose.yaml ${DC_OPT}"
# shellcheck disable=SC2086
docker compose ${DC_OPT} up -d
全体は次のようになります。
#!/bin/sh
SCRIPT_DIRNAME=$(dirname "$0")
SCRIPT_DIR=$(cd "${SCRIPT_DIRNAME}/" || exit 1;pwd)
PROJECT_DIR=$(cd "${SCRIPT_DIR}/.." || exit 1;pwd)
DOCKER_PROJECT_NAME=$(basename "${PROJECT_DIR}")
CONTAINER_NAME=gitlab-ce-https
DC_OPT="-f ${PROJECT_DIR}/compose-gitlab-ce-https-net.yaml"
DC_OPT="-f ${PROJECT_DIR}/compose.yaml ${DC_OPT}"
# shellcheck disable=SC2086
docker compose ${DC_OPT} up -d
echo "start - ${CONTAINER_NAME} check healthy: $(date '+%Y-%m-%d %H:%M:%S')"
until docker inspect "${CONTAINER_NAME}" | grep "Status" | grep -v "unhealthy" | grep "healthy" > /dev/null; do
>&2 echo "${CONTAINER_NAME}: not healthy"
sleep 30
done
echo "done - ${CONTAINER_NAME} check healthy: $(date '+%Y-%m-%d %H:%M:%S')"
echo "start - ${CONTAINER_NAME} gitlab reconfigure : $(date '+%Y-%m-%d %H:%M:%S')"
until docker compose -p "${DOCKER_PROJECT_NAME}" logs | grep "gitlab Reconfigured" > /dev/null; do
>&2 echo "${CONTAINER_NAME}: gitlab reconfigure..."
sleep 30
done
echo "done - ${CONTAINER_NAME} gitlab reconfigured: $(date '+%Y-%m-%d %H:%M:%S')"
バックアップ用スクリプト script/backup.sh
とコンテナー削除用の script/down.sh
については、前回に紹介したものについて、Docker Compose プロジェクト名、コンテナー名を変更すれば良いだけなので、省略します。
HTTPS 対応版コンテナーの起動と動作確認
準備ができたら script/run.sh
スクリプトで HTTPS 対応の GitLab コンテナーと Mailpit コンテナーを起動します。
cd ${GITLAB_CE_HTTPS_DIR}
sh script/run.sh
次に Docker コンテナーを使って動作確認をしますが、その前に Docker ネットワークの bridge
で使っている Gateway
の IP アドレスを確認しておきます。
$ docker network inspect bridge | grep Gateway
"Gateway": "172.17.0.1"
これが必要になることについては、Docker ネットワークについての知識が必要になります。詳細は省略しますが、簡単に説明しておくと、gitlab.local.internal
コンテナーや mailpit.local.internal
コンテナーへ他の Docker コンテナーから クセスするときは、この bridge
ネットワーク経由で Docker ホスト用に公開しているポートへアクセスするので、この IP アドレスが必要となります。
それから、動作確認用に Docker コンテナーを docker container run
コマンドで起動します。Docker イメージとしては ubuntu:24.04
を使い、起動コマンドは bash
とします。
このとき、コンテナーの /etc/hosts
へエントリーを追加するために --add-host
を使います。ここで指定する IP アドレスは、先程調べた bridge
で使っている Gateway
の IP アドレスにします。
また、ホスト名を webclient001
、コンテナー名を webclient001
として区別しやすくしておきます。
さらに、${CFSSL_DIR}/ca/ca.pem
を使うので、--volume
でバインドマウントしてコンテナー内のファイルとして見えるようにしておきます。
整理すると、次の docker container run
コマンドになります。
cd ${CFSSL_DIR}/ca/
docker container run --rm -it \
--add-host "gitlab-ce-https.local.internal:172.17.0.1" \
--add-host "mailpit.local.internal:172.17.0.1" \
--hostname webclient001 \
--name webclient001 \
--volume "$(pwd)/ca.pem:/cfssl-ca.crt" \
ubuntu:24.04 \
bash
コマンド実行したら、コンテナーにアタッチした状態の bash
プロンプトが表示されます。このまま、コンテナー内でコマンド実行して、バインドマウントしたファイルや /etc/hosts
に指定したホストのエントリーが追加されているか確認します。
root@webclient001:/# ls /cfssl-ca.crt
/cfssl-ca.crt
root@webclient001:/# cat /etc/hosts | tail -3
172.17.0.1 gitlab-ce-https.local.internal
172.17.0.1 mailpit.local.internal
172.17.0.2 webclient001
次に認証局の証明書をサーバーへ登録するために必要な ca-certificates
パッケージをインストールします。また、動作確認用に curl
パッケージをインストールします。
apt update && apt -y install ca-certificates curl
それから、次の HTTPS 化された Mailpit コンテナーへ curl
コマンドでアクセスしてみます。Mailpit コンテナーの方が GitLab コンテナーよりも先に起動するので、こちらで動作確認します。
ここでは実行結果の最後に改行をつけるため、オプションとして -w'\n'
をつけています。
curl -w'\n' https://mailpit.local.internal:8025/
ここまでのコマンド実行結果例は次のようになります。
root@webclient001:/# apt update && apt -y install ca-certificates curl
(略)
root@webclient001:/# curl -w'\n' https://mailpit.local.internal:8025/
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
このように curl
コマンドは失敗します。
サーバー証明書の検証をしないようにオプション --insecure
をつけて curl
コマンドを実行することもできます。
curl -w'\n' --insecure https://mailpit.local.internal:8025/
こちらの実行例は次のようになり、成功して HTML データが取得できます。
root@webclient001:/# curl -w'\n' --insecure https://mailpit.local.internal:8025/
<!DOCTYPE html>
<html lang="en" class="h-100">
(略)
</html>
root@h001:/#
一応、アクセスができますが、--insecure
オプションをつけなくても成功するようにしたいところです。
自己認証局の証明書をシステムへ登録
さて、curl
コマンドへ --insecure
オプションをつけなくてもアクセスできるようにするには、自己認証局の証明書をシステムへ登録します。そのためのコマンドが ca-certificates
パッケージに含まれる update-ca-certificates
コマンドです。
Ubuntu では、用意した自己認証局の証明書ファイルを /usr/local/share/ca-certificates/
においてから update-ca-certificates
コマンドを実行すると、自己認証局の証明書をシステムへ登録できます。
ここでは次のコマンドを実行します。
cp /cfssl-ca.crt /usr/local/share/ca-certificates/cfssl-ca.crt
update-ca-certificates
update-ca-certificates
コマンドの実行結果の例は次のようになります。
root@h001:/# update-ca-certificates
Updating certificates in /etc/ssl/certs...
rehash: warning: skipping ca-certificates.crt,it does not contain exactly one certificate or CRL
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
証明書が登録されると 1 added, 0 removed; done.
といったメッセージが出力されます。ここが 0 added, 0 removed; done.
となっていると追加登録はされていません。
証明書を登録したら、--insecure
オプションをつけずに curl
コマンドを実行してみましょう。
root@webclient001:/# curl -w'\n' https://mailpit.local.internal:8025/
<!DOCTYPE html>
<html lang="en" class="h-100">
(略)
</html>
今度は成功するはずです。
Web ブラウザへ自己認証局の証明書をインポート
次に、Web ブラウザへ自己認証局の証明書をインポートします。ここでは Ubuntu Desktop 版の Chrome での作業例を説明します。
Chrome を起動したら、ロケーションバーに次の URL を指定します。
それから、次の手順を踏みます。
- 表示される画面で「認証局」を選択
- 表示される画面で「インポート」をクリック
- ファイル選択画面で
${CFSSL_DIR}/ca/ca.pem
を選び、「選択」をクリック - 認証局の画面で「信頼の設定」について、すべてのチェックボックスをチェック
- 「OK」をクリック
これで、「org-local.internal」の自己認証局の証明書が Web ブラウザにインポートされます。
この設定をしてから HTTPS 対応した GitLab コンテナーや Mailpit コンテナーへアクセスすると、警告なしで URL を開くことができます。
確認のため、次の URL を開いてみましょう。
おわりに
cfssl
の説明から3回かけて HTTPS 対応について説明しました。自己署名でも HTTPS 対応はできますが、自己認証局を使う場合は、このようにそれなりの手間がかかります。
しかし、手間をかけた分、設定の後のシステムは通常環境に近い警告の出ない環境となり、全体の使い勝手は良くなります。また、こうやって証明書関連の作業ができるようになると、この関係の知識も増えていき、スキルアップにつながります。
とはいえ、自己認証局の証明書をシステムへ登録するのは、どこまで対応するのか、という課題は残ります。
たとえば、Docker コンテナーを使うときに、毎回、update-ca-certificates
コマンドが実行できるようにして自己認証局の証明書を登録するのは大変です。登録済みの Docker イメージをカスタムビルドしてから使うというのが現実的ですが、カスタムビルドしないと使えないというのもいまひとつなときがあることでしょう。
できることが増えても、全部ができるわけでなく、できないこともわかるようになります。いずれにせよ、選択肢の幅は広まるので、このように、セルフホスト Git サービスの稼働をテーマに作業をして、スキルアップしていくのが良いと考えています。
Discussion