🐷

Dockerのネットワークの仕組みをちょっとだけ理解する

に公開

今回はDockerの基礎的な話です。

背景

踏み台サーバーを通して外部システムに接続をする必要がある機能をローカル環境で実装をしている際に、ローカルPC上では接続できるのにDocker上にあるアプリ経由だと接続ができない、といったことが起きました。
「そういえばアプリケーションはDocker上で動かしてるから、ホストで踏み台にアクセスしてもアプリケーション上では接続できないジャン( ◠‿◠ )」
ということは分かったのですが、なぜそうなるのかをうまく説明できるほど理解できていなかったので、改めて調べることにしました。

起きたこと

下記の手順を実行して、外部システムに接続できないということが起きました。

  • ローカルホストで踏み台サーバー経由で外部システムに接続
    • ssh -NL 3000:external-system:80 bastion
      - ブラウザで外部システムにアクセスできることを確認
    • http://127.0.0.1:3000/にアクセス
  • アプリケーション内で外部システムに接続
    • $this->connection = new Client(['base_uri' => 'http://127.0.0.1:3000/']);

アプリケーション内でのhttp://127.0.0.1は、起動しているDockerコンテナ自身のサービスを指します。
そのため、http://127.0.0.1:3000/では外部システムに接続することができませんでした。

Docker内のネットワークの状態

Dockerのネットワーク、基礎理解は万全ですか?【Dockerコンテナ・グレートジャーニー④】という記事が分かりやすかったので、以下画像をお借りします。
http://127.0.0.1:8080でDocker上のサーバーにアクセスできる仕組みを解説しています。

Docker内でひとつのネットワークが作成されているようです。
Dockerには複数のネットワークが複数できるみたいなので、docker network lsを実行して、どんなネットワークがあるかを見てみます。

NETWORK ID     NAME          DRIVER    SCOPE
a450ae757a4e   bridge        bridge    local
533460490ca7   host          host      local
cb9debf60dec   none          null      local
5a410953ff96   my-app_default   bridge    local

開発しているアプリケーションは、my-app_defaultというネットワーク内で動いているようでした。

解決策

http://127.0.0.1ではなく、http://host.docker.internal:3000/で接続したら、外部システムに接続することができました!

ただしこれはあくまで開発環境向けであって、Docker Desktop forMac 以外の環境では動きません🙅‍♀️ので、ご注意を

補足

docker-composeでコンテナを作成した場合、networksセクションの記載がない場合は自動でネットワークを作成してくれます。
自動で作成された場合、ネットワークの名前は{docker-compose.ymlファイルが置かれているディレクトリ名}_defaultになります。

感想

Dockerの理解が浅いので、いろいろ触って学んでいきたい気持ちがあったりなかったりします。
こちらの記事が分かりやすくてよかったです。
仮想化を知るには、仮想化ではないとは何かを知るべきだ【Dockerコンテナ・グレートジャーニー①】

参考

Discussion