連不上容器的四個原因與 -p 的方向

「容器明明跑起來了,瀏覽器卻連不上」是初學第一名的卡關點。因為 network namespace 的關係,容器的 port 80 跟主機的 port 80 是兩個完全不同的東西

port 指的是 TCP port,就是平常講的 80 port、443 port——同一個 IP 上用來區分不同服務的號碼。容器有自己的 network namespace,等於有自己一整套 port 空間。)

口訣:-p 主機:容器

左邊自由選,右邊必須是容器裡程式真的在聽的 port(由 image 決定)。

docker run -d -p 8080:80 --name web nginx:1.25-alpine
docker port web        # 查某個容器的 port 對應

照順序檢查

  1. 忘了加 -pdocker ps 的 PORTS 欄要有 0.0.0.0:8080->80/tcp 這種帶箭頭的字樣,沒箭頭就是沒轉發
  2. 右邊那個 port 寫錯 — 寫 -p 8080:8080 但 nginx 聽的是 80。查法:Docker Hub 說明或 docker inspectExposedPorts
  3. 主機 port 被佔用bind: address already in use,用 lsof -i :8080 找佔用者
  4. 容器裡的程式只聽 127.0.0.1 — 最陰險的一種。app.listen(3000, '127.0.0.1') 只接受容器內部連線,外面轉發進來的封包被拒。容器裡的服務一定要聽 0.0.0.0

EXPOSE 不會開 port

Dockerfile 的 EXPOSE 3000 只是文件,宣告給讀的人和工具看,要真的連得到還是得 -p(唯一例外是 docker run -P 大寫,自動把所有 EXPOSE 的 port 隨機對應到主機)。

⚠️ 容器之間互連不需要 -p容器之間要用容器名稱連線而不是 localhost