昨天最後有提到,我們到目前為止,可以過橋跟出國是為我們把 FORWARD policy 設定成 ACCEPT,但其實安裝 Docker 以後,他是設定成 DROP 的,於是我們也透過以下指令來把設定調整回來:
sudo iptables --policy FORWARD DROP
把 FORWARD 設定成 DROP 後,我們來 ns1 裡試試看目前的情況:
ubuntu@ip-xxx:~$ sudo ip netns exec ns1 bash
root@ip-xxx:/home/ubuntu# ping 172.17.0.3 -c 2
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
--- 172.17.0.3 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1002ms
無法 ping 成功,同時間我們也在 host 去針對 docker1
錄封包:
ubuntu@ip-xxx:~$ sudo tcpdump -i docker1 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on docker1, link-type EN10MB (Ethernet), capture size 262144 bytes
13:35:05.581568 IP 172.18.0.2 > 172.17.0.3: ICMP echo request, id 37263, seq 1, length 64
13:35:06.583079 IP 172.18.0.2 > 172.17.0.3: ICMP echo request, id 37263, seq 2, length 64
這邊可以看到,其實 docker1
是有收到這個 ICMP echo request 的喔,同時也對 veth1-br
錄封包的話,會發現 veth1-br
沒有收到請求,也就是 docker1
收到了,但沒有轉給 veth1-br
。
root@ip-xxx:/home/ub![https://ithelp.ithome.com.tw/upload/images/20221015/201518577bRPh6WhNE.png](https://ithelp.ithome.com.tw/upload/images/20221015/201518577bRPh6WhNE.png)untu# ping 8.8.8.8 -c 2
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
--- 8.8.8.8 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1028ms
無法 ping 成功,同時對 docker1
錄封包:
ubuntu@ip-xxx:~$ sudo tcpdump -i docker1 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on docker1, link-type EN10MB (Ethernet), capture size 262144 bytes
13:38:42.995503 IP 172.18.0.2 > 8.8.8.8: ICMP echo request, id 37276, seq 1, length 64
13:38:44.023108 IP 172.18.0.2 > 8.8.8.8: ICMP echo request, id 37276, seq 2, length 64
docker1
一樣有收到,但同一時間對 ens5
錄封包的話,會發現 ens5
沒有收到任何請求,跟對 ns2 ping 一樣,是 docker1
有收到,但沒有轉發到 ens5
。
我們來觀察一下目前 host 中 iptables 的設定,試著來看看 Docker 對 iptables 有做什麼調整:
因為都是 docker1
收得到,但沒有轉發,所以我特別關注了 FORWARD 這個區塊,標示起來的這幾條規則是我懷疑有相關的,讓我們逐一來試試看:
Chain FORWARD (policy DROP 6 packets, 504 bytes)
num pkts bytes target prot opt in out source destination
6 0 0 ACCEPT all -- docker0 docker0 0.0.0.0/0 0.0.0.0/0
這條規則的意思應該是允許轉發從 docker0
進入並且從 docker0
離開的,我推測如果對 docker1
加上這條應該可以讓 ns1 到 ns2,來試試看:
ubuntu@ip-xxx:~$ sudo iptables -t filter -A FORWARD -i docker1 -o docker1 -j ACCEPT
到 ns1 裡 ping 看看 ns2 的 172.18.0.3:
root@ip-xxx:/home/ubuntu# ping 172.18.0.3 -c 2
PING 172.18.0.3 (172.18.0.3) 56(84) bytes of data.
64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.080 ms
64 bytes from 172.18.0.3: icmp_seq=2 ttl=64 time=0.067 ms
--- 172.18.0.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1022ms
rtt min/avg/max/mdev = 0.067/0.073/0.080/0.006 ms
果然可以 ping 到了,那當然 veth1-br
也有收到封包:
ubuntu@ip-172-31-59-121:~$ sudo tcpdump -i veth1-br -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth1-br, link-type EN10MB (Ethernet), capture size 262144 bytes
13:56:22.424809 IP 172.18.0.2 > 172.18.0.3: ICMP echo request, id 37311, seq 1, length 64
13:56:22.424830 IP 172.18.0.3 > 172.18.0.2: ICMP echo reply, id 37311, seq 1, length 64
13:56:23.447113 IP 172.18.0.2 > 172.18.0.3: ICMP echo request, id 37311, seq 2, length 64
13:56:23.447134 IP 172.18.0.3 > 172.18.0.2: ICMP echo reply, id 37311, seq 2, length 64
Chain FORWARD (policy DROP 6 packets, 504 bytes)
num pkts bytes target prot opt in out source destination
5 6666 358K ACCEPT all -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0
這條規則跟 6 很像,只是是加上了 !
,所以是允許轉發從 docker0
進入但不是從 docker0
離開的封包?我推測如果對 docker1
加上這條應該可以讓 ns1 到外部去,來試試看:
ubuntu@ip-xxx:~$ sudo iptables -t filter -A FORWARD -i docker1 ! -o docker1 -j ACCEPT
到 ns1 裡去 ping 看看 8.8.8.8:
root@ip-xxx:/home/ubuntu# ping 8.8.8.8 -c 2
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
--- 8.8.8.8 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1000ms
欸,還是失敗的,讓我們看看對 docker1
錄的封包:
ubuntu@ip-xxx:~$ sudo tcpdump -i docker1 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on docker1, link-type EN10MB (Ethernet), capture size 262144 bytes
14:00:51.790927 IP 172.18.0.2 > 8.8.8.8: ICMP echo request, id 37334, seq 1, length 64
14:00:52.791110 IP 172.18.0.2 > 8.8.8.8: ICMP echo request, id 37334, seq 2, length 64
跟之前一樣,有收到 ICMP echo request,那這時候 ens5
的情況呢?
ubuntu@ip-172-31-59-121:~$ sudo tcpdump -i ens5 icmp -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens5, link-type EN10MB (Ethernet), capture size 262144 bytes
14:00:51.790972 IP 172.31.59.121 > 8.8.8.8: ICMP echo request, id 37334, seq 1, length 64
14:00:51.797111 IP 8.8.8.8 > 172.31.59.121: ICMP echo reply, id 37334, seq 1, length 64
14:00:52.791147 IP 172.31.59.121 > 8.8.8.8: ICMP echo request, id 37334, seq 2, length 64
14:00:52.797291 IP 8.8.8.8 > 172.31.59.121: ICMP echo reply, id 37334, seq 2, length 64
咦咦咦,ens5
是有收到 ICMP echo request 的,也就是 docker1
這次有 ICMP 請求轉發到 ens5
喔,表示我們剛剛加的規則則是有效的,而且 ens5
也有收到來自 8.8.8.8 的 reply,很顯然,這次是 ens5
沒有將封包轉發給 docker1
?
Chain FORWARD (policy DROP 6 packets, 504 bytes)
num pkts bytes target prot opt in out source destination
3 7034 48M ACCEPT all -- * docker0 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
4 4 336 DOCKER all -- * docker0 0.0.0.0/0 0.0.0.0/0
於是我來試試看加上一條允許轉發從 docker1
離開的規則看看:
ubuntu@ip-xxx:~$ sudo iptables -t filter -A FORWARD -o docker1 -j ACCEPT
再次回到 ns1 裡試試看 ping 8.8.8.8:
root@ip-xxx:/home/ubuntu# ping 8.8.8.8 -c 2
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=101 time=7.68 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=101 time=7.80 ms
--- 8.8.8.8 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 7.682/7.742/7.802/0.060 ms
喔耶,果然成功了!docker1
也如預期地,收到了 ICMP echo reply 了:
ubuntu@ip-xxx:~$ sudo tcpdump -i docker1 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on docker1, link-type EN10MB (Ethernet), capture size 262144 bytes
14:05:58.665230 IP 172.18.0.2 > 8.8.8.8: ICMP echo request, id 37351, seq 1, length 64
14:05:58.672885 IP 8.8.8.8 > 172.18.0.2: ICMP echo reply, id 37351, seq 1, length 64
14:05:59.667115 IP 172.18.0.2 > 8.8.8.8: ICMP echo request, id 37351, seq 2, length 64
14:05:59.674873 IP 8.8.8.8 > 172.18.0.2: ICMP echo reply, id 37351, seq 2, length 64
到此,我們成功地關掉無腦轉發這件事,好好地針對我們的 docker1
設定了相關的轉發規則,愈來愈接近 Docker 的做法了!
今天也來到了鐵人賽第 30 天了,我是真的不敢相信自己可以完賽,從開賽之初,就是拖延到死線的最後一天晚上才發出第一天的文章,真的完全沒有存稿、也沒有任何計畫的狀態,外加非常忙碌的工作。白天一整天幾乎是沒有什麼喘息時間,每天免強趕在 7、8 點下班,草草吃個晚餐,就得坐到書桌前開始寫文,偶爾某一天寫得長一些,可以拆成兩篇、放著過 12 點發,讓自己第二天可以稍微輕鬆一點點。除此之外,決大部分的文章都是當天想、當天晚上做實驗、邊做實驗邊紀錄,有些實驗以前做過,有的也真的是第一次做,有時候差點做不出來,或是做出來的跟我理解的不一樣、無法解釋什麼的,每天都超刺激,經常是在晚上 12 點前的幾分鐘發出來,就這樣痛苦且掙扎的走到了第 30 天。
雖然鐵人賽這麼多屆了、很多人也都有做到,但還是覺得很有成就感、也很開心,最重要的是感謝我的伴侶,他要忍受我超級忙的時程表,幾乎沒有陪伴他的時間,也幫我做掉很多事,最近他確診了,希望他早日恢復健康,也希望跟他同住的我,可以是天選之人 QQ
另外要感謝被我拖下水一起參賽的前同事兼好友 Sra,他比我還認真,有計畫、有存稿地在進行,這邊推薦一下他的鐵人賽「PyTorch 生態鏈實戰運用」,對機器學習有興趣的,務必去看一下,可以跟他交流交流,他是個技術與溝通能力兼俱的人,之前跟他一起工作很愉快!
再來是要感謝我 AppWorks School 的學員們,感謝他們時不時就幫我點擊一下文章,增加一點點閱率。這份工作我也快要滿一年了,目前帶過三個班,從他們身上,我親眼看到原來人類的動機可以這麼強烈,也可以這麼認真跟有毅力,還不是一個、兩個人這樣,是幾十個人都這樣,我從他們身上學習到很多東西,每當我想要放棄的時候,我都會想,我平時都鼓勵他們不可以輕易放棄,那我也要做到才行啊,可以說如果不是他們,我可能撐不到現在。
最後還是要感謝我自己啦,拖延症外加躺平的我,竟然可以完成,這系列與其說是討論 Docker,還不如說是在討論 Linux,我有做到第一天說的,想要分享一些這些年在研究 Docker 觀察到的一些事,平常都要求學員們,不要相信網路文章、不要相信我說的,要親自動手做實驗,我應該幾乎每天的文章都有動手的部分,有的很簡單、只需要下幾個指令觀察一下,有的需要寫點程式,但無論如何,親自動手做實驗與觀察,這應該是工程師最基本的素養,我做到了,以後可以更有底氣要求學員了(喂)。
寫到今天,其實網路篇還沒寫完,cgroup 跟 volume 也沒有寫到,最近跟學員們在 container 做網路連線數量的測試,也有遇到一些好玩的結論,也都還無法紀錄進來,甚至還有朋友們敲碗過的 build images, docker compose 等,我的文章廢話比較多,之前就開玩笑,要寫到這些,鐵人賽大概要 100 天以上才有可能(不,我開玩笑的,不要 100 天)...聽說 21 天會養成一個新習慣,但我覺得我明天就會立刻放下每天寫文這件事,以後有機會再繼續寫下去嚕,以前跟朋友聊過,基礎入門教學的文章會最多人看,這次也有感受到,沒人看的話動力也的確會降低,之後再看看嚕。
最後分享一下社群好友 Mouson 最近在 FB 分享的句子:
卓越是一門藝術,來自訓練加上習慣。我們行事會得宜,不是因為有美德或卓越,而是因為行為得宜,而擁有美德或卓越。我們重複做的事會造就我們。因此卓越不是一次行動,而是一種習慣。 -- 亞里斯多德
很多事不是因為你很厲害,所以可以做到,而是你做到了,所以你變得很厲害,藉此鼓勵以後想參賽的朋友們,共勉之。