Docker Compose配置疑问:仅暴露指定容器端口,阻止其他端口被主机访问
问题分析与解决方案
你遇到的问题核心是对Docker网络模型和expose指令的作用理解有一点偏差,咱们一步步拆解:
1. 先澄清expose和ports的真实作用
你查到的定义基本没错,但有个关键细节被忽略了:
ports:主动将容器端口映射到主机的网卡接口(包括主机的本地IP和公网IP),允许外部设备(非Docker网络内的设备)通过主机IP访问容器服务。expose:这本质上是一个文档性的声明,主要作用是告诉其他开发者这个容器服务使用了哪个端口,同时Docker Compose会自动将这些端口信息注入到关联服务的环境变量中(比如APP_PORT_8080_TCP)。它完全不具备网络访问控制的能力——容器的端口是否能被访问,取决于服务的监听地址和网络的连通性。
2. 为什么主机能访问10.0.0.7:8080?
你的custom-net是一个普通的Docker Bridge网络,这种网络的特性是:
- 主机和容器之间是直接连通的,Docker会自动在主机上配置路由规则,让主机可以直接访问容器的IP。
- 你的
app容器内的服务应该是监听在0.0.0.0:8080(这是大多数应用的默认配置),而不是仅监听容器内部的127.0.0.1。这意味着只要能连通容器IP,就能访问这个端口——而主机刚好能连通10.0.0.7,所以扫描会显示端口开放。
3. 实现需求的解决方案:隔离容器网络
要实现「仅让web_server能访问app的8080端口,主机无法访问」,最优雅的方式是使用内部专用网络:
修改后的docker-compose.yml
version: "3.9" services: app: image: sandbox/app container_name: app volumes: - ./src/app:/app/ restart: unless-stopped networks: - internal-net # 仅加入内部专用网络 web_server: image: nginx:latest container_name: proxy ports: - "80:80" networks: - internal-net # 和app服务通信 - external-net # 对外提供web服务 networks: internal-net: internal: true # 标记为内部网络,主机无法直接访问其中的容器 driver: bridge external-net: driver: bridge
配置说明
internal-net设置了internal: true,这个网络内的容器只能和同网络的容器通信,主机无法直接访问这些容器的IP和端口,彻底隔离了主机对app服务的访问。web_server同时加入两个网络:通过internal-net以服务名(app:8080)访问app的8080端口,通过external-net对外暴露80端口给主机和外部设备。- 不需要给容器指定固定IP,Docker会自动分配网络内的IP,且服务名访问更稳定可靠。
这样调整后,你再用nmap扫描主机,就只能看到web_server的80端口开放,app的8080端口会完全不可达。
内容的提问来源于stack exchange,提问作者DustInTheSilence
相关产品推荐
相关产品推荐

