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 は自己署名のサーバー証明書で動作するので、HTTPS 対応自体はしていましたが、最初のアクセス時に Web ブラウザ上で警告が出てしまったり、Web クライアントからアクセスするときにサーバー証明書の妥当性検証を無視する設定が必要だったりしました。
cfssl で作成したサーバー証明書や自己認証局の証明書を使って、どのようにシステム利用時の挙動が変わるか見てみたいところです。全部説明したいところですが作業量が多いので、今回は準備の説明だけにします。
ディレクトリー構成
今回用意するディレクトリー構成は次のようにします。初期化の作業用にディレクトリーを用意しています。
gitlab-ce-https/init/gitlab-ce-https/
├── compose.yaml
└── script/
├── down.sh
├── init.sh
└── run.sh
なお、ここでは最初の gitlab-ce-https
ディレクトリーを ${GITLAB_CE_HTTPS_DIR}
と表記します。
ホスト名の FQDN
サーバー証明書を利用するにあたっては、ホスト名を gitlab-ce.local.internal
のような Fully Qualified Domain Name(FQDN、完全修飾ドメイン名)で使用する必要がありました。
内部的に使用するドメイン名は最後に .internal
をつければ良いので、ここでは、local.internal
というドメインで各サーバー用コンテナーを用意することにします。
ホスト名 | 提供するサービス |
---|---|
gitlab-ce-https.local.internal | GitLab |
mailpit.local.internal | Mailpit |
これらは Docker ホストマシンで動かすので、hosts ファイル(Ubuntu/WSL Ubuntu は /etc/hosts
、Windows は C:\Windows\System32\drivers\etc\hosts
)へ次のエントリーを追記します。ファイル編集には管理者権限が必要です。
127.0.0.1 gitlab-ce-https.local.internal
127.0.0.1 mailpit.local.internal
FQDN 使用版の compose.yaml
それでは、以前作成した compose.yaml
をベースにして FQDN 使用版にしてみましょう。
次の変更をします。
- ホスト名について FQDN を使用するように変更
- mailpit.local.internal 用の Docker ボリュームを有効化
- ポート番号 8443 については
127.0.0.1
以外の IP アドレスでも有効化
具体的には次のようになります。
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}'
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'
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'
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:
- '127.0.0.1:8025:8025'
- '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
# ---- mailpit のメールを永続化したい場合はこちらも有効化
volumes:
mailpit-data:
name: gitlab-ce-https-mailpit-data
スクリプトの用意
次に script
ディレクトリーにスクリプトを用意します。
バインドマウントをするときに必要なディレクトリーを作成するため、次のようなスクリプト script/init.sh
を用意します。
#!/bin/sh
SCRIPT_DIRNAME=$(dirname "$0")
SCRIPT_DIR=$(cd "${SCRIPT_DIRNAME}/" || exit 1;pwd)
PROJECT_DIR=$(cd "${SCRIPT_DIR}/../../.." || exit 1;pwd)
for t in config data logs; do
if [ ! -e "${PROJECT_DIR}/srv/gitlab/${t}" ]; then
mkdir -p "${PROJECT_DIR}/srv/gitlab/${t}";
fi
done
また、起動用スクリプト script/run.sh
も用意します。gitlab-ce-https コンテナーが使えるようになるまで、結構な時間が必要です。コンテナーが使える状態になったら、このスクリプトが終了するようにしてあります。どれくらい時間が必要だったかも実行後にわかるようにしてあるので、起動時は、これを使うようにしましょう。
#!/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=gitlab-ce-https
CONTAINER_NAME=gitlab-ce-https
docker compose -f "${PROJECT_DIR}/compose.yaml" 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}: reconfigure..."
sleep 30
done
echo "done - ${CONTAINER_NAME} gitlab reconfigured: $(date '+%Y-%m-%d %H:%M:%S')"
コンテナー削除用のスクリプト script/down.sh
も用意しておきます。
#!/bin/sh
DOCKER_PROJECT_NAME=gitlab-ce-https
docker compose -p "${DOCKER_PROJECT_NAME}" down
初期化作業
ファイルが用意できたら、初期化作業をします。
cd ${GITLAB_CE_HTTPS_DIR}
sh init/gitlab-ce-https/script/init.sh
sh init/gitlab-ce-https/script/run.sh
実行例は次のようになります。
$ sh init/gitlab-ce-https/script/run.sh
[+] Running 4/4
✔ Network gitlab-ce-https_default Created 0.1s
✔ Volume "gitlab-ce-https-mailpit-data" Created 0.0s
✔ Container mailpit Started 0.3s
✔ Container gitlab-ce-https Started 0.3s
start - gitlab-ce-https check healthy: 2024-12-18 19:52:50
gitlab-ce-https: not healthy
(略)
done - gitlab-ce-https check healthy: 2024-12-18 19:57:21
start - gitlab-ce-https gitlab reconfigure : 2024-12-18 19:57:21
gitlab-ce-https: reconfigure...
(略)
done - gitlab-ce-https gitlab reconfigured: 2024-12-18 20:04:23
GitLab のサーバー証明書設置
GitLab の起動が終わったら、GitLab のサーバー証明書を設置します。
実は GitLab の起動時に、内部では Let's encrypt によるサーバー証明書作成の処理が動いていて、done - gitlab-ce-https check healthy
の行が表示されたときには、次のファイルが作成されています。
$ ls /etc/gitlab/ssl
gitlab-ce-https.local.internal.crt gitlab-ce-https.local.internal.key-staging
gitlab-ce-https.local.internal.key letsencrypt_account_private_key.pem
この中で実際に HTTPS 設定時に必要なのは、ファイル名が .key
と .crt
で終わるもので、前回の cfssl
で作成したファイルとの対応は次のようになります。これらを置き換えれば良いということになります。
cfssl でのファイル名 | GitLab でのファイル名 |
---|---|
server-key.pem | gitlab-ce-https.local.internal.key |
server.pem | gitlab-ce-https.local.internal.crt |
ここでは、${GITLAB_CE_HTTPS_DIR}
を含むディレクトリーと同じところに前回の cfssl
ディレクトリーがあるとして、次のようにしてファイルコピーをします。自動生成されたものに戻して動作の違いをみたいこともあるので、それらをバックアップしてから更新しています。
sudo mv ./srv/gitlab/config/ssl/gitlab-ce-https.local.internal.key \
./srv/gitlab/config/ssl/gitlab-ce-https.local.internal.key.original
sudo mv ./srv/gitlab/config/ssl/gitlab-ce-https.local.internal.crt \
./srv/gitlab/config/ssl/gitlab-ce-https.local.internal.crt.original
sudo cp ../cfssl/server/server.pem \
./srv/gitlab/config/ssl/gitlab-ce-https.local.internal.crt
sudo cp ../cfssl/server/server-key.pem \
./srv/gitlab/config/ssl/gitlab-ce-https.local.internal.key
sudo ls -al ./srv/gitlab/config/ssl
サーバー証明書のファイルを変更したので、gitlab-ce-https
コンテナーは再起動する必要があります。
Mailpit のサーバー証明書設置
前回、cfssl
で作成したサーバー証明書は、gitlab-ce-https.local.internal
、mailpit.local.internal
、localhost
で使えるものしてありましたから、GitLab で使ったものと同じものが使えます。次のような対応関係になります。
cfssl でのファイル名 | Mailpit でのファイル名 |
---|---|
server-key.pem | private.key |
server.pem | server.crt |
ここで、Mailpit のサーバー証明書の置き場所は compose.yaml
でコメントにしてありますが、環境変数 MP_UI_TLS_CERT
と MP_UI_TLS_KEY
で指定できます。
GitLab のときと同様に、前回の cfssl
ディレクトリーから、次のようにしてファイルコピーをします。こちらは mailpit.local.interval:/data
の中は空なので用意したサーバー証明書ファイルをコピーするだけです。
docker compose -p gitlab-ce-https cp \
../cfssl/server/server.pem \
mailpit:data/server.crt
docker compose -p gitlab-ce-https cp \
../cfssl/server/server-key.pem \
mailpit:data/private.key
docker compose -p gitlab-ce-https exec mailpit \
ls -al /data/
こちらは、サーバー証明書のファイルが用意できたので、mailpit
コンテナーを停止してから compose.yaml
の内容を変更し、それから、mailpit
コンテナーを起動する必要があります。
初期化作業の終了
以上で、初期化作業は終了です。script/down.sh
スクリプトで、これらのコンテナーを停止します。
cd ${GITLAB_CE_HTTPS_DIR}
sh init/gitlab-ce-https/script/down.sh
おわりに
今回の説明はここまでにしておきます。今回の作業は待ち時間が長いので、やり直しが発生すると大変です。記事を執筆するにあたり、何度も初期化作業をすることになったので、結構時間が取られました。
最初に自動で実行される Let's encrypt の処理については無効化することができるのですが、それをすると証明書まわりの設定情報がどうなるのか調べる必要が出てきます。初期設定は自動処理に任せて、必要なファイルだけ置き換えた方が手間がかからないので、割り切ってそうしています。
なお、今回は run.sh
の方にも注目してもらいたいところです。時間がかかる処理については、自動化するときにどのようにチェックするか考える必要があります。シェルスクリプトの until
を使う方法はよく使われるので、こういう機会に覚えておくと良いでしょう。
Discussion