概要
通常、Self-Managed版のGitLabは内部的にバンドルされているNginxを使うようになっているが、それを使わず別のWebサーバーを使うことが可能になっている。
Docker版のGitLabを利用する際、バンドルされたNginxを無効化し、同じくコンテナとしてたてたNginxを使うようにするために必要になった設定をメモとして残す。
動作環境
- Linux: Ubuntu 22.04
- GitLabイメージ: gitlab/gitlab-ce:16.8.5-ce.0
- Nginxイメージ: nginx:1.25.5
起こった問題
以下のようなdocker-compoaseの定義ファイル(一部抜粋)を用意し、コンテナを起動した。
service:
gitlab:
image: gitlab/gitlab-ce:16.8.5-ce.0
container_name: gitlab
restart: always
environment:
# GITLAB_OMNIBUS_CONFIG環境変数を追加することで内容が設定として反映される
# nginx['enable'] = false: バンドルされたNginxを無効化
# web_server['external_users'] = ['www-data']: コンテナで動かすNginxのプロセスはwww-dataユーザーで実行されている
# gitlab_rails['trusted_proxies'] = ['172.17.0.0/16']: Dockerデフォルトのブリッジネットワークのアドレス範囲からの通信を許可
GITLAB_OMNIBUS_CONFIG: |
external_url '<GitLabを公開するURL>'
nginx['enable'] = false
web_server['external_users'] = ['www-data']
gitlab_rails['trusted_proxies'] = ['172.17.0.0/16']
expose:
- '80'
volumes:
- gitlabsocket:/var/opt/gitlab/gitlab-workhorse/sockets
nginx:
container_name: nginx
build: ./nginx
restart: always
tty: true
ports:
- '80:80'
volumes:
- gitlabsocket:/var/opt/gitlab/gitlab-workhorse/sockets
volumes:
gitlabsocket:
ここで、Dockerボリュームgitlabsocket
を用意し双方のコンテナにマウントすることで、gitlabコンテナの/var/opt/gitlab/gitlab-workhorse/sockets
に存在するソケットファイルにnginxコンテナがアクセスできるようにしている。また、Nginx側の.confファイルで以下のようにソケットのパスを指定していた。
upstream gitlab-workhorse {
server unix:/var/opt/gitlab/gitlab-workhorse/sockets/socket
}
上記設定でコンテナを起動してアクセスしたところ、nginxの502 Bad Gatewayのレスポンスとなった。nginx側ではconnect() to unix:/var/opt/gitlab/gitlab-workhorse/sockets/socket failed (13: Permission denied) while connecting to upstream
のようなエラーログが出ており、ソケットファイルにアクセスする権限がないことが原因だった。
うまくいかなかった方法
GitLabのイシューの回答を参考に、以下のようなシェルスクリプトをnginxコンテナの/docker-entrypoint.d
に格納するようにした。(Nginx公式のイメージでは/docker-entrypoint.d内のシェルスクリプトがコンテナ起動時に順次実行される)
#!/bin/sh
SOCKET_DIR="/var/opt/gitlab/gitlab-workhorse/sockets"
SOCKET_FILE=$SOCKET_DIR"/socket"
while [ ! -e $SOCKET_FILE ]
do
sleep 1
done
chmod -R 777 $SOCKET_DIR
これにより、ソケットファイルが作られたらその権限を変更することで、nginxのwww-data
ユーザーがアクセスしコンテナ間通信ができるようになった。
しかし、ホストのマシンを再起動したり、docker compose restart
したりすると再度通信ができなくなってしまった。これは、ボリュームマウントされているソケットファイルがrestart直後も残っているために、gitlabコンテナが立ち上がり新しいソケットファイルが作られた際にそれを検知して権限を更新し直すことができなかったためと考えられた。
うまくいった方法
そもそも、nginxコンテナ側でソケットファイル/var/opt/gitlab/gitlab-workhorse/sockets/socket
の所有者・所有グループを確認すると、UID=998, GID=998となっている。
gitlabコンテナの方を見てみると、gitlabのプロセスを実行しているユーザーgit
(グループgit
)はUID=998、GID=998であり、ソケットファイルもこのgit
ユーザーが所有しているということがわかる。
そのため、Nginx側もワーカープロセスをUID998のgit
ユーザーで動かせばソケットファイルにアクセスできることになる。
gitlabコンテナの設定を以下のように変更してUID、GIDを明示的に指定するとともに、外部Webサーバーのユーザー名はgit
に変える。
- web_server['external_users'] = ['www-data']
+ web_server['external_users'] = ['git']
+ user['uid'] = 998
+ user['gid'] = 998
さらに、Nginx側ではDockerfileでgit
ユーザーとgit
グループをUID=998、GID=998で作るよう指定し、
RUN groupadd -g 998 git && useradd -u 998 -g 998 git
Nginxの.confファイルでワーカープロセスはgitユーザーが実行することにする。
user git;
上記設定により、nginxコンテナとgitlabコンテナ間でUNIXドメインソケットによる通信をさせることができた。