背景
これの続きとして、docker-registryへhttpsで接続できるようにしたい。
nginxでリバースプロキシを構築して上記を実現する予定ですが、そもそもリバースプロキシを使ったことがないため、実際に導入してイメージをつかんでみます。
docker-composeを使います。
環境
- AWSのEC2
- 使ったAMIはamzn2-ami-hvm-2.0.20210126.0-x86_64-gp2
dockerバージョン
$ docker --version
Docker version 20.10.4, build d3cb89e
$ docker-compose --version
docker-compose version 1.27.4, build 40524192
構成図
前提
- https接続のための証明書が取得済みであること。
本環境ではletsencryptで発行したSSL証明書を使います。 - docker,docker-composeが使えること
フォルダ構成
.
|-- cert
| |-- fullchain.pem # サーバ証明書
| `-- privkey.pem # 秘密鍵
|-- docker-compose.yaml
|-- reverseproxy
| `-- nginx.conf
|-- web1
| `-- index.html
|-- web2
| `-- index.html
`-- web3
`-- index.html
webサーバのindex.htmlは↓です。
$ cat web{1..3}/index.html
<h1>this is web1</h1>
<h1>this is web2</h1>
<h1>this is web3</h1>
docker-compose.yaml
以下を使用しました
version: "3.9"
services:
reverse-proxy:
image: nginx:1.20
extra_hosts:
- "host.docker.internal:host-gateway" # 注1
ports:
- 5043:443
volumes:
- ./cert/fullchain.pem:/etc/nginx/conf.d/fullchain.pem:ro
- ./cert/privkey.pem:/etc/nginx/conf.d/privkey.pem:ro
- ./reverseproxy/nginx.conf:/etc/nginx/nginx.conf:ro
- ./reverseproxy/.htpasswd:/etc/nginx/.htpasswd:ro
web1:
image: nginx:1.20
extra_hosts:
- "host.docker.internal:host-gateway" # 注1
ports:
- 6043:80
volumes:
- ./web1/index.html:/usr/share/nginx/html/index.html
web2:
image: nginx:1.20
extra_hosts:
- "host.docker.internal:host-gateway" # 注1
ports:
- 7043:80
volumes:
- ./web2/index.html:/usr/share/nginx/html/index.html
web3:
image: nginx:1.20
extra_hosts:
- "host.docker.internal:host-gateway" # 注1
ports:
- 8043:80
volumes:
- ./web3/index.html:/usr/share/nginx/html/index.html
nginx.conf
リバースプロキシとして動作させるnginxのconfファイルは以下です。
events { # 注2
worker_connections 1024;
}
http {
server {
listen 443 ;
ssl on ; # 注3
ssl_protocols TLSv1.3; # 注4
ssl_certificate /etc/nginx/conf.d/fullchain.pem;
ssl_certificate_key /etc/nginx/conf.d/privkey.pem;
server_name localhost;
location /web1 {
proxy_pass http://host.docker.internal:6043/; # 注1
proxy_set_header Host $host;
proxy_set_header X-Forwarded-for $remote_addr;
auth_basic_user_file /etc/nginx/.htpasswd; # 注5
auth_basic "basic ninnsyou";
}
location /web2 {
proxy_pass http://host.docker.internal:7043/; # 注1
proxy_set_header Host $host;
proxy_set_header X-Forwarded-for $remote_addr;
auth_basic_user_file /etc/nginx/.htpasswd;
auth_basic "basic ninnsyou";
}
location /web3 {
proxy_pass http://host.docker.internal:8043/; # 注1
proxy_set_header Host $host;
proxy_set_header X-Forwarded-for $remote_addr;
auth_basic_user_file /etc/nginx/.htpasswd;
auth_basic "basic ninnsyou";
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
注を付けた箇所の説明をします。
注1 host.docker.internal について
ここを参考にさせていただきました。
extra_hosts:
- "host.docker.internal:host-gateway"
とすることで、コンテナからホストへのアクセスを実現しています。
extra_hostsはドメインとIPアドレスに紐づけを行います。/etc/hostsのようなものです。
host.docker.internal はホストにアクセスするための特別なドメインであり、host-gatewayを選択すればホストにアクセスできる様です。
githubのページから手順の参考にしましたが、公式のドキュメントには現時点でlinux向けの記載はなさそうです。
(docker for Windows , docker for MACについては記載があります)
注1 localhostの指定はOK?
localhost:6043と指定してもうまくいきません。
リバースプロキシコンテナのlocalhost:6043に転送され、ホストの6043に転送されるわけではないからです。
上記のhost.docker.internalや、ホストのIPアドレスを指定しましょう。
dockerのネットワーク、DNSについてはいずれまとめて調べてみたいですね。
注2 nginx.conf eventsブロックについて
ここの記載がないとリバースプロキシコンテナが立ち上がりません。(そもそもnginxが動作しない)
何らかの値を入れれば問題なく通りそうです。
$ head -n 3 reverseproxy/nginx.conf
#events {
# worker_connections 1024;
#}
$ docker-compose up -d
$ docker-compose logs reverse-proxy
...
reverse-proxy_1 | /docker-entrypoint.sh: Configuration complete; ready for start up
reverse-proxy_1 | 2021/05/22 06:01:11 [emerg] 1#1: no "events" section in configuration
reverse-proxy_1 | nginx: [emerg] no "events" section in configuration
$
$ head -n 3 reverseproxy/nginx.conf
events {
worker_connections 1024;
}
$ docker-compose up -d
$ docker-compose logs reverse-proxy
...
reverse-proxy_1 | /docker-entrypoint.sh: Configuration complete; ready for start up
$
知らなかったです。
注3 nginx.conf SSLの記載箇所
最初以下の様にしていました。
起動すると非推奨だと怒られました。動作はします。
server {
listen 443 ;
ssl on ;
[docker] $ docker-compose logs reverse-proxy
...
reverse-proxy_1 | 2021/05/22 06:18:48 [warn] 1#1: the "ssl" directive is deprecated, use the "listen ... ssl" directive instead in /etc/nginx/nginx.conf:8
reverse-proxy_1 | nginx: [warn] the "ssl" directive is deprecated, use the "listen ... ssl" directive instead in /etc/nginx/nginx.conf:8
reverse-proxy_1 | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
reverse-proxy_1 | /docker-entrypoint.sh: Configuration complete; ready for start up
過去のバージョンと記法が異なっているのでしょうか。
ドキュメントにある通り、以下の記載にしましょう
server {
listen 443 ssl;
注4 TLS1.3に限定する
安全性を考慮してTLS1.3の通信に限定しました。
以下の様に記載したらTLS1.3を使わない通信は弾いてくれます。
server {
ssl_protocols TLSv1.3;
[test@test-server ~]$ curl --tlsv1.2 -u test:test https://example.test:5043/web3
curl: (35) Peer reports incompatible or unsupported protocol version.
[test@test-server ~]$ curl --tlsv1.3 -u test:test https://example.test:5043/web3
<h1>this is web3</h1>
注5 nginxにbasic認証を付ける
ドキュメントを参考にしました。
以下の記載で認証を実現しています。htpasswdファイルをあらかじめ用意しておきましょう。
location /web1 {
auth_basic_user_file /etc/nginx/.htpasswd;
auth_basic "basic ninnsyou";
コンテナ起動、疎通確認
それでは起動してみます。
docker-compose.yamlがあるディレクトリで行います。
$ docker-compose up -d
Creating network "reverse-proxy_ssl_default" with the default driver
Creating reverse-proxy_ssl_web1_1 ... done
Creating reverse-proxy_ssl_web3_1 ... done
Creating reverse-proxy_ssl_reverse-proxy_1 ... done
Creating reverse-proxy_ssl_web2_1 ... done
$ docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------------------------------------
reverse-proxy_ssl_reverse-proxy_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:5043->443/tcp, 80/tcp
reverse-proxy_ssl_web1_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:6043->80/tcp
reverse-proxy_ssl_web2_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:7043->80/tcp
reverse-proxy_ssl_web3_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:8043->80/tcp
問題なく起動していそうです。別ホストからcurlで確認してみましょう
$ curl --tlsv1.3 -u test:test https://example.test:5043/web1
<h1>this is web1</h1>
$ curl --tlsv1.3 -u test:test https://example.test:5043/web2
<h1>this is web2</h1>
$ curl --tlsv1.3 -u test:test https://example.test:5043/web3
<h1>this is web3</h1>
# -u basic認証を行う。ユーザとパスワードを指定
問題なさそうです。アクセスログも確認してみます。
(見やすくするために出力を並び替えています。)
$ docker-compose logs | grep curl
web1_1 | 172.27.0.1 - test [22/May/2021:07:14:19 +0000] "GET / HTTP/1.0" 200 22 "-" "curl/7.29.0" "<クライアントIP>"
web2_1 | 172.27.0.1 - test [22/May/2021:07:14:22 +0000] "GET / HTTP/1.0" 200 22 "-" "curl/7.29.0" "<クライアントIP>"
web3_1 | 172.27.0.1 - test [22/May/2021:07:07:12 +0000] "GET / HTTP/1.0" 200 22 "-" "curl/7.29.0" "<クライアントIP>"
reverse-proxy_1 | <クライアントIP> - test [22/May/2021:07:14:23 +0000] "GET /web3 HTTP/1.1" 200 22 "-" "curl/7.29.0"
うまくいっていますね!ちなみにアクセス元の172.27.0.1は前述したgatewayです。
確認は以下の様にできますが、説明については別の機会にしたいと思います。
$ docker network inspect reverse-proxy_ssl_default | jq ".[] | {IPAM}[].Config[].Gateway"
"172.27.0.1"
# reverse-proxy_ssl_defaultは今回のdocker-composeで作ったネットワークです。
最後に
以上となります。
docker-registryも無事に構築できるとうれしいです。
参考
- 全体的に参考にさせていただきました
https://qiita.com/zawawahoge/items/d58ab6b746625e8d4457 - dockerのhost.docker.internalについて参考にさせていただきました
https://qiita.com/skobaken/items/03a8b9d0e443745862ac - nginxでのSSL設定について参考にさせていただきました
https://qiita.com/tnoce/items/ded6d3d298da5972ab63!