こんにちは!
seiです。
皆さん、Docker使ってますか?
Dockerでつまずくところと言えば通信ですよね。インフラエンジニアじゃない人にとっては通信の部分わかりずらい事この上ないと思います。
今回はコンテナから外部に通信する方法を紹介します。
ある程度Docker使ってきて知見が貯まったので備忘録です。
Dockerコンテナから外部のコンテナへアクセスする
外部のコンテナにアクセスする場合、以下2パターンがあると思います。
- 同じマシン(インスタンス)で起動している別のコンテナにアクセス
- 別のマシンで起動しているコンテナにアクセスする
同じマシンで起動している別のコンテナにアクセス
コンテナから他のコンテナへアクセスする場合は「Docker Network」を使うと良いです。
docker-compose.yamlファイルを使うと自動でDocker Networkが作成され、それぞれのコンテナは同じnetworkを使用します。
version: '3'
services:
web:
image: nginx:latest
ports:
- "80:80"
db:
image: postgres:latest
environment:
POSTGRES_DB: mydatabase
POSTGRES_USER: user
POSTGRES_PASSWORD: password
同一ネットワーク内にあるコンテナ同士は、IPアドレスを「サービス名」にすれば通信ができます。
この場合だと、バックエンドサービスからpostgreに通信する際は以下のホスト名の部分を「db」に置き換えれば通信ができます。
“postgres://user:password@ホスト名:5432/mydatabase”
また、使用するネットワークを明示することもできます。
ネットワークを命ずすることで、別々のdocker-compose.yamlファイルに記載しているコンテナ同士でも、サービス名による通信ができます。
ただしこの場合は、あらかじめdocker network createコマンドでネットワークを作成しておく必要があります。
version: '3'
services:
web:
image: nginx:latest
networks:
- my-external-network
networks:
my-external-network:
external: true
別のマシンで起動してるコンテナにアクセス
別のマシンで起動してるコンテナにアクセスしたい場合は、以下2つの方法があるかと思います。
- 接続先のインスタンスのIPとポートに対して通信する
- コンテナオーケストレーションツールを使用する
接続先のインスタンスのIPとポートに対して通信する
接続する側のインスタンスについて考えてみます。
この場合、単純に接続先のインスタンスに向かって通信を投げるだけです。
あたりまえですが、コンテナからの通信はホストインスタンスからの通信として扱われます。
例えば、パブリックIPが172.160.32.94のインスタンスで立ち上げているDockerコンテナから外部に通信するときは、172.160.32.94からの通信として扱われます。
なので、接続される側のインスタンスのfirewallはコンテナが稼働しているインスタンスのIPを許可すれば大丈夫です。
一方接続される側のインスタンスについて考えてみます。
接続される側のインスタンスでは、dockerコンテナのホストは0.0.0.0で立ち上げておかないと通信できません。
通信の流れは
外部からの通信が来る→ホストマシンに通る→ホストマシン上で動いているコンテナに通る
のようになっているので、ホストマシンからコンテナの通信でブロックされてしまいます。
コンテナ内でサーバをlocalhostで立ち上げた場合は、コンテナ内からの通信(コンテナ自身のIPからの通信)でしかアクセスできません。
ちなみに、ホストマシン側から見たコンテナのIPは、docker inspectコマンドで確かめることができます。このIPはコンテナ起動の度に変わります。
Dockerコンテナからホストマシンにアクセスする
Dockerコンテナからホストマシンで稼働しているサービスにアクセスしたい場合もあるかもしれません。
以前にdocker内部からホストマシンのIPを調べて通信したことがありますが、非常に使いずらかったです。
コンテナ新しく立てれば済む場合もあるので見直してみてください。
ホストマシンのIPアドレスを使う
コンテナ側から見たホストマシンのIPは172.17.0.1になる場合が多いようです。(Linux OS)
固定する方法はなさそうなので、毎回調べる必要があります。
ネットワーク設定を以下コマンドで出力できます。
ip route
–network=”host”を使う
コンテナを起動するときに –network=”host”を使うと、コンテナがホストのネットワークを共有するようになります。
マシン自体がコンテナになるイメージですね。マシンのリソースを節約したい場合に使うと良いが、セキュリティリスクがあるので十分注意して行うべきと公式サイトに記載があります。
これでlocalhostでホストにアクセスすることができます。
docker-compose.yamlファイルでは以下のように記載します。
version: '3'
services:
my-service:
image: my-image:latest
network_mode: "host"
まとめ
Dockerは従来の仮想マシンと違って、軽くてめちゃめちゃ気に入ってます。
特にvscodeの拡張機能の「dev-container」だとコンテナ内tに直接入って開発できるので、local開発での仮想マシンと同じような使い方が可能です!
コンテナ内に入ってからgitを使おうとすると、少し使いにくいのが残念ですが、まだ使ったことがない方はぜひ使ってみて下さい!