docker-compose 中 ports 和 expose 有什么区别?
ports 把容器端口发布到宿主机(外部可访问),expose 仅在 compose 内部网络向其他服务开放端口(不对外)。内部依赖用 expose,对外服务用 ports。
一句话区别:ports 会把端口发布到宿主机**(宿主机端口:容器端口,外部网络可达);expose 只在 compose 服务间网络内开放端口,宿主机和外部都访问不到。数据库这类只供内部服务连的用 expose,需要浏览器/外部访问的才用 ports。**
ports:对外发布
services:
mysql:
image: mysql:8
ports:
- "3306" # 容器 3306 → 宿主机随机端口
docker compose ps 会看到 0.0.0.0:32769->3306/tcp——宿主机的 32769 被映射过去,局域网里任何人都能连。固定端口写法 "3306:3306"。
expose:仅内部可见
services:
mysql:
image: mysql:8
expose:
- "3306" # 只有同一 compose 网络里的服务能访问
app:
image: myapp
# app 里用 mysql:3306 连接
app 服务通过服务名 mysql:3306 正常连接;宿主机上 curl localhost:3306 不通。
一个常见误解
其实同一 compose 文件里的服务本来就能互相访问任意容器端口(通过内部 DNS 和服务名),expose 更多是文档性声明+与老版 link 语义的兼容。真正的边界是:
- 要不要从宿主机/外部访问?要 →
ports - 只在服务间访问 → 什么都不写也行,写
expose表明意图
安全建议
- 数据库、Redis、消息队列默认不要用 ports 暴露到宿主机,尤其宿主机有公网 IP 时
- 调试期临时需要,可用
"127.0.0.1:3306:3306"只绑定回环地址
观测云对照
内部服务的可观测一样不能少。 不对外暴露的数据库、缓存,DataKit 照样能在宿主机层面采集其指标与日志,慢查询、连接数异常通过监控器告警——端口不开放不等于状态不可见。
常见问题(FAQ)
Q:ports 写 "3306" 和 "3306:3306" 有什么区别?
A:前者宿主端口随机分配(每次启动可能变),后者固定映射到宿主 3306。
Q:expose 会影响容器间通信吗?
A:不会限制——即使不写 expose,同网络服务也能访问容器所有端口;它主要起声明作用。
Q:生产环境数据库该暴露 ports 吗?
A:不该。只留应用服务的端口,数据层全部走内部网络。