一、需求背景
某项目组采用容器化部署架构,通过docker-compose
对服务进行编排管理。为确保核心服务安全性,需对以下三个暴露的宿主机端口实施IP白名单访问控制:
服务名称 | 宿主机IP | 宿主机端口 | 容器内部端口 |
---|---|---|---|
apollo-configservice | 172.22.33.204 | 10002 | 8080 |
apollo-adminservice | 172.22.33.204 | 10003 | 8090 |
apollo-portal | 172.22.33.204 | 10004 | 8070 |
-
允许访问的IP白名单地址 172.16.200.200,允许访问apollo 全资源
-
apollo docker-compose 文件
version: '3'
services:
apollo-configservice:
container_name: apollo-configservice
image: docker.cnb.cool/srebro/apollo:apollo-configservice-2.3.0
volumes:
- ./logs:/opt/logs
- /etc/localtime:/etc/localtime:ro
ports:
- "10002:8080"
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://172.22.33.201:3306/ApolloConfigDB?characterEncoding=utf8
- SPRING_DATASOURCE_USERNAME=srebro
- SPRING_DATASOURCE_PASSWORD=srebro@2025
- EUREKA_INSTANCE_HOME_PAGE_URL=http://172.22.33.204:10002
- EUREKA_INSTANCE_IP_ADDRESS=172.22.33.204
- TZ=Asia/Shanghai
restart: always
networks:
- srebroapollo-adminservice: depends_on: - apollo-configservice container_name: apollo-adminservice image: docker.cnb.cool/srebro/apollo:apollo-adminservice-2.3.0 volumes: - ./logs:/opt/logs - /etc/localtime:/etc/localtime:ro ports: - "10003:8090" environment: - SPRING_DATASOURCE_URL=jdbc:mysql://172.22.33.201:3306/ApolloConfigDB?characterEncoding=utf8 - SPRING_DATASOURCE_USERNAME=srebro - SPRING_DATASOURCE_PASSWORD=srebro@2025 - EUREKA_INSTANCE_HOME_PAGE_URL=http://172.22.33.204:10003 - EUREKA_INSTANCE_IP_ADDRESS=172.22.33.204 - TZ=Asia/Shanghai restart: always networks: - srebro apollo-portal: depends_on: - apollo-adminservice container_name: apollo-portal image: docker.cnb.cool/srebro/apollo:apollo-portal-2.3.0 volumes: - ./logs:/opt/logs - /etc/localtime:/etc/localtime:ro ports: - "10004:8070" environment: - SPRING_DATASOURCE_URL=jdbc:mysql://172.22.33.201:3306/ApolloPortalDB?characterEncoding=utf8 - SPRING_DATASOURCE_USERNAME=srebro - SPRING_DATASOURCE_PASSWORD=srebro@2025 - APOLLO_PORTAL_ENVS=baseline - baseline_META=http://172.22.33.204:10002 - TZ=Asia/Shanghai restart: always networks: - srebro
networks:
srebro:
external: true
二、分析
- 🚫 使用iptables的方式进行限制。
- 配置后的策略需要持久化,系统或者容器重启后 策略还在。
- 查看docker 官方文档,有关于Docker 为网桥网络创建
iptables
规则的说明 - 默认情况下,允许所有外部源 IP 连接到已发布到 Docker 主机地址的端口;要仅允许特定 IP 或网络访问容器,需要在 DOCKER-USER 过滤器链的顶部插入一条否定规则。
- 以下规则会丢弃来自除 192.0.2.2 之外的所有 IP 地址的数据包。被这些自定义链中的规则接受或拒绝的数据包将不会被附加到 FORWARD 链的用户定义规则看到。因此,要添加其他规则来筛选这些数据包,使用 DOCKER-USER 链。

三、实现方式
只允许17216.200.200 访问apollo 暴露在宿主机上的 10002,10003,10004 端口
配置iptables 策略
- ⚠️ 需要注意 ,--dport 指的是容器的端口,而不是宿主机的映射后的端口,网上查看很多资料都是写的宿主机的端口都是不对的,这边只在docker 的论坛看到一个关于
--dport
的说明

正确配置方式(推荐两种方法):
iptables -I 是插入到链的最前面 ,确保每个端口的 ACCEPT 规则在 DROP 规则之前。
方法一:为每个端口单独设置规则(清晰直观)
# 先添加拒绝规则
iptables -I DOCKER-USER -p tcp --dport 8080 -j DROP
iptables -I DOCKER-USER -p tcp --dport 8090 -j DROP
iptables -I DOCKER-USER -p tcp --dport 8070 -j DROP
# 再添加允许规则(它们会被插入到链的顶部)
iptables -I DOCKER-USER -p tcp --dport 8080 -s 172.16.200.200 -j ACCEPT
iptables -I DOCKER-USER -p tcp --dport 8090 -s 172.16.200.200 -j ACCEPT
iptables -I DOCKER-USER -p tcp --dport 8070 -s 172.16.200.200 -j ACCEPT
方法二:使用 multiport
模块合并规则(更高效)
# 先添加拒绝规则
iptables -I DOCKER-USER -p tcp -m multiport --dports 8080,8090,8070 -j DROP
# 再添加允许规则(它会被插入到链的顶部)
iptables -I DOCKER-USER -p tcp -s 172.16.200.200 -m multiport --dports 8080,8090,8070 -j ACCEPT
验证规则顺序
执行以下命令检查规则顺序,确保 ACCEPT 规则在 DROP 规则之上:
[root@localhost apollo]# iptables -L DOCKER-USER -n --line-numbers
Chain DOCKER-USER (1 references)
num target prot opt source destination
1 ACCEPT tcp -- 172.16.200.200 0.0.0.0/0 tcp dpt:8080
2 ACCEPT tcp -- 172.16.200.200 0.0.0.0/0 tcp dpt:8090
3 ACCEPT tcp -- 172.16.200.200 0.0.0.0/0 tcp dpt:8070
4 DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080
5 DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8090
6 DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8070
7 RETURN all -- 0.0.0.0/0 0.0.0.0/0
访问测试

iptables 规则持久化保存
[root@localhost apollo]# service iptables save
iptables: Saving firewall rules to /etc/sysconfig/iptables: [ OK ]
四、其他
docker 多容器端口相同,怎么限制?
上面的案例,阐述的是,docker 容器里的端口分别是不同的端口,如果我们容器内的端口都是8080,那应该怎么限制呢,典型的场景就是所有微服务的容器端口都是相同的,只是暴露的端口不同
服务名称 | 宿主机IP | 宿主机端口 | 容器内部端口 |
---|---|---|---|
apollo-configservice | 172.22.33.204 | 10002 | 8080 |
apollo-adminservice | 172.22.33.204 | 10003 | 8080 |
apollo-portal | 172.22.33.204 | 10004 | 8080 |
使用iptables 限制访问的目的地址
需要提前创建好docker 的网桥,指定容器的网络, ipv4_address: xx.xx.xx.xx
docker-compose.yaml
version: '3'
services:
apollo-configservice:
container_name: apollo-configservice
image: docker.cnb.cool/srebro/apollo:apollo-configservice-2.3.0
volumes:
- ./logs:/opt/logs
- /etc/localtime:/etc/localtime:ro
ports:
- "10002:8080"
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://172.22.33.201:3306/ApolloConfigDB?characterEncoding=utf8
- SPRING_DATASOURCE_USERNAME=srebro
- SPRING_DATASOURCE_PASSWORD=srebro@2025
- EUREKA_INSTANCE_HOME_PAGE_URL=http://172.22.33.204:10002
- EUREKA_INSTANCE_IP_ADDRESS=172.22.33.204
- TZ=Asia/Shanghai
restart: always
networks:
srebro:
ipv4_address: 10.22.33.66
apollo-adminservice:
depends_on:
- apollo-configservice
container_name: apollo-adminservice
image: docker.cnb.cool/srebro/apollo:apollo-adminservice-2.3.0
volumes:
- ./logs:/opt/logs
- /etc/localtime:/etc/localtime:ro
ports:
- "10003:8080"
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://172.22.33.201:3306/ApolloConfigDB?characterEncoding=utf8
- SPRING_DATASOURCE_USERNAME=srebro
- SPRING_DATASOURCE_PASSWORD=srebro@2025
- EUREKA_INSTANCE_HOME_PAGE_URL=http://172.22.33.204:10003
- EUREKA_INSTANCE_IP_ADDRESS=172.22.33.204
- TZ=Asia/Shanghai
restart: always
networks:
srebro:
ipv4_address: 10.22.33.67
apollo-portal:
depends_on:
- apollo-adminservice
container_name: apollo-portal
image: docker.cnb.cool/srebro/apollo:apollo-portal-2.3.0
volumes:
- ./logs:/opt/logs
- /etc/localtime:/etc/localtime:ro
ports:
- "10004:8080"
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://172.22.33.201:3306/ApolloPortalDB?characterEncoding=utf8
- SPRING_DATASOURCE_USERNAME=srebro
- SPRING_DATASOURCE_PASSWORD=srebro@2025
- APOLLO_PORTAL_ENVS=baseline
- baseline_META=http://172.22.33.204:10002
- TZ=Asia/Shanghai
restart: always
networks:
srebro:
ipv4_address: 10.22.33.68
networks:
srebro:
external: true
配置方式
-
只允许白名单地址
172.16.200.200
可以访问apollo 的10002
和10004
端口,也就是可以访问apollo-configservice
和apollo-portal
服务,其他都不允许访问。 -
这里的
10.22.33.66
,10.22.33.67
,10.22.33.68
三个IP 是容器的IP地址,8080
是容器的端口。三个IP 分别对应apollo-configservice
,apollo-adminservice
和apollo-portal
服务。#先添加拒绝规则
iptables -I DOCKER-USER -p tcp --dport 8080 -j DROP再添加允许规则(它们会被插入到链的顶部)
iptables -I DOCKER-USER -p tcp -s 172.16.200.200 -d 10.22.33.66 --dport 8080 -j ACCEPT
iptables -I DOCKER-USER -p tcp -s 172.16.200.200 -d 10.22.33.68 --dport 8080 -j ACCEPT
验证规则顺序
执行以下命令检查规则顺序,确保 ACCEPT 规则在 DROP 规则之上:
[root@localhost apollo]# iptables -L DOCKER-USER -n --line-numbers
Chain DOCKER-USER (1 references)
num target prot opt source destination
1 ACCEPT tcp -- 172.16.200.200 10.22.33.68 tcp dpt:8080
2 ACCEPT tcp -- 172.16.200.200 10.22.33.66 tcp dpt:8080
3 DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080
4 RETURN all -- 0.0.0.0/0 0.0.0.0/0
访问测试

iptables 规则持久化保存
[root@localhost apollo]# service iptables save
iptables: Saving firewall rules to /etc/sysconfig/iptables: [ OK ]
其他方式🚫 限制docker外部IP 访问
1、docker运行在宿主机模式上,直接走宿主机的防火墙或者iptables管理
2、docker 的外部暴露地址监听在 127.0.0.1 上 , 本地再运行一个NGINX 做代理,设置NGINX 白名单
K8S 场景下,怎么限制外部的IP 访问
- 用clusterip,内部访问没问题,外部走访问nginx的nodeport或者ingress,这样就可以用白名单了