Docker 容器網路名稱空間不可見
本文將探討 Docker 容器中網路名稱空間檔案的一個問題。我們將研究為什麼網路名稱空間檔案對 ip netns ls 命令不可見。
在繼續之前,讓我們先簡要概述一下 Docker、容器和網路名稱空間。
容器化
容器化類似於虛擬化,其中應用程式及其所有依賴項和庫都打包到一個容器中;它可以在任何計算環境中執行。當作業系統核心以及所有必要的庫和依賴項都包含在容器中時,任何處理該應用程式的人員都可以僅使用該容器來處理它,而不是在虛擬機器上設定適當的計算環境。容器沒有客戶機作業系統,並在主機上執行。因此,它們根據需要共享相關的庫和資源。
由於特定於容器的二進位制檔案和庫在主機核心上執行,因此應用程式的處理和執行速度非常快。
容器在幾分之一秒內啟動,並且容器比虛擬機器更輕量級且速度更快。
Docker
Docker 是一個軟體平臺,可實現應用程式的快速開發、測試和部署。Docker 將軟體組織成稱為容器的標準化單元,其中包含軟體執行所需的一切,例如庫、系統工具、程式碼和執行時。Docker 允許您將應用程式快速部署和擴充套件到任何環境,同時確信您的程式碼將執行。
網路名稱空間
Linux 網路名稱空間是核心的一項功能,允許我們虛擬化和隔離網路環境。例如,使用網路名稱空間,您可以建立獨立的網路介面和路由表,這些介面和路由表與系統其餘部分隔離。
Linux 中的名稱空間分為六種型別:pid、net、uts、mnt、ipc 和 user。
示例
如果您執行命令“lsns”,它將顯示系統中所有現有的名稱空間,如下所示。
$ lsns
輸出
NS TYPE NPROCS PID USER COMMAND 4026531836 pid 2 7358 sachin -bash 4026531837 user 2 7358 sachin -bash 4026531838 uts 2 7358 sachin -bash 4026531839 ipc 2 7358 sachin -bash 4026531840 mnt 2 7358 sachin -bash 4026532185 net 2 7358 sachin -bash
不可見的 Docker 網路名稱空間
當我們建立 Docker 容器時,守護程序將為容器程序生成名稱空間偽檔案。然後,這些檔案將放置在 /proc/pid/ns 目錄中,其中 pid 是容器的程序 ID。考慮以下場景
pi@TTP:sudo docker run --rm -d ubuntu:latest sleep infinity c5503724a3ab4339e9246f0ef4cddf475e1f4f98964df834bfacaf5ff1 70fb03
pi@TTP:docker inspect --format '{{.State.Pid}}' c5503724a3ab 1946
檢視 /proc/1946/ns 目錄,我們可以看到所有不同型別的名稱空間都已建立。
pi@TTP:sudo ls -la /proc/1946/ns total 0 dr-x--x--x 2 root root 0 Oct 6 17:25 . dr-xr-xr-x 9 root root 0 Oct 6 17:25 .. lrwxrwxrwx 1 root root 0 Oct 6 17:28 ipc -> ipc:[4026532177] lrwxrwxrwx 1 root root 0 Oct 6 17:25 mnt -> mnt:[4026532175] lrwxrwxrwx 1 root root 0 Oct 6 17:25 net -> net:[4026532180] lrwxrwxrwx 1 root root 0 Oct 6 17:28 pid -> pid:[4026532178] lrwxrwxrwx 1 root root 0 Oct 6 17:28 user -> user:[4026531837] lrwxrwxrwx 1 root root 0 Oct 6 17:28 uts -> uts:[4026532176]
在名稱空間偽檔案列表中可以看到此程序的 net 檔案的存在。我們可以預期在列出所有網路名稱空間時 net 檔案會出現,因為它對應於 Linux 網路名稱空間。但是,很明顯情況並非如此。例如,現在執行 ip netns ls 會產生 0 個結果。
pi@TTP:ip netns ls pi@TTP:
缺少檔案引用
我們必須瞭解 ip netns ls 命令在 /var/run/netns 目錄中搜索網路名稱空間檔案。但是,在建立網路名稱空間檔案後,Docker 守護程序不會在 /var/run/netns 目錄中建立對它的引用。因此,ip netns ls 無法解析網路名稱空間檔案。
pi@TTP:mkdir -p /var/run/netns pi@TTP:touch /var/run/netns/c5503724a3ab
要繫結掛載 net 檔案,請使用 mount -o bind 命令 -
pi@TTP:mount -o bind /proc/1946/ns/net /var/run/netns/c5503724a3ab
再次執行相同的 ip netns ls 命令將按預期顯示網路名稱空間。
pi@TTP:ip netns ls c5503724a3ab (id: 1)
在建立到網路名稱空間檔案的檔案引用後,我們可以使用 ip netns exec 執行任何 ip 命令。例如,我們可以使用 ip addr list 命令檢查網路名稱空間中的介面 -
pi@TTP:ip netns exec c5503724a3ab ip addr list 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.3/16 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe11:3/64 scope link valid_lft forever preferred_lft forever
結論
我們在本教程的開始簡要概述了 Linux 名稱空間、Docker 和容器。然後,我們演示了 docker run 建立的網路名稱空間檔案在執行 ip netns ls 時不會出現的問題。我們後來發現,這是因為在 /var/run/netns 中沒有建立檔案引用,而 ip netns ls 命令在該目錄中查詢任何網路名稱空間。
最後,我們在文章中給出了一個簡單的解決方法:將檔案繫結掛載到 /var/run/netns,以便可以使用 ip netns ls 找到它。