GitLab + docker registry + nginx リバースプロキシ + オレオレ証明書SSLをdocker-composeで構築
こちらの記事 でも利用させていただいた、 sameersbn / docker-gitlab とContainer Registryを連携して、さらにnginxでリバースプロキシしてついでにSSL化したいと思います。ただし、オレオレ証明書です。
今回はCentOSの仮想マシン上で構築してみます。
一応実行環境はこんな感じ。
$ cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
$ docker --version
Docker version 19.03.5, build 633a0ea
$ docker-compose --version
docker-compose version 1.25.0, build 0a186604
ではまず普通にdocker-composeでGitLabを構築します。
この時、「GITLAB_RELATIVE_URL_ROOT=/gitlab」にしといてください。
最後にdocker-compose.ymlを丸ごと載せてるのでそちらを見ながら読んでもらうといいかもです。
$ docker-compose up -d redis postgresql
$ docker-compose up -d gitlab
結構時間かかると思います。気長に待ちましょう。
無事起動したらhttp://[仮想マシンのIP]:10080/gitlabにアクセスして、
rootのパスワード設定しておいてください。
続いて証明書を作成します。
今回はdocker-compose.ymlがあるディレクトリにcertsディレクトリを作成し、
そこに証明書を作成します。
また、Chromeで怒られないようにSANを含めます。
詳しくはこちら
のサイト様を参照ください。
$ mkdir certs
$ cd certs/
$ openssl genrsa 2048 > server.key
Generating RSA private key, 2048 bit long modulus
..............................+++
.............+++
e is 65537 (0x10001)
$ openssl req -new -key server.key > server.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
$ echo subjectAltName=DNS:*.tsuchinokometal.com > san.ext
$ openssl x509 -days 3650 -req -signkey server.key < server.csr > server.crt -extfile san.ext
Signature ok
subject=/C=JP/L=Default City/O=Default Company Ltd
Getting Private key
続いて、nginx用の設定ファイルを先に作っておきます。
$ mkdir conf.d
$ vi conf.d/ssl.conf
ssl.confは以下の通り。
内容についてはほぼこちら
と一緒。
server {
root /dev/null;
server_name example.tsuchinokometal.com;
charset UTF-8;
listen *:443 ssl http2;
ssl_certificate /certs/server.crt;
ssl_certificate_key /certs/server.key;
ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4';
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_session_timeout 5m;
client_max_body_size 0;
chunked_transfer_encoding on;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
location /gitlab {
proxy_pass http://gitlab;
}
}
server {
listen *:80;
server_name example.tsuchinokometal.com;
server_tokens off;
return 301 https://$http_host:$request_uri;
}
さらにdocker-compose.ymlを変更します。
- GITLAB_HTTPS=true
- GITLAB_HOST=example.tsuchinokometal.com
以下を追記します。
nginx:
image: nginx
volumes:
- ./conf.d:/etc/nginx/conf.d
- ./certs:/certs
ports:
- "80:80"
- "443:443"
GitLabの再作成およびnginxを起動します。
$ docker-compose stop gitlab
$ docker-compose up -d gitlab
$ docker-compose up -d nginx
アクセスするためにオレオレ証明書を信頼させてください。
僕はMacを使っているのでこちら
を参考にさせていただきました。
あと、ドメインで名前解決できるようにhostsに追記しておいてください。
見ての通りexample.tsuchinokometal.comを想定して設定しています。
各自の環境に合わせて変更してください。
ここまでで、GitLabにhttpsでアクセスできると思いますが、どうでしょうか?
(リバースプロキシしてるんでポート指定が不要になります)
では、registryとの連携を構築します。
docker-compose.ymlを変更してください。
gitlabにcertsディレクトリをマウントしてregistryの設定を追記します。
volumes:
- ./certs:/certs
environment:
- GITLAB_REGISTRY_ENABLED=true
- GITLAB_REGISTRY_HOST=example.tsuchinokometal.com
- GITLAB_REGISTRY_PORT=443
- GITLAB_REGISTRY_API_URL=http://registry:5000
- GITLAB_REGISTRY_KEY_PATH=/certs/server.key
registryを追記します。 volumesにregistry-dataも追記しといてください。
registry:
restart: always
image: registry:2
expose:
- "5000"
ports:
- "5000:5000"
volumes:
- registry-data:/registry
- ./certs:/certs
environment:
- REGISTRY_LOG_LEVEL=info
- REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/registry
- REGISTRY_AUTH_TOKEN_REALM=https://example.tsuchinokometal.com/gitlab/jwt/auth
- REGISTRY_AUTH_TOKEN_SERVICE=container_registry
- REGISTRY_AUTH_TOKEN_ISSUER=gitlab-issuer
- REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE=/certs/server.crt
- REGISTRY_STORAGE_DELETE_ENABLED=true
さらに、nginxに以下を追記してください。
location /v2/ {
proxy_pass http://registry:5000;
}
コンテナを再起動したら、GitLabにログインして適当なプロジェクトを作成し、Container Registryを開いてみてください。
以下のように表示されれば成功です。
Macからregistryの動作確認します。 まずregistryにログインします。
% docker login example.tsuchinokometal.com
Username: root
Password:
Login Succeeded
このときこんなエラーが出た場合、Macの方のDockerを再起動してください。
Login did not succeed, error: Error response from daemon: Get https://example.tsuchinokometal.com/v2/: x509: certificate signed by unknown authority
適当なコンテナにタグ付けしてプッシュします。
% docker pull alpine:latest
latest: Pulling from library/alpine
c9b1b535fdd9: Pull complete
Digest: sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d
Status: Downloaded newer image for alpine:latest
docker.io/library/alpine:latest
% docker tag alpine:latest example.tsuchinokometal.com/root/test/hoge:fuga
% docker push example.tsuchinokometal.com/root/test/hoge:fuga
The push refers to repository [example.tsuchinokometal.com/root/test/hoge]
5216338b40a7: Pushed
fuga: digest: sha256:ddba4d27a7ffc3f86dd6c2f92041af252a1f23a8e742c90e6e1297bfa1bc0c45 size: 528
GitLab側でこんなふうに表示されます。
GitLabと連携させればソースコードと一緒にコンテナイメージが管理できますし、 GitLabのユーザで認証も付けられるのでかなり管理しやすいんじゃないでしょうか。
最終的に、docker-compose.ymlは以下のようになりました。 ここではやりませんでしたが、共有ネットワーク作ってdocker-compose.ymlを分割した方が管理しやすいかもですね。
version: '3'
services:
redis:
restart: always
image: sameersbn/redis:4.0.9-2
command:
- --loglevel warning
volumes:
- redis-data:/var/lib/redis:Z
postgresql:
restart: always
image: sameersbn/postgresql:10-2
volumes:
- postgresql-data:/var/lib/postgresql:Z
environment:
- DB_USER=gitlab
- DB_PASS=password
- DB_NAME=gitlabhq_production
- DB_EXTENSION=pg_trgm
gitlab:
restart: always
image: sameersbn/gitlab:12.5.5
depends_on:
- redis
- postgresql
ports:
- "10080:80"
- "10022:22"
volumes:
- gitlab-data:/home/git/data:Z
- ./certs:/certs
environment:
- GITLAB_REGISTRY_ENABLED=true
- GITLAB_REGISTRY_HOST=example.tsuchinokometal.com
- GITLAB_REGISTRY_PORT=443
- GITLAB_REGISTRY_API_URL=http://registry:5000
- GITLAB_REGISTRY_KEY_PATH=/certs/server.key
- DEBUG=false
- DB_ADAPTER=postgresql
- DB_HOST=postgresql
- DB_PORT=5432
- DB_USER=gitlab
- DB_PASS=password
- DB_NAME=gitlabhq_production
- REDIS_HOST=redis
- REDIS_PORT=6379
- TZ=Asia/Tokyo
- GITLAB_TIMEZONE=Tokyo
- GITLAB_HTTPS=true
- SSL_SELF_SIGNED=false
- GITLAB_HOST=example.tsuchinokometal.com
- GITLAB_PORT=10080
- GITLAB_SSH_PORT=10022
- GITLAB_RELATIVE_URL_ROOT=/gitlab
- GITLAB_SECRETS_DB_KEY_BASE=Nz7kgKFT9CzgscN7Wzj9chCp3KRk77ghr4wqmTHbdRxWw44Kmc9WpvPqfjFhkXM7
- GITLAB_SECRETS_SECRET_KEY_BASE=hPFsKkX4kqftKJpMwgnpvnqKwqsWmkfPsN3F4xTCbTghJ77qvnxdFkxkt3XX3PFT
- GITLAB_SECRETS_OTP_KEY_BASE=HXWdMCLhkWwLLMCnJLNK4sLhPk9VsskrvJpppCFfhRhfb9fMd9hdqWJp9tgCXXvz
- GITLAB_ROOT_PASSWORD=
- GITLAB_ROOT_EMAIL=
- GITLAB_NOTIFY_ON_BROKEN_BUILDS=true
- GITLAB_NOTIFY_PUSHER=false
- GITLAB_EMAIL=notifications@example.com
- GITLAB_EMAIL_REPLY_TO=noreply@example.com
- GITLAB_INCOMING_EMAIL_ADDRESS=reply@example.com
- GITLAB_BACKUP_SCHEDULE=daily
- GITLAB_BACKUP_TIME=01:00
- SMTP_ENABLED=false
- SMTP_DOMAIN=www.example.com
- SMTP_HOST=smtp.gmail.com
- SMTP_PORT=587
- SMTP_USER=mailer@example.com
- SMTP_PASS=password
- SMTP_STARTTLS=true
- SMTP_AUTHENTICATION=login
- IMAP_ENABLED=false
- IMAP_HOST=imap.gmail.com
- IMAP_PORT=993
- IMAP_USER=mailer@example.com
- IMAP_PASS=password
- IMAP_SSL=true
- IMAP_STARTTLS=false
- OAUTH_ENABLED=false
- OAUTH_AUTO_SIGN_IN_WITH_PROVIDER=
- OAUTH_ALLOW_SSO=
- OAUTH_BLOCK_AUTO_CREATED_USERS=true
- OAUTH_AUTO_LINK_LDAP_USER=false
- OAUTH_AUTO_LINK_SAML_USER=false
- OAUTH_EXTERNAL_PROVIDERS=
- OAUTH_CAS3_LABEL=cas3
- OAUTH_CAS3_SERVER=
- OAUTH_CAS3_DISABLE_SSL_VERIFICATION=false
- OAUTH_CAS3_LOGIN_URL=/cas/login
- OAUTH_CAS3_VALIDATE_URL=/cas/p3/serviceValidate
- OAUTH_CAS3_LOGOUT_URL=/cas/logout
- OAUTH_GOOGLE_API_KEY=
- OAUTH_GOOGLE_APP_SECRET=
- OAUTH_GOOGLE_RESTRICT_DOMAIN=
- OAUTH_FACEBOOK_API_KEY=
- OAUTH_FACEBOOK_APP_SECRET=
- OAUTH_TWITTER_API_KEY=
- OAUTH_TWITTER_APP_SECRET=
- OAUTH_GITHUB_API_KEY=
- OAUTH_GITHUB_APP_SECRET=
- OAUTH_GITHUB_URL=
- OAUTH_GITHUB_VERIFY_SSL=
- OAUTH_GITLAB_API_KEY=
- OAUTH_GITLAB_APP_SECRET=
- OAUTH_BITBUCKET_API_KEY=
- OAUTH_BITBUCKET_APP_SECRET=
- OAUTH_SAML_ASSERTION_CONSUMER_SERVICE_URL=
- OAUTH_SAML_IDP_CERT_FINGERPRINT=
- OAUTH_SAML_IDP_SSO_TARGET_URL=
- OAUTH_SAML_ISSUER=
- OAUTH_SAML_LABEL="Our SAML Provider"
- OAUTH_SAML_NAME_IDENTIFIER_FORMAT=urn:oasis:names:tc:SAML:2.0:nameid-format:transient
- OAUTH_SAML_GROUPS_ATTRIBUTE=
- OAUTH_SAML_EXTERNAL_GROUPS=
- OAUTH_SAML_ATTRIBUTE_STATEMENTS_EMAIL=
- OAUTH_SAML_ATTRIBUTE_STATEMENTS_NAME=
- OAUTH_SAML_ATTRIBUTE_STATEMENTS_USERNAME=
- OAUTH_SAML_ATTRIBUTE_STATEMENTS_FIRST_NAME=
- OAUTH_SAML_ATTRIBUTE_STATEMENTS_LAST_NAME=
- OAUTH_CROWD_SERVER_URL=
- OAUTH_CROWD_APP_NAME=
- OAUTH_CROWD_APP_PASSWORD=
- OAUTH_AUTH0_CLIENT_ID=
- OAUTH_AUTH0_CLIENT_SECRET=
- OAUTH_AUTH0_DOMAIN=
- OAUTH_AUTH0_SCOPE=
- OAUTH_AZURE_API_KEY=
- OAUTH_AZURE_API_SECRET=
- OAUTH_AZURE_TENANT_ID=
nginx:
image: nginx
volumes:
- ./conf.d:/etc/nginx/conf.d
- ./certs:/certs
ports:
- "80:80"
- "443:443"
registry:
restart: always
image: registry:2
expose:
- "5000"
ports:
- "5000:5000"
volumes:
- registry-data:/registry
- ./certs:/certs
environment:
- REGISTRY_LOG_LEVEL=info
- REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/registry
- REGISTRY_AUTH_TOKEN_REALM=https://example.tsuchinokometal.com/gitlab/jwt/auth
- REGISTRY_AUTH_TOKEN_SERVICE=container_registry
- REGISTRY_AUTH_TOKEN_ISSUER=gitlab-issuer
- REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE=/certs/server.crt
- REGISTRY_STORAGE_DELETE_ENABLED=true
volumes:
redis-data:
postgresql-data:
gitlab-data:
registry-data:
一応ssl.confはこんな感じ。
server {
root /dev/null;
server_name example.tsuchinokometal.com;
charset UTF-8;
listen *:443 ssl http2;
ssl_certificate /certs/server.crt;
ssl_certificate_key /certs/server.key;
ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4';
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_session_timeout 5m;
client_max_body_size 0;
chunked_transfer_encoding on;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
location /gitlab {
proxy_pass http://gitlab;
}
location /v2/ {
proxy_pass http://registry:5000;
}
}
server {
listen *:80;
server_name example.tsuchinokometal.com;
server_tokens off;
return 301 https://$http_host:$request_uri;
}