docker容器里排错小方法

docker 容器在封装的时候一般只会安装程序需要的软件包。一些工具类的软件包不会安装的,这样容器会很大。也不常用,无意义。

但是这样如果容器有问题,或想查看一些信息,如网络信息、文件内容、抓包等。这样就没办法做到了。

下面说一种方法,容器共享进程、网络资源,可以用用 –pid、–ipc、–net 等参数

这样就可以查看容器的进程信息、网络、文件等事情了。

首先,运行一个容器:

1
docker run -d -p 7080:80 nginx:latest

运行一个nginx容器,

直接用 docker exec 进到容器里的时候, 是不能用iptables、ps、vim等命令的。

获取容器ID

1
2
3
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b99f5509819c nginx:latest "nginx -g 'daemon of…" 2 hours ago Up 2 hours 0.0.0.0:7080->80/tcp musing_kepler

我们开始进入到容器

1
2
CID=b99f5509819c
docker run -it --net=container:$CID --ipc=container:$CID --pid=container:$CID alpine-tools:latest

CID 是容器 ID, 后面都用 $CID 来代替

  • alpine-tools:latest 是自己做的镜像, 可以把常用的命令放在里面,如(iptables、tcpdump、vim等)

这样,容器的网络、磁盘、进程都和你启动这个容器共享了,所以就可以实时查看nginx容器里的信息。

运行ps 就可以看到nginx的进程了

1
2
3
4
5
6
7
/ # ps
PID USER TIME COMMAND
1 root 0:00 nginx: master process nginx -g daemon off;
6 101 0:00 nginx: worker process
77 root 0:00 /bin/sh
82 root 0:00 ps
/ #

运行tcpdump 就可以实时抓包了

1
2
3
4
5
6
7
8
9
10
11
12
13
/ # tcpdump -XX -A
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
09:35:44.971181 IP 10.1.1.1.5045 > b99f5509819c.80: Flags [S], seq 1170821353, win 65535, options [mss 1280,nop,wscale 6,nop,nop,TS val 53306312 ecr 0,sackOK,eol], length 0
0x0000: 0242 ac11 0002 0242 bf93 7039 0800 45b8 .B.....B..p9..E.
0x0010: 0040 0000 0000 2a06 1951 0a76 c026 ac11 .@....*..Q.v.&..
0x0020: 0002 13b5 0050 45c9 50e9 0000 0000 b002 .....PE.P.......
0x0030: ffff af53 0000 0204 0500 0103 0306 0101 ...S............
0x0040: 080a 032d 63c8 0000 0000 0402 0000 ...-c.........
09:35:44.971227 IP b99f5509819c.80 > 10.1.11.5045: Flags [S.], seq 3301963106, ack 1170821354, win 28960, options [mss 1460,sackOK,TS val 237381948 ecr 53306312,nop,wscale 9], length 0
0x0000: 0242 bf93 7039 0242 ac11 0002 0800 4500 .B..p9.B......E.
0x0010: 003c 0000 4000 4006 c40c ac11 0002 0a76 .<..@.@........v
......

但是这个时候运行 iptables 还是不行的, 提示没有权限

1
2
3
4
/ # iptables -n -L
iptables v1.8.3 (legacy): can't initialize iptables table `filter': Permission denied (you must be root)
Perhaps iptables or your kernel needs to be upgraded.
/ #

需要运行工具容器的时候提权才能行,添加 privileged 参数。 如:

1
docker run -it --privileged --net=container:$CID --ipc=container:$CID --pid=container:$CID alpine-tools:latest

运行 iptables 命令 (返回结果类似于这样)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 # iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target prot opt source destination

Chain INPUT (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination
DOCKER_OUTPUT all -- 0.0.0.0/0 127.0.0.11

Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
DOCKER_POSTROUTING all -- 0.0.0.0/0 127.0.0.11

Chain DOCKER_OUTPUT (1 references)
target prot opt source destination
DNAT tcp -- 0.0.0.0/0 127.0.0.11 tcp dpt:53 to:127.0.0.11:36820
DNAT udp -- 0.0.0.0/0 127.0.0.11 udp dpt:53 to:127.0.0.11:37685

Chain DOCKER_POSTROUTING (1 references)
target prot opt source destination
SNAT tcp -- 127.0.0.11 0.0.0.0/0 tcp spt:36820 to::53
SNAT udp -- 127.0.0.11 0.0.0.0/0 udp spt:37685 to::53

如果你的容器是 -v 挂载volume 启动的话

容器启动:

1
docker run -d -p 7080:80 nginx:latest

可以用下面的方式查看 volume 里数据。

1
docker run -it --privileged --net=container:$CID --ipc=container:$CID --pid=container:$CID --volumes-from $CID:ro alpine-tools:latest

这样就可以查看 volume 里的数据了,

  • 如果你的volume是NFS、ceph等网络存储,你可以这样做来吧数据备份到本地。
1
2
3
docker run --volumes-from $CID -v $(pwd):/backup alpine-tools:latest tar cvf /backup/backup.tar /home

# 将 $CID 容器上volume挂在到本容器上, 在讲当前目录挂在到容器的 /backup 目录, 进入容器执行 tar 备份目录

另外 还有其他方式可以查看容器的方式,简单介绍一下。

nsenter 方式

nsenter 需要做的容器里的进程 PID 的,

1
2
PID=$(docker inspect --format '{{.State.Pid}}' $CID)
nsenter --target $PID --mount --uts --ipc --net --pid

这样就可以进图到容器里了。

这样的你程序镜像就不用安装一下系统工具的软件包了。 有问题可以用这一种容器共享的方式来排查了。

感谢您的支持!