最近、Go
とTypeScript
を使って個人開発しているときに、Goのサーバーが立たないということがありました。
色々調べても中々分からず結構手こずってしまい、友達に聞いたところ3分くらいで解決しました。
そこで言われたのが、Docker ポートフォワーディングで調べてみてって言われて調べたら解決したので、今回はそれを記事にしようと思います。
Dockerのポートフォワーディングとは
まず、docker-compose.yml
ファイルを見てみましょう。
version: '3.9'
services:
backend:
build:
context: .
dockerfile: ./docker/backend/app/Dockerfile
tty: true
volumes:
- type: bind
source: ./backend
target: /api
ports:
- "8080:8080"
その原因の部分が、
ports:
- "8080:8080"
このポート番号が「:」で右と左に分かれています。
この記号を使うことで、コンテナのポート番号と、ローカルのポート番号を紐づけることができます。
右がコンテナのポート番号で左がホスト(あなた自身のパソコン)のポート番号です。
今回go run main.go
を叩くと、ポート番号3000
が呼ばれていたので、アクセスできなかったんですね。
アクセスできるようにするには、
ports:
- "3000:8080"
ここで少し公式ドキュメントを見てみると、このように書いてありました。
デフォルトの Docker コンテナは外の世界と通信できます。しかし、外の世界からはコンテナに接続できません。
公式ドキュメント
つまり、ブラウザからコンテナのポート番号にアクセスしようとしてもアクセスできないということが公式ドキュメントにも書いてありましたね。
Dockerのネットワークを調べてみる
ネットワークドライバー
Docker
ではネットワークの扱いが重要で、Docker
のコンテナ内ではコンテナで1つのプロセスだけを動かすのが定石です。
つまり、1つのコンテナにGo
とUbuntu
を動かすといったことはあまりしない方がいいんですね。
1つのコンテナにつき、1つのプロセスで構成し、それぞれで通信をするのがいいんですね。
以下の画像のような感じです。
(入門 Dockerより引用)
そのネットワークを構成するものとして代表的なものが2つあります。
それが、bridgeとhostです。
bridge
Docker
のネットワークを構成する上で、デフォルトがbridge
です。
何も指定しなければ、ネットワークを構成するものとして、ブリッジが採用されます。
ブリッジは、簡単にいうと、次にどこにいくかを指示してくれる機械です。(厳密には違いますが、ここでは気にしないこととします)
ブリッジを使うことで、コンテナ間で通信をしてくれるわけですね。
実際に見てみましょう。
以下のようなコマンドを叩くことで、docker
のネットワークにブリッジがあることがわかります。
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
47ddb51d32a4 bridge bridge local
d7d8e86102f6 host host local
ca24a558faf1 none null local
bridge
があることが確認できました。
host
host
ネットワークは、そのホスト(あなた自身のPC)の構成と同じで、コンテナとホストで使用できるポートを共有します。つまり、
コンテナとローカルのネットワーク分離は行われないため、性能は向上します。
ですが、現在ホストPCのOSがLinux
の時にしか、このネットワークは使えないんです。
Docker Desktop for Mac
、Docker Desktop for Windows
、Docker EE for Windows Server
では使えないんですね。
その根拠が公式ドキュメントで書かれています。
ホストネットワークにおけるドライバーは Linux ホスト上においてのみ動作します。 Docker Desktop for Mac、Docker Desktop for Windows、Docker EE for Windows Server ではサポートされていません。
このような経緯があるから、docker network
のデフォルトにはブリッジが採用されているのかもしれませんね。
【参考資料】