背景
最近偶然听了几堂极客时间的云原生免费公开课程,首次接触到了Linux namespace技术,并了解到这正是现在风头正劲的容器技术基石,引起了自己探究一二的兴趣,结合课程+网络搜索+实践操作,也算有了一些初步的了解,这里记录、总结一些学习过程。
Linux namespace简介
namespace技术网上的介绍已经很多了,这里不做过多赘述,简单总结namespace是Linux 内核提供的支持内核资源隔离的关键技术,目前包含以下7类namespace:
Namespace 变量 隔离资源
Cgroup CLONE_NEWCGROUP Cgroup 根目录
IPC CLONE_NEWIPC System V IPC, POSIX 消息队列等
Network CLONE_NEWNET 网络设备,协议栈、端口等
Mount CLONE_NEWNS 挂载点
PID CLONE_NEWPID 进程ID
User CLONE_NEWUSER 用户和group ID
UTS CLONE_NEWUTS Hostname和NIS域名
本文中主要涉及到的是Network+PID+Mount三个namespace。
容器运行时缺少必要命令问题与解决方案
下载使用docker官方提供的基础操作系统镜像-本例中为deiban--时会发现很多命令都默认没有安装--比如网络抓包tcpdump、甚至进程信息查看ps/top等,直觉上的办法只能进入容器内部逐个安装。然而如果每次运行新容器都需要安装一遍相关工具包的话未免有些繁琐,另外如果只是启动初期临时使用一下这些工具调试,之后便不再需要,额外安装这些工具其实也不必要的增大了容器本身的复杂度。
针对这一问题,其实linux提供了nsenter、unshare命令用于进入容器进程所属Network、PID、Mount 等namespace执行宿主机命令,从而达到无需在容器中安装命令,直接使用宿主机相应命令的目的,以下以tcpdump/ps/top三个命令的执行为例进行进行介绍。
利用宿主机tcpdump命令对docker容器进行抓包
利用nsenter命令可以指定目标namespace,并在其中执行对应命令。
以下命令先运行一个debian基础镜像的容器,而后在其中执行ip addr命令查看网络配置,并尝试执行tcpdump命令抓包
~# docker run -it --name ns_test_net -d debian:stretch
d221b13a5fbcbf23a981a3067847b743081fff20ae05e6892b8744546cb1b148
~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d221b13a5fbc debian:stretch "bash" 9 seconds ago Up 6 seconds ns_test_net
~# docker exec -it ns_test_net bash
root@d221b13a5fbc:/# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1
link/ipip 0.0.0.0 brd 0.0.0.0
23: eth0@if24: <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 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
root@d221b13a5fbc:/# tcpdump dump -i any -nvv
bash: tcpdump: command not found
可以看到报错command not found,此时可以简单通过nsenter使用宿主机命令进入容器所属namespace执行相关命令:
通过ip addr 查看容器网络配置,通过tcpdump 尝试抓包
~# docker inspect -f {
{.State.Pid}} ns_test_net # 获取容器进程在宿主机上的pid
9164
nsenter -t 9164 -n ip addr # -t指定容器进程pid,-n指定使用对应pid的Networ