docker psのPORTSの見方

docker psのPORTS部分が、

5432/tcp

だったり

0.0.0.0:80->80/tcp

となっていたり違いが分からなかったので調べてみた。

#sudo docker ps -a
CONTAINER ID        IMAGE                                  COMMAND                  CREATED          STATUS          PORTS               NAMES
f582ab60c43c        postgres:10.14                         "docker-entrypoint.s…"   27 minutes ago   Up 27 minutes   5432/tcp            some-postgres
6177204c8be3        zabbix/zabbix-web-nginx-mysql:latest   "docker-entrypoint.sh"   9 days ago       Up 27 minutes   0.0.0.0:80->80/tcp  zabbix-web-nginx-mysql

docker inspectで調べてみると下のようになっている。

# sudo docker inspect some-postgres | less
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"ExposedPorts": {
 "5432/tcp": {}
},
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"NetworkSettings": {
 "Bridge": "",
 "SandboxID": "cdf8021dbbc819351ffdcb21cf0a025203e6b2432492aeb9d8aec39f6f0bea21",
 "HairpinMode": false,
 "LinkLocalIPv6Address": "",
 "LinkLocalIPv6PrefixLen": 0,
 "Ports": {
 "5432/tcp": null
},
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Dockerfile referenceによると

The EXPOSE instruction informs Docker that the container listens on the specified network ports at runtime. You can specify whether the port listens on TCP or UDP, and the default is TCP if the protocol is not specified.The EXPOSE instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published. To actually publish the port when running the container, use the -p flag on docker run to publish and map one or more ports, or the -P flag to publish all exposed ports and map them to high-order ports.

google翻訳すると

EXPOSE命令は、コンテナーが実行時に指定されたネットワークポートでリッスンすることをDockerに通知します。ポートがTCPとUDPのどちらでリッスンするかを指定でき、プロトコルが指定されていない場合、デフォルトはTCPです。EXPOSE命令は実際にはポートを公開しません。これは、イメージを作成する人とコンテナーを実行する人の間の一種のドキュメントとして機能し、ポートの公開が意図されています。コンテナーの実行時に実際にポートを公開するには、docker runで-pフラグを使用して1つ以上のポートを公開およびマップするか、-Pフラグを使用して公開されたすべてのポートを公開して上位ポートにマップします。

となっているので、どうやら5432/tcpとなっているExposedPortsの部分は、実際にポートを公開しているわけではないので外部からコンテナのこのポート(5432/tcp)には接続はできず、人間が判断しやすいように見せているだけであると。

で、コンテナとして実際にポートを公開し外部からこのポート(5432/tcp)に繋げたい場合は-pを使って

docker run -p 5432:5432/tcp ・・・・・

のようにコンテナ作成時にポート公開するようにしろということらしい。するとdocker inspectは下のようになり

# sudo docker inspect some-postgres | less
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"ExposedPorts": {
 "5432/tcp": {}
},
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"NetworkSettings": {
 "Bridge": "",
 "SandboxID": "cdf8021dbbc819351ffdcb21cf0a025203e6b2432492aeb9d8aec39f6f0bea21",
 "HairpinMode": false,
 "LinkLocalIPv6Address": "",
 "LinkLocalIPv6PrefixLen": 0,
 "Ports": {
   "5432/tcp": [
    {
       "HostIp": "0.0.0.0",
       "HostPort": "5432"
    }
  ]
},
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

docker paもPORTS部分が「0.0.0.0:5432->5432/tcp」となり外部から5432ポートへ接続出来るようになる。

# sudo docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
2d2080585c4e        postgres:10.14      "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes        0.0.0.0:5432->5432/tcp   some-postgres