一、問題現(xiàn)象
1、現(xiàn)象舉例:
# 自制的springboot項目的dockerfile
# springboot 其實就是一個簡單的hello-world程序媒熊,寫了一個HelloController 做測試
# dockerfile內(nèi)容:
FROM java:8
MAINTAINER shan <test@qq2363581677@163.com>
ADD ./demo.jar /demo.jar
EXPOSE 8848
CMD java -jar /demo.jar
# 構(gòu)建鏡像
docker build -f ./dockerfile -t demo .
# 創(chuàng)建醒第、映射端口、運行容器
docker run -d --name=demo -p 8838:8848 demo
在阿里云服務(wù)器上外置的防火墻或安全組放行端口 8838 后谨湘,在瀏覽器發(fā)現(xiàn)可以直接訪問到數(shù)據(jù)
----問題在于咱還沒有開啟內(nèi)置的防火墻firewalld,卻出現(xiàn)了端口可以直接被訪問的情況
2芥丧、使用centos7 的防火墻firewalld查看放行端口情況
使用 docker 來部署項目紧阔,發(fā)現(xiàn)直接使用 -p 映射端口,會出現(xiàn)問題:
導(dǎo)致docker直接透過系統(tǒng)本機的防火墻续担,不用開端口可以直接外網(wǎng)訪問 8838 端口擅耽。
二、問題原因
1物遇、docker無視防火墻firewalld 的原因:其實docker并不是繞過了防火墻乖仇,<font color=red>只是因為它往iptables里寫了規(guī)則,你在firewalld里看不到而已询兴。</font>(centos7系統(tǒng)既有iptables乃沙,也有firewalld)
在docker安裝完后,會接管iptables诗舰,只要你docker run的時候加入?yún)?shù)警儒,他會自動向iptables里面添加規(guī)則。
所以使用 -p 容器端口:主機端口眶根,最終會在iptables中添加上容器的端口蜀铲。
? 防火墻 iptables 和 firewalld 的關(guān)系
Iptables:是centos6自帶的防火墻工具边琉,對服務(wù)器自身、網(wǎng)絡(luò)通信流量進(jìn)行控制蝙茶,用于過濾數(shù)據(jù)包艺骂,屬于網(wǎng)絡(luò)層防火墻。
FirewallD:是centos7自帶的防火墻工具隆夯,但是也同樣支持iptables钳恕。能夠允許哪些服務(wù)可用,哪些端口可用蹄衷,屬于更高一層的防火墻忧额。
iptables 與 firewalld 都不是真正的防火墻, 它們都只是用來定義防火墻策略的防火墻管理工具愧口。
● 對于 centos7 系統(tǒng)既有iptables睦番,也有firewalld
2、使用 iptables的命令可以查看到docker 容器的端口
iptables -L DOCKER
三耍属、問題的解決
1托嚣、依靠阿里云服務(wù)器提供的外置防火墻(推薦
)
有的服務(wù)器叫防火墻,有的服務(wù)器叫安全組厚骗,都是一個東西示启,都是系統(tǒng)的外置防火墻。
防火墻就像一個門领舰,想象一下你的錢藏到你的房間夫嗓,這時候有一個小偷想要來偷你的錢,小偷需要先溜進(jìn)你家大門【外置防火墻(安全組/防火墻)】冲秽,然后再溜進(jìn)你的房間【內(nèi)置防火墻(iptables/firewalld)】舍咖。
解決方式1:依靠阿里云服務(wù)器提供的外置防火墻放行需要暴露給外界的端口
- 相當(dāng)于關(guān)閉了你家大門
雖然內(nèi)置防火墻和外置防火墻一起使用更加安全,但是影響了數(shù)據(jù)訪問的效率了锉桑,為了速度排霉,有時候確保安全即可,不用更加安全民轴。
? 購買了騰訊云服務(wù)的老鐵要注意一下:
配置安全組的時候攻柠,不要選擇放行所有端口,要選擇自定義杉武,然后放行80、443辙售、ping轻抱、ssh端口(ssh端口建議進(jìn)行修改,不使用默認(rèn)的22)
2旦部、端口映射時指定監(jiān)聽地址為本機
對于那些只需要在本地訪問祈搜,不需要向外暴露端口的服務(wù)较店,在進(jìn)行端口映射的時候指定監(jiān)聽地址為127.0.0.1。
# 創(chuàng)建容燕、映射端口梁呈、運行容器
docker run -d --name=demo -p 127.0.0.1:8838:8848 demo
- 這時候,外界(通過瀏覽器)就無法訪問了到8838 端口了蘸秘,即使在外置防火墻放行了端口官卡。
3、禁用 docker 的 iptables 規(guī)則
- 原因就是docker 在iptables 加入規(guī)則醋虏,才導(dǎo)致內(nèi)置防火墻放行了docker容器的端口寻咒,現(xiàn)在咱就根治它,在docker配置文件禁止修改iptables 規(guī)則颈嚼。
① docker 配置修改毛秘,禁止 iptables 規(guī)則
# 編輯/lib/systemd/system/docker.service文件
# 在ExecStart后添加 --iptables=false
② 重載 docker 配置 & 重啟 docker 服務(wù)
systemctl daemon-reload
systemctl restart docker
完成上述兩步以及可以采用系統(tǒng) firewall 控制端口訪問,但會出現(xiàn) docker 容器間無法訪問阻课,而且容器內(nèi)也無法訪問外部網(wǎng)絡(luò)叫挟。
③ 使用類似 NAT 網(wǎng)絡(luò)方式使得 docker 可以訪問外部網(wǎng)絡(luò)
firewall-cmd --permanent --zone=public --add-masquerade
- 使用該方法解決 docker 無視系統(tǒng)防火墻問題所帶來的缺點:容器內(nèi)無法獲取得到客戶端的真實 IP,由于是類似 NAT 網(wǎng)絡(luò)限煞,常常 nginx 日志上記錄的是 docker0 網(wǎng)絡(luò)的子網(wǎng) IP抹恳,對于一些業(yè)務(wù)無法獲取真實 IP 可能不能容忍,看個人的取舍吧晰骑。
4适秩、使用 expose 方式暴露端口,然后采用 nginx 代理轉(zhuǎn)發(fā)(推薦
)
(1) 使用dockerCompose 編排+nginx代理轉(zhuǎn)發(fā)
① dockerCompose 中編排內(nèi)容:
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服務(wù)名相當(dāng)于域名秽荞,可以通過app找到對應(yīng)的ip地址
}
server{
listen 80;
server_name blog.yilele.site;
location /api {
proxy_pass http://appstream;#nginx代理轉(zhuǎn)發(fā)
}
}
(2) 上面例子的demo容器(使用dockerfile)+ nginx
server{
listen 80;
server_name blog.yilele.site;
location /hello {# 啟動docker的demo容器后,可以通過命令:docker inspect demo 找到demo對應(yīng)的ip地址
proxy_pass http://demo的ip地址:8888; # nginx代理轉(zhuǎn)發(fā)
}
}
? ports 和 expose 區(qū)別:
-
ports: 暴露容器端口到主機的任意端口或指定端口抚官。不管是否指定主機端口扬跋,使用ports都會將端口暴露給主機和其他容器。
- "9000:8080" # 綁定容器的8080端口到主機的9000端口 - "443" # 綁定容器的443端口到主機的任意端口凌节,容器啟動時隨機分配綁定的主機端口號
-
expose: 暴露容器給
link
到當(dāng)前容器的容器钦听。即暴露給處于同一個networks的容器。搭配link 進(jìn)行使用倍奢。expose: - "8000"
參考文章:《docker無視防火墻問題總結(jié)》 https://icharle.com/dockeriptables.html
如果本文對你有幫助的話記得給一樂點個贊哦朴上,感謝!