容器網路除錯怎麼辦?一條命令就搞定
nsenter 命令是一個可以在指定程式的命令空間下執行指定程式的命令。它位於 util-linux 包中。
用途
一個最典型的用途就是進入容器的網路命令空間。相當多的容器為了輕量級,是不包含較為基礎的命令的,比如說
ip address
,
ping
,
telnet
,
ss
,
tcpdump
等等命令,這就給除錯容器網路帶來相當大的困擾:只能透過
docker inspect ContainerID
命令獲取到容器 IP,以及無法測試和其他網路的連通性。這時就可以使用 nsenter 命令僅進入該容器的網路名稱空間,使用宿主機的命令除錯容器網路。
此外,nsenter 也可以進入
mnt
,
uts
,
ipc
,
pid
,
user
命令空間,以及指定根目錄和工作目錄。
使用
首先看下 nsenter 命令的語法:
nsenter [options] [program [arguments]]
options:
-t, --target pid:指定被進入名稱空間的目標程式的pid
-m, --mount[=file]:進入mount命令空間。如果指定了file,則進入file的命令空間
-u, --uts[=file]:進入uts命令空間。如果指定了file,則進入file的命令空間
-i, --ipc[=file]:進入ipc命令空間。如果指定了file,則進入file的命令空間
-n, --net[=file]:進入net命令空間。如果指定了file,則進入file的命令空間
-p, --pid[=file]:進入pid命令空間。如果指定了file,則進入file的命令空間
-U, --user[=file]:進入user命令空間。如果指定了file,則進入file的命令空間
-G, --setgid gid:設定執行程式的gid
-S, --setuid uid:設定執行程式的uid
-r, --root[=directory]:設定根目錄
-w, --wd[=directory]:設定工作目錄
如果沒有給出program,則預設執行$SHELL。
示例:
執行一個 nginx 容器,檢視該容器的 pid:
[root@staight ~]# docker inspect -f {{.State.Pid}} nginx5645
然後,使用 nsenter 命令進入該容器的網路命令空間:
[root@staight ~]# nsenter -n -t5645[root@staight ~]# ip addr1: 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 forever18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever
進入成功~
在 Kubernetes 中,在得到容器 pid 之前還需獲取容器的 ID,可以使用如下命令獲取:
[root@node1 test]# kubectl get pod test -oyaml|grep containerID - containerID: docker://cf0873782d587dbca6aa32f49605229da3748600a9926e85b36916141597ec85
或者更為精確地獲取 containerID :
[root@node1 test]# kubectl get pod test -o template --template='{{range .status.containerStatuses}}{{.containerID}}{{end}}'docker://cf0873782d587dbca6aa32f49605229da3748600a9926e85b36916141597ec85
原理
namespace
Linux在不斷的新增名稱空間,目前有:
-
mount : 掛載名稱空間,使程式有一個獨立的掛載檔案系統,始於Linux 2.4.19
-
ipc : ipc名稱空間,使程式有一個獨立的ipc,包括訊息佇列,共享記憶體和訊號量,始於Linux 2.6.19
-
uts : uts名稱空間,使程式有一個獨立的hostname和domainname,始於Linux 2.6.19
-
net : network命令空間,使程式有一個獨立的網路棧,始於Linux 2.6.24
-
pid : pid名稱空間,使程式有一個獨立的pid空間,始於Linux 2.6.24
-
user : user名稱空間,是程式有一個獨立的user空間,始於Linux 2.6.23,結束於Linux 3.8
-
cgroup : cgroup名稱空間,使程式有一個獨立的cgroup控制組,始於Linux 4.6
[root@staight ns]# pwd/proc/1/ns[root@staight ns]# lltotal 0lrwxrwxrwx 1 root root 0 Sep 23 19:53 ipc -> ipc:[4026531839]lrwxrwxrwx 1 root root 0 Sep 23 19:53 mnt -> mnt:[4026531840]lrwxrwxrwx 1 root root 0 Sep 23 19:53 net -> net:[4026531956]lrwxrwxrwx 1 root root 0 Sep 23 19:53 pid -> pid:[4026531836]lrwxrwxrwx 1 root root 0 Sep 23 19:53 user -> user:[4026531837]lrwxrwxrwx 1 root root 0 Sep 23 19:53 uts -> uts:[4026531838]
clone
clone 和 fork 比較類似,但更為精細化,比如說使用 clone 建立出的子程式可以共享父程式的虛擬地址空間,檔案描述符表,訊號處理表等等。不過這裡要強調的是,clone 函式還能為新程式指定名稱空間。
#define _GNU_SOURCE
#include <sched.h>
int clone(int (*fn)(void *), void *child_stack,
int flags, void *arg, ...
/* pid_t *ptid, void *newtls, pid_t *ctid */ );
其中 flags 即可指定名稱空間,包括:
-
CLONE_NEWCGROUP: cgroup
-
CLONE_NEWIPC: ipc
-
CLONE_NEWNET: net
-
CLONE_NEWNS: mount
-
CLONE_NEWPID: pid
-
CLONE_NEWUSER: user
-
CLONE_NEWUTS: uts
使用示例:
pid = clone(childFunc, stackTop, CLONE_NEWUTS | SIGCHLD, argv[1]);
setns
# define _GNU_SOURCE /* See feature_test_macros(7) */
# include <sched.h>
int setns ( int fd, int nstype);
fd引數是一個指向一個名稱空間的檔案描述符,位於/proc/PID/ns/目錄。
nstype指定了允許進入的名稱空間,一般可設定為 0,表示允許進入所有名稱空間。
因此,往往該函式的用法為:
-
呼叫setns函式: 指定該執行緒的名稱空間。
-
呼叫execvp函式: 執行指定路徑的程式,建立子程式並替換父程式。
這樣,就可以指定名稱空間執行新的程式了。
程式碼示例:
#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
int
main(int argc, char *argv[])
{
int fd;
if (argc < 3) {
fprintf(stderr, "%s /proc/PID/ns/FILE cmd args...\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY); /* Get file descriptor for namespace */
if (fd == -1)
errExit("open");
if (setns(fd, 0) == -1) /* Join that namespace */
errExit("setns");
execvp(argv[2], &argv[2]); /* Execute a command in namespace */
errExit("execvp");
}
使用示例:
./ns_exec /proc/3550/ns/uts /bin/bash
nsenter
那麼,最後就是 nsenter 了,nsenter 相當於在setns的示例程式之上做了一層封裝,使我們無需指定名稱空間的檔案描述符,而是指定程式號即可。
指定程式號PID以及需要進入的名稱空間後,nsenter會幫我們找到對應的名稱空間檔案描述符/proc/PID/ns/FD,然後使用該名稱空間執行新的程式。
參考檔案
-
容器內抓包定位網路問題:
-
man-page:nsenter:
-
man-page:clone:
-
man-page:setns:
來源:%E5%91%BD%E4%BB%A4%E7%AE%80%E4%BB%8B/
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70013542/viewspace-2937078/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- What! 一條命令搞定監控?
- 網路不可用怎麼辦?無法訪問網際網路怎麼辦?網路故障原因大起底
- Android adb 網路除錯Android除錯
- echarts搞定各種地圖(想怎麼畫就怎麼畫)Echarts地圖
- docker 容器除錯技巧Docker除錯
- 公司網站開啟錯誤怎麼辦網站
- 公司網站報502錯誤怎麼辦網站
- 網站提示400錯誤:錯誤請求怎麼辦網站
- console除錯命令除錯
- Mac os上不了網怎麼辦,網路設定怎麼還原Mac
- 網站搬家資料庫錯誤怎麼辦?網站資料庫
- 網站資料庫老是錯誤怎麼辦?網站資料庫
- 網站首頁報416錯誤怎麼辦?網站
- 今日頭條的 ByteSpider,怎麼就成了小網站的“噩夢”?IDE網站
- 【除錯】SystemTap除錯網路卡狀態一例除錯
- 除錯——條件斷點除錯斷點
- 網站證書錯誤打不開網頁怎麼辦網站網頁
- 公司網站顯示指令碼錯誤怎麼辦網站指令碼
- 網站提示502 錯誤閘道器怎麼辦網站
- 網站資料庫連線錯誤怎麼辦?網站資料庫
- 兩條命令搞定 ChatGPT API 的呼叫問題ChatGPTAPI
- 網速不穩定怎麼辦?網路小白都在看
- 除錯 Docker 容器內部程式除錯Docker
- 如何除錯神經網路引數除錯神經網路
- Linkerd 2.10(Step by Step)—使用 Debug Sidecar,注入除錯容器來捕獲網路資料包IDE除錯
- docker刪除所有容器和映象命令Docker
- win10ip地址配置錯誤網路無法連線怎麼辦 ip地址配置錯誤網路無法連線的方法Win10
- 網站出現資料庫連線錯誤怎麼辦?網站資料庫
- 網站資料庫連線時錯誤怎麼辦?網站資料庫
- win10 如何除錯串列埠_win10串列埠除錯怎麼除錯Win10除錯串列埠
- win10 wifi有網顯示沒網怎麼辦_win10電腦找不到wifi網路怎麼辦Win10WiFi
- Android除錯命令收錄Android除錯
- Flutter的命令列除錯Flutter命令列除錯
- GDB除錯命令詳解除錯
- gdb高階除錯命令高階除錯
- 【HBase】誤刪除資料怎麼辦?
- 小白怎麼入門網路安全?看這篇就夠啦!
- git刪除本地分支命令 git怎麼刪除本地分支Git