前提
各種バージョン
$ docker.exe -v
Docker version 18.03.0-ce, build 0520e24302
$ docker-compose.exe -v
docker-compose version 1.20.1, build 5d8c71b2
$ docker-machine.exe ssh default 'docker -v'
Docker version 18.09.1, build 4c52b90
version: '3'
ホストのIP
192.168.99.100
10.0.2.15
- 他
-
172
始まりのIPは Docker が作成するので一旦無視する
-
docker@default:~$ ifconfig | grep "inet addr"
inet addr:172.19.0.1 Bcast:172.19.255.255 Mask:255.255.0.0
inet addr:172.17.0.1 Bcast:172.17.255.255 Mask:255.255.0.0
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
inet addr:192.168.99.100 Bcast:192.168.99.255 Mask:255.255.255.0
inet addr:127.0.0.1 Mask:255.0.0.0
対象プロトコル
- IP v4
- TCP
- Dockerのportsでは TCPとUDP の両方を指定できるが、今回は TCP のみを対象とする。
検証方法
nginx を使用して コンテナ内にHTTP(80番port)サーバーを動かす。
version: '3'
services:
nginx:
image: nginx:1.15
ports:
- "127.0.0.1:8080:80" # ここを変更していく
検証結果
1対1のport mapping
各ports指定の , は各URLへ curl
でアクセスできるかの結果
"<Host IP>:<Host Port>:<Container Port>"
"127.0.0.1:8080:80"
docker@default:~$ netstat -ant | grep -E "8080|State"
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN
"127.1.2.3:8080:80"
1
docker@default:~$ netstat -ant | grep -E "8080|State"
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.1.2.3:8080 0.0.0.0:* LISTEN
"192.168.99.100:8080:80"
ループバック 127.0.0.0/8
を指定した場合と違い、 192.168.99.0/24
ネットワークの他のホストからのアクセスを受け付けられるようになる。
※ Firewallなどで外からの通信が許可されている場合に限る2
docker@default:~$ netstat -ant | grep -E "8080|State"
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 192.168.99.100:8080 0.0.0.0:* LISTEN
"0.0.0.0:8080:80"
自ホスト宛の通信ならネットワーク・IPアドレスを問わず受け付けてコンテナに転送する
docker@default:~$ netstat -ant | grep -E "8080|State"
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 :::8080 :::* LISTEN
"8.8.8.8:8080:80"
3
ホストが持っていないIPを指定するとエラーとなりコンテナを作成できない
$ docker-compose.exe up -d
Removing dockernginx_nginx_1
Recreating 0ad48208ae60_dockernginx_nginx_1 ... error
ERROR: for 0ad48208ae60_dockernginx_nginx_1 Cannot start service nginx: driver failed programming external connectivity on endpoint dockernginx_nginx_1 (ed3d7ae26be69b038d3896e637a0163449fa524a93ddfe98a5673190e7519e06): Error starting userland proxy: listen tcp 8.8.8.8:8080: bind: cannot assign requested address
ERROR: for nginx Cannot start service nginx: driver failed programming external connectivity on endpoint dockernginx_nginx_1 (ed3d7ae26be69b038d3896e637a0163449fa524a93ddfe98a5673190e7519e06): Error starting userland proxy: listen tcp 8.8.8.8:8080: bind: cannot assign requested address
Encountered errors while bringing up the project.
"<Host Port>:<Container Port>"
(<Host IP>:
を省略した場合)
"8080:80"
-
<Host IP>
を0.0.0.0
とした場合("0.0.0.0:8080:80"
) と同じ
docker@default:~$ netstat -ant | grep -E "8080|State"
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 :::8080 :::* LISTEN
$ docker-compose port nginx 80
0.0.0.0:8080
"<Container Port>"
(<Host IP>:<Host Port>:
を省略した場合)
"80"
-
<Host IP>
:0.0.0.0
を指定したとみなされる("<Host Port>:<Container Port>"
指定のときと同じ) -
<Host Port>
: 使用可能なポート番号(エフェメラルポート)をDockerが選択- コンテナを作り直した際に同一Port番号となることは保証されていない
$ docker-compose up -d --force-recreate; docker-compose port nginx 80
Recreating dockernginx_nginx_1 ... done
0.0.0.0:32777
$ docker-compose up -d --force-recreate; docker-compose port nginx 80
Recreating dockernginx_nginx_1 ... done
0.0.0.0:32778
$ docker-compose up -d --force-recreate; docker-compose port nginx 80
Recreating dockernginx_nginx_1 ... done
0.0.0.0:32779
$ docker-compose up -d --force-recreate; docker-compose port nginx 80
Recreating dockernginx_nginx_1 ... done
0.0.0.0:32780
範囲(Range)指定
"8080-8082:80-82"
範囲内のIPの数が同じなら <Host Port>
と <Container Port>
が1対1対応する
0.0.0.0:8080->80
0.0.0.0:8081->81
0.0.0.0:8082->82
$ docker-compose ps
Name Command State Ports
---------------------------------------------------------------------------------------------------------------------
dockernginx_nginx_1 nginx -g daemon off; Up 0.0.0.0:8080->80/tcp, 0.0.0.0:8081->81/tcp, 0.0.0.0:8082->82/tcp
"8080-8082:80"
(<Host Port>
側だけ範囲指定)
<Host Port>
側の範囲(8080
, 8081
, 8082
)から使用可能なportをdockerが選択する。
<Host IP>:<Host Port>:
を省略した "<Container Port>"
指定の動きに近い4。
$ docker-compose up -d --force-recreate; docker-compose port nginx 80
Creating network "dockernginx_default" with the default driver
Creating dockernginx_nginx_1 ... done
0.0.0.0:8081
$ docker-compose up -d --force-recreate; docker-compose port nginx 80
Recreating dockernginx_nginx_1 ... done
0.0.0.0:8082
$ docker-compose up -d --force-recreate; docker-compose port nginx 80
Recreating dockernginx_nginx_1 ... done
0.0.0.0:8080
$ docker-compose up -d --force-recreate; docker-compose port nginx 80
Recreating dockernginx_nginx_1 ... done
0.0.0.0:8081
$ docker-compose up -d --force-recreate; docker-compose port nginx 80
Recreating dockernginx_nginx_1 ... done
0.0.0.0:8082
いつ使うか?(<Host Port>
側だけ範囲指定できることの嬉しさ)
--scale
オプションを指定して、(1種類のServiceで)2つ以上のコンテナを作成するとき。
portを1対1(例: "8080:80"
)で指定しているときに --scale
オプションを使用して2つ以上のコンテナを作成するとport重複によって1つしかコンテナを作成できない
$ docker-compose up -d --scale nginx=2
Creating network "dockernginx_default" with the default driver
The "nginx" service specifies a port on the host. If multiple containers for this service are created on a single host, the port will clash.
Creating dockernginx_nginx_1 ... error
Creating dockernginx_nginx_2 ... done
ERROR: for dockernginx_nginx_1 Cannot start service nginx: driver failed programming external connectivity on endpoint dockernginx_nginx_1 (8f55e9f086d4beea21daf076a731d998f6ec8440df4b28c99fb4f1a97272164d): Bind for 0.0.0.0:8080 failed: port is already allocated
ERROR: for nginx Cannot start service nginx: driver failed programming external connectivity on endpoint dockernginx_nginx_1 (8f55e9f086d4beea21daf076a731d998f6ec8440df4b28c99fb4f1a97272164d): Bind for 0.0.0.0:8080 failed: port is already allocated
Encountered errors while bringing up the project.
$ docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------
dockernginx_nginx_1 nginx -g daemon off; Exit 128
dockernginx_nginx_2 nginx -g daemon off; Up 0.0.0.0:8080->80/tcp
<Host Port>
側を範囲指定(例: "8080-8082:80"
)しておけば --scale
オプションを使用して2つ以上のコンテナを作成してもport重複が発生せずコンテナの作成が成功する。
$ docker-compose up -d --scale nginx=3
Creating network "dockernginx_default" with the default driver
The "nginx" service specifies a port on the host. If multiple containers for this service are created on a single host, the port will clash.
Creating dockernginx_nginx_1 ... done
Creating dockernginx_nginx_2 ... done
Creating dockernginx_nginx_3 ... done
$ docker-compose ps
Name Command State Ports
-------------------------------------------------------------------------
dockernginx_nginx_1 nginx -g daemon off; Up 0.0.0.0:8081->80/tcp
dockernginx_nginx_2 nginx -g daemon off; Up 0.0.0.0:8082->80/tcp
dockernginx_nginx_3 nginx -g daemon off; Up 0.0.0.0:8080->80/tcp
※ コンテナの番号とport番号の順序は一致するとは限らないらしい
- 1 -> 8081
- 2 -> 8082
- 3 -> 8080
ちなみに、範囲の長さより少ないscale数を指定することも可能5。
$ docker-compose up -d --scale nginx=2
Creating network "dockernginx_default" with the default driver
The "nginx" service specifies a port on the host. If multiple containers for this service are created on a single host, the port will clash.
Creating dockernginx_nginx_1 ... done
Creating dockernginx_nginx_2 ... done
$ docker-compose ps
Name Command State Ports
-------------------------------------------------------------------------
dockernginx_nginx_1 nginx -g daemon off; Up 0.0.0.0:8082->80/tcp
dockernginx_nginx_2 nginx -g daemon off; Up 0.0.0.0:8081->80/tcp
"8080:80-82"
コンテナ側の範囲の長さの方が多い指定は許されない
$ docker-compose up -d
The Compose file '.\docker-compose.yml' is invalid because:
services.nginx.ports is invalid: Port ranges don't match in length
"8080-8082:80-89"
同上。
$ docker-compose up -d
The Compose file '.\docker-compose.yml' is invalid because:
services.nginx.ports is invalid: Port ranges don't match in length
"8080-8089:80-82"
<Host Port>
と <Container Port>
の範囲の長さが異なる場合も許されない
$ docker-compose up -d
The Compose file '.\docker-compose.yml' is invalid because:
services.nginx.ports is invalid: Port ranges don't match in length
"80-82"
"<Container Port>" (<Host IP>:<Host Port>:を省略した場合) と同じく、コンテナ側の 80
, 81
, 82
をホスト側の空きportに適当に割り当てる
$ docker-compose up -d --force-recreate; docker-compose ps
Creating network "dockernginx_default" with the default driver
Creating dockernginx_nginx_1 ... done
Name Command State Ports
------------------------------------------------------------------------------------------------------------------------
dockernginx_nginx_1 nginx -g daemon off; Up 0.0.0.0:32814->80/tcp, 0.0.0.0:32813->81/tcp, 0.0.0.0:32812->82/tcp
$ docker-compose up -d --force-recreate; docker-compose ps
Recreating dockernginx_nginx_1 ... done
Name Command State Ports
------------------------------------------------------------------------------------------------------------------------
dockernginx_nginx_1 nginx -g daemon off; Up 0.0.0.0:32817->80/tcp, 0.0.0.0:32816->81/tcp, 0.0.0.0:32815->82/tcp
$ docker-compose up -d --force-recreate; docker-compose ps
Recreating dockernginx_nginx_1 ... done
Name Command State Ports
------------------------------------------------------------------------------------------------------------------------
dockernginx_nginx_1 nginx -g daemon off; Up 0.0.0.0:32820->80/tcp, 0.0.0.0:32819->81/tcp, 0.0.0.0:32818->82/tcp
$ docker-compose up -d --force-recreate; docker-compose ps
Recreating dockernginx_nginx_1 ... done
Name Command State Ports
------------------------------------------------------------------------------------------------------------------------
dockernginx_nginx_1 nginx -g daemon off; Up 0.0.0.0:32823->80/tcp, 0.0.0.0:32822->81/tcp, 0.0.0.0:32821->82/tcp
"80-80"
(範囲の始まりと終わりが同じ番号)
"80"
指定と同じ。
"127.0.0.1-5:8080:80"
<Host IP>
部分に範囲指定はできない
$ docker-compose up -d
The Compose file '.\docker-compose.yml' is invalid because:
services.nginx.ports is invalid: Invalid port "127.0.0.1-5:8080:80", should be [[remote_ip:]remote_port[-remote_port]:]port[/protocol]
"127.0.0.1-5:8080-8085:80"
同上
$ docker-compose up -d
The Compose file '.\docker-compose.yml' is invalid because:
services.nginx.ports is invalid: Invalid port "127.0.0.1-5:8080-8085:80", should be [[remote_ip:]remote_port[-remote_port]:]port[/protocol]
参考ページ
- Compose file version 3 reference | Docker Documentation
- Docker Composeのscaleオプションを使ったときのポートマッピング設定方法 - 理系学生日記
-
127始まり(第一オクテットが
127
)のIP(例:127.1.2.3
)も127.0.0.1
にように使える。port番号で区別しなくて良いので便利。 ↩ ↩2 ↩3 ↩4 ↩5 -
Windows(Docker Desktop for Windows) の場合、Windowsのファイアウォール設定上では
vpnkit
を許可すると別ホストからのアクセスが可能となる。Linuxの場合、Dockerはiptablesの設定を書き換えるため意図しない公開に注意(参考: Dockerでマストドンやってたら、遮断したはずのポートが丸見えだった件 | Divide et impera) ↩ -
8.8.8.8
はGoogleの所有するIPアドレス。Google Public DNS として公開されている。 ↩ -
"80"
指定は(Boot2Docker の TinyCoreLinuxの場合)"32768-60999:80"
指定と同じだと考えらられる ↩ -
逆に、port範囲の長さより多いscale数を指定したら、port重複でコンテナは(一部)作成されない
この場合、使われないport番号が生じる(どれが使われないかは不定)。 ↩