7.9 EXPOSE 暴露連接埠
7.9.1 基本語法
EXPOSE <連接埠> [<連接埠>/<協定>...]
EXPOSE 宣告容器執行時提供服務的連接埠。這是一個 文件性質的宣告,告訴使用者容器會監聽哪些連接埠。
7.9.2 基本用法
## 宣告單個連接埠
EXPOSE 80
## 宣告多個連接埠
EXPOSE 80 443
## 宣告 TCP 和 UDP 連接埠
EXPOSE 80/tcp
EXPOSE 53/udp
7.9.3 EXPOSE 的作用
1. 文件說明
告訴映象使用者,容器將在哪些連接埠提供服務:
## 使用者一看就知道這是 web 應用
EXPOSE 80 443
## 檢視映象暴露的連接埠
$ docker inspect nginx --format '{{.Config.ExposedPorts}}'
map[80/tcp:{}]
2. 配合 -P 使用
使用 docker run -P 時,Docker 會自動對映 EXPOSE 的連接埠到宿主機隨機連接埠:
## Dockerfile
EXPOSE 80
$ docker run -P nginx
$ docker port $(docker ps -q)
80/tcp -> 0.0.0.0:32768
7.9.4 EXPOSE vs -p
| 屬性 | EXPOSE | -p |
|---|---|---|
| 位置 | Dockerfile | docker run 指令 |
| 作用 | 宣告/文件 | 實際連接埠對映 |
| 是否必需 | 否 | 是 (外部訪問時) |
| 對映發生時 | 不發生 | 執行時發生 |
flowchart TD
Expose["EXPOSE 80
僅宣告意圖"] Run["docker run -p
實際連接埠對映
宿主機 ←→ 容器"] Expose ~~~ Run
僅宣告意圖"] Run["docker run -p
實際連接埠對映
宿主機 ←→ 容器"] Expose ~~~ Run
沒有 EXPOSE 也能 -p
## 即使沒有 EXPOSE,也可以使用 -p
FROM nginx
## 沒有 EXPOSE
...
## 仍然可以對映連接埠
$ docker run -p 8080:80 mynginx
7.9.5 常見誤解
誤解:EXPOSE 會開啟連接埠
## ❌ 錯誤理解:這不會讓容器可從外部訪問
EXPOSE 80
EXPOSE 不會:
- 自動進行連接埠對映
- 讓服務可從外部訪問
- 在容器啟動時開啟連接埠監聽
EXPOSE 只是元資料宣告。容器是否實際監聽該連接埠,取決於容器內的應用。
正確理解
## Dockerfile
FROM nginx
EXPOSE 80 # 1. 宣告:這個容器會在 80 連接埠提供服務
## 執行:需要 -p 才能從外部訪問
$ docker run -p 8080:80 nginx # 2. 對映:宿主機 8080 → 容器 80
7.9.6 最佳實踐
1. 總是宣告應用使用的連接埠
## Web 服務
FROM nginx
EXPOSE 80 443
## 資料庫
FROM postgres
EXPOSE 5432
## Redis
FROM redis
EXPOSE 6379
2. 使用明確的協定
## 預設是 TCP
EXPOSE 80
## 明確指定 UDP
EXPOSE 53/udp
## 同時支援 TCP 和 UDP
EXPOSE 53/tcp 53/udp
3. 與應用實際連接埠保持一致
## ✅ 好:EXPOSE 與應用連接埠一致
ENV PORT=3000
EXPOSE 3000
CMD ["node", "server.js"]
## ❌ 差:EXPOSE 與應用連接埠不一致(誤導)
EXPOSE 80
CMD ["node", "server.js"] # 實際監聽 3000
7.9.7 使用環境變數
ARG PORT=80
EXPOSE $PORT
7.9.8 在 Compose 中
在 Compose 中設定如下:
services:
web:
build: .
ports:
- "8080:80" # 對映連接埠(類似 -p)
expose:
- "80" # 僅宣告(類似 EXPOSE)
expose 在 Compose 中僅用於容器間通訊的文件說明,不進行連接埠對映。