docker 映射端口穿透內置防火牆
- 2022 年 6 月 29 日
- 筆記
- docker 映射端口穿透內置防火牆
一、問題現象
1、現象舉例:
# 自製的springboot項目的dockerfile
# springboot 其實就是一個簡單的hello-world程序,寫了一個HelloController 做測試
# dockerfile內容:
FROM java:8
MAINTAINER shan <test@[email protected]>
ADD ./demo.jar /demo.jar
EXPOSE 8848
CMD java -jar /demo.jar
# 構建鏡像
docker build -f ./dockerfile -t demo .
# 創建、映射端口、運行容器
docker run -d --name=demo -p 8838:8848 demo
在阿里雲服務器上外置的防火牆或安全組放行端口 8838 後,在瀏覽器發現可以直接訪問到數據
—-問題在於咱還沒有開啟內置的防火牆firewalld,卻出現了端口可以直接被訪問的情況
2、使用centos7 的防火牆firewalld查看放行端口情況
使用 docker 來部署項目,發現直接使用 -p 映射端口,會出現問題:
導致docker直接透過系統本機的防火牆,不用開端口可以直接外網訪問 8838 端口。
二、問題原因
1、docker無視防火牆firewalld 的原因:其實docker並不是繞過了防火牆,只是因為它往iptables里寫了規則,你在firewalld里看不到而已。(centos7系統既有iptables,也有firewalld)
在docker安裝完後,會接管iptables,只要你docker run的時候加入參數,他會自動向iptables裏面添加規則。
所以使用 -p 容器端口:主機端口,最終會在iptables中添加上容器的端口。
☺ 防火牆 iptables 和 firewalld 的關係
Iptables:是centos6自帶的防火牆工具,對服務器自身、網絡通信流量進行控制,用於過濾數據包,屬於網絡層防火牆。
FirewallD:是centos7自帶的防火牆工具,但是也同樣支持iptables。能夠允許哪些服務可用,哪些端口可用,屬於更高一層的防火牆。
iptables 與 firewalld 都不是真正的防火牆, 它們都只是用來定義防火牆策略的防火牆管理工具。
● 對於 centos7 系統既有iptables,也有firewalld
2、使用 iptables的命令可以查看到docker 容器的端口
iptables -L DOCKER
三、問題的解決
1、依靠阿里雲服務器提供的外置防火牆(推薦
)
-
有的服務器叫防火牆,有的服務器叫安全組,都是一個東西,都是系統的外置防火牆。
-
防火牆就像一個門,想像一下你的錢藏到你的房間,這時候有一個小偷想要來偷你的錢,小偷需要先溜進你家大門【外置防火牆(安全組/防火牆)】,然後再溜進你的房間【內置防火牆(iptables/firewalld)】。
解決方式1:依靠阿里雲服務器提供的外置防火牆放行需要暴露給外界的端口
- 相當於關閉了你家大門
雖然內置防火牆和外置防火牆一起使用更加安全,但是影響了數據訪問的效率了,為了速度,有時候確保安全即可,不用更加安全。
☺ 購買了騰訊雲服務的老鐵要注意一下:
配置安全組的時候,不要選擇放行所有端口,要選擇自定義,然後放行80、443、ping、ssh端口(ssh端口建議進行修改,不使用默認的22)
2、端口映射時指定監聽地址為本機
對於那些只需要在本地訪問,不需要向外暴露端口的服務,在進行端口映射的時候指定監聽地址為127.0.0.1。
# 創建、映射端口、運行容器
docker run -d --name=demo -p 127.0.0.1:8838:8848 demo
- 這時候,外界(通過瀏覽器)就無法訪問了到8838 端口了,即使在外置防火牆放行了端口。
3、禁用 docker 的 iptables 規則
- 原因就是docker 在iptables 加入規則,才導致內置防火牆放行了docker容器的端口,現在咱就根治它,在docker配置文件禁止修改iptables 規則。
① docker 配置修改,禁止 iptables 規則
# 編輯/lib/systemd/system/docker.service文件
# 在ExecStart後添加 --iptables=false
② 重載 docker 配置 & 重啟 docker 服務
systemctl daemon-reload
systemctl restart docker
完成上述兩步以及可以採用系統 firewall 控制端口訪問,但會出現 docker 容器間無法訪問,而且容器內也無法訪問外部網絡。
③ 使用類似 NAT 網絡方式使得 docker 可以訪問外部網絡
firewall-cmd --permanent --zone=public --add-masquerade
- 使用該方法解決 docker 無視系統防火牆問題所帶來的缺點:容器內無法獲取得到客戶端的真實 IP,由於是類似 NAT 網絡,常常 nginx 日誌上記錄的是 docker0 網絡的子網 IP,對於一些業務無法獲取真實 IP 可能不能容忍,看個人的取捨吧。
4、使用 expose 方式暴露端口,然後採用 nginx 代理轉發(推薦
)
(1) 使用dockerCompose 編排+nginx代理轉發
① dockerCompose 中編排內容:
version: "3"
services:
app:
image: app
container_name: app
build: ..
expose:
- "8888"
depends_on:
- mysql
- redis
nginx:
image: nginx
container_name: nginx
ports:
- 80:80
- 443:443
volumes:
- /mnt/docker/nginx/:/etc/nginx/
links:
- app
depends_on:
- app
② nginx 中的配置:
upstream appstream{
server app:8888; #dockerCompose編排之後,app服務名相當於域名,可以通過app找到對應的ip地址
}
server{
listen 80;
server_name blog.yilele.site;
location /api {
proxy_pass //appstream;#nginx代理轉發
}
}
(2) 上面例子的demo容器(使用dockerfile)+ nginx
server{
listen 80;
server_name blog.yilele.site;
location /hello {# 啟動docker的demo容器後,可以通過命令:docker inspect demo 找到demo對應的ip地址
proxy_pass //demo的ip地址:8888; # nginx代理轉發
}
}
☺ ports 和 expose 區別:
-
ports: 暴露容器端口到主機的任意端口或指定端口。不管是否指定主機端口,使用ports都會將端口暴露給主機和其他容器。
- "9000:8080" # 綁定容器的8080端口到主機的9000端口 - "443" # 綁定容器的443端口到主機的任意端口,容器啟動時隨機分配綁定的主機端口號
-
expose: 暴露容器給
link
到當前容器的容器。即暴露給處於同一個networks的容器。搭配link 進行使用。expose: - "8000"
參考文章:《docker無視防火牆問題總結》 //icharle.com/dockeriptables.html
如果本文對你有幫助的話記得給一樂點個贊哦,感謝!