初めてDockerを扱うエンジニアを見てるとDockerポート周りで悩んでいる人を見かけます。別に難しい事はないのですが確かに紛らわしい事もありますのでまとめました。
結局ポートの問題とは、公開されない
と意図せず公開されちゃう
に帰着されます。つまりこんな感じ・・・
- Dockerfile内でEXPOSEしたのに公開されない
- ufwで閉じたはずなんだけどアクセスできちゃう
- docker-compose でlinkしてないのに…
- 起動時にデータベースにアクセスできない
思いついた順に簡単にまとめました。
Dockerfile内でEXPOSEしたのに公開されない
DockerfileでEXPOSE
宣言しただけだとポートの解放は行われません。ついでにいうと、EXPOSEはイメージに書かれる単なるコメントなので、本当に何もしません。
EXPOSEを書くと、以下のようにinspectすることでportを得られます。
$ docker inspect <image> -f "{{ .Config.ExposedPorts }}"
map[4567/tcp:{}]
ただこれだけです。もうEXPOSE
のことは忘れていいと思います…EXPOSE
を書いても書かなくても次の-p
オプションをつければ公開されるし、つけなければ公開されません。
ポート全公開オプション-P(大文字)
の挙動には作用するようだけどどっちみち使わないよね?!
-p
オプション
ポートを公開する必要のあるコンテナの起動には必ず-p
オプションが必要です。
docker run nginx
ではポートは公開されないので以下のようにします。
docker run -p 127.0.0.1:80:80 nginx
省略時公開範囲に注意
ついでに書いておくと、ポートオプション127.0.0.1:80:80
の部分、コロン(:)が3つつきますが公開するIPアドレス:公開するポート:コンテナのポート
の順番です。最初の公開するIPアドレス:
の部分は省略することができ、そのときは0.0.0.0:
つまりホストのすべてのインターフェイスに対して公開となります。
ここで注意してほしいのは「公開するIPアドレス:
の部分を省略する」ということはホスト外からのアクセスが来る可能性があるということです。「省略→公開」の設定になりますのでご注意して下さい。ローカルで試すなら、127.0.0.1:80:80のように使うべきですし、公開サービスならtraefikなどのルータを介してアクセスするべきだと思います。ここら辺の具体的な方法は以前の記事1つのサーバにたくさんのWebサービスを詰め込む方法
を参考にしてください。
ufwで閉じたはずなんだけどアクセスできちゃう
ufwはUbuntuで利用される、iptablesのフロントエンドです。簡単な操作でパケットフィルタリングができるため愛用者は多いのではないでしょうか?ただし、ufwとDocker併用するのは注意が必要です。Dockerはufwよりも優先度の高い方法(Chain)でポートの開放を行います。なので、ufwでDockerコンテナへのパケットフィルタリングができるとは思わない方がいいでしょう。これを回避する方法 もありますが、副作用があるのでおすすめされていません。
前項と合わせると、ufwで閉じているおもって-p
オプションで公開するIPアドレス:
を省略するとと実は公開されていたなんてことがあり得ますので注意です。
docker-compose でlinkしてないコンテナにつながる
例えば以下のようなdocker-composeのサービスで
docker-compose.yml
version: '3'
services:
app:
image: ruby:3.0
links:
- redis
command: ping -i
redis:
image: redis:3.2
links
は以前のDockerではサービス内のコンテナ間接続制御に使われていましたが、今は起動順にしか関係しません。なので、linksの部分を削除してもネットワーク的につながります。
$ docker-compose exec app ping redis [17:26:38]
PING redis (172.18.0.3) 56(84) bytes of data.
64 bytes from a_redis_1.a_default (172.18.0.3): icmp_seq=1 ttl=64 time=0.143 ms
64 bytes from a_redis_1.a_default (172.18.0.3): icmp_seq=2 ttl=64 time=0.189 ms
64 bytes from a_redis_1.a_default (172.18.0.3): icmp_seq=3 ttl=64 time=0.113 ms
^C
--- redis ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 14ms
rtt min/avg/max/mdev = 0.113/0.148/0.189/0.032 ms
docker-compose でサービス起動時にデータベースにアクセスできない
docker-composeはlinks
オプションで起動順しか管理しませんので、前項の例にあるようなapp
が起動したときには依存するredis
はまだ起動中かもしれません。このようなときにはdockerlize
のような仕組みを使って依存サービスの起動を待つ必要があります。詳しい解説がありましたので、そちらに譲ります。
以上駆け足で4点説明してきました。他にもはまりどころなどありましたらコメント欄でご指摘いただければと思います。