EXPOSE 是声明不是发布
EXPOSE 声明镜像内应用监听的端口,本质是元数据:它让使用者与工具知道镜像期望对外提供哪些端口,并作为 docker run -P 随机发布端口的依据。它本身不监听端口、不做映射、也不改动任何防火墙,真正让外部访问到的动作仍然由 -p 或编排里的端口配置决定。
基本信息
| 语法 | EXPOSE 80 443/tcp 53/udp,不写协议时默认 tcp |
|---|---|
| 性质 | 纯元数据声明,不监听、不映射、不改动防火墙 |
| 与 -P 联动 | docker run -P 会按 EXPOSE 声明把端口随机发布到宿主高位端口 |
| 内省方式 | docker inspect -f '{{.Config.ExposedPorts}}' 镜像 |
| 编排差异 | 编排里声明的容器端口同样只是声明,可达性由 Service 与网络插件决定 |
| 常见误解 | EXPOSE 之后仍需 -p 才能从宿主外部访问 |
四层才决定能访问
| 层级 | 作用 | 不配置的后果 |
|---|---|---|
| EXPOSE | 镜像元数据声明 | 不影响可达性,只是缺少说明文档 |
| -p 或编排端口 | 建立宿主到容器的端口映射 | 容器外完全访问不到 |
| 云安全组与主机防火墙 | 放行宿主对外端口 | 宿主机之外仍被拦住 |
| 进程实际监听 | 决定端口是否真的在监听 | 声明了但进程没监听,连接被拒 |
典型使用场景
- 让使用者一眼看出镜像提供哪些端口,减少沟通成本
- 配合 -P 做快速试验,随机映射到宿主端口避免冲突
- 作为编排与部署文档的一部分,与 Service 配置保持一致
- 端口冲突排查时对照声明的端口与实际映射
- 多协议场景显式声明 tcp 与 udp,避免只放行一半
示例
示例
EXPOSE 8080 # 声明应用监听端口,仅作为元数据
EXPOSE 53/udp # 声明 udp 端口时必须显式写协议
# 真正的发布发生在运行阶段
docker run -p 8080:8080 myapp # 映射到宿主端口
docker run -P myapp # 按 EXPOSE 声明随机发布
docker inspect -f '{{.Config.ExposedPorts}}' myapp:1.0.0 # 查看声明结果「EXPOSE 了却访问不了」是正常现象:要对外必须再加端口映射。反过来也一样,映射做了但云安全组没放开,宿主之外依然不通,四个条件要同时成立。
不要把 EXPOSE 当成访问控制手段:它不限制任何流量,也不会缩小攻击面。把不该暴露的端口写进声明,反而会误导使用者与自动化工具去发布它。