为Docker分配物理网卡
为Docker分配物理网卡
Docker内部使用了Net namespace进行网络隔离,我们也可以利用这种底层的特性来魔改容器。
运行中的容器都对应一个PID,每个PID都有自己的名称空间,它的名称空间在 /proc/[PID]/ns 下
ls -lah /proc/2047/ns/
total 0
dr-x--x--x 2 root root 0 Nov 22 09:41 .
dr-xr-xr-x 9 root root 0 Nov 22 09:41 ..
lrwxrwxrwx 1 root root 0 Nov 22 09:44 cgroup -> 'cgroup:[4026532459]'
lrwxrwxrwx 1 root root 0 Nov 22 09:44 ipc -> 'ipc:[4026532343]'
lrwxrwxrwx 1 root root 0 Nov 22 09:44 mnt -> 'mnt:[4026532341]'
lrwxrwxrwx 1 root root 0 Nov 22 09:41 net -> 'net:[4026532400]'
lrwxrwxrwx 1 root root 0 Nov 22 09:44 pid -> 'pid:[4026532344]'
lrwxrwxrwx 1 root root 0 Nov 22 09:52 pid_for_children -> 'pid:[4026532344]'
lrwxrwxrwx 1 root root 0 Nov 22 09:44 time -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Nov 22 09:52 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Nov 22 09:44 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Nov 22 09:44 uts -> 'uts:[4026532342]'
namespace都是链接文件,格式为xxx:[inode number]。
Kubernests的Pod 的SideCar机制也是利用了这种特性,有选择的打通pause容器和其他容器之间的名称空间。
在系统层来看的话,就是每个sidecar内的容器使用了同一个net namespace inode的名称空间,这样他们的资源就实现了共享。
既然每个进程都有名称空间,那么pid为1的init进程也拥有自己的名称空间,就是系统开机之后使用的名称空间,所有的物理网卡也在这个名称空间下。
/proc/1/ns/net
---
ls -l /proc/1/ns/net
lrwxrwxrwx 1 root root 0 Nov 22 17:30 /proc/1/ns/net -> net:[4026531956]
那么问题来了,我们可否编辑内存中的名称空间,让物理网卡跑到容器的名称空间呢?
物理网卡进入了名称空间后怎么让它被使用?
完成上面两步,我们就能使用容器内的物理网卡了。
让ip命令识别到容器的namespace
我们都知道如果使用如下命令创建网络名称空间,会被创建到 /var/run/netns
下
root@ubuntu2210origin:~# ip netns list
root@ubuntu2210origin:~# ip netns add ns0
root@ubuntu2210origin:~# ls -la /var/run/netns/
total 0
drwxr-xr-x 2 root root 60 Nov 22 09:26 .
drwxr-xr-x 25 root root 780 Nov 22 09:26 ..
-r--r--r-- 1 root root 0 Nov 22 09:26 ns0
那么是不是我们利用这个原理,只要下面有名称空间,ip netns命令就可以进行管理呢?答案是肯定的
其他不是ip netns创建的network namespace,只要在这个目录下创建一个指向对应network namespace文件的链接即可。
创建目标容器
使用下面的命令创建一个没有网络的容器(pod原理一样)
docker run -d -ti --user root --net=none --name netutils nmaguiar/netutils /bin/bash
创建net namespace链接
既然ip netns 可以管理netns,我们创建链接过去让容器的net namespace可以被管理
CONTAINER_NAME="netutils"
PID=$(docker inspect --format '{{.State.Pid}}' $CONTAINER_NAME)
NAMESPACE_NAME="ns$PID"
NS_PATH="/var/run/netns/$NAMESPACE_NAME"
mkdir -p /var/run/netns
ln -sfT /proc/$PID/ns/net $NS_PATH
检查管理情况,出现下面类似的结果代表成功
root@ubuntu2210origin:~# ip netns show
ns1261
ns0
为namespace分配物理网卡
INTERFACE="enp0s17"
ip link set $INTERFACE netns $NAMESPACE_NAME
配置物理网卡
必须使用root权限才能配置物理网卡
配置网卡的ip,ip的路由表。
内核生效过慢?路由表并非立刻生效,sleep之后成功率100%
IP_ADDRESS="10.0.2.15/24"
GATEWAY="10.0.2.2"
ip netns exec $NAMESPACE_NAME ip addr add $IP_ADDRESS dev $INTERFACE
# ip netns exec $NAMESPACE_NAME ip route del default 如果网络为none则不需要删除
sleep 1
ip netns exec $NAMESPACE_NAME ip route add default via $GATEWAY dev $INTERFACE
ip netns exec $NAMESPACE_NAME ip link set $INTERFACE up
ip netns exec $NAMESPACE_NAME ip addr show $INTERFACE
如果开启了dhcp使用如下命令也可以,有一定概率让物理网卡 卡死在进程里,导致无法找到,必须找到卡死进程杀死
ip netns exec $NAMESPACE_NAME dhclient
出现如下输出代表成功
5: enp0s17: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
link/ether 08:00:27:6c:20:11 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 scope global enp0s17
valid_lft forever preferred_lft forever
检查生效
出现如下情况则成功
docker exec -it netutils ip a
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
5: enp0s17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:6c:20:11 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 scope global enp0s17
valid_lft forever preferred_lft forever
---
docker exec -it netutils ip route
default via 10.0.2.2 dev enp0s17
10.0.2.0/24 dev enp0s17 proto kernel scope link src 10.0.2.1
---
docker exec -it netutils ip rule
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
---
docker exec -it netutils ping -c 4 baidu.com
PING baidu.com (39.156.66.10) 56(84) bytes of data.
64 bytes from 39.156.66.10: icmp_seq=1 ttl=46 time=37.5 ms
64 bytes from 39.156.66.10: icmp_seq=2 ttl=46 time=38.7 ms
64 bytes from 39.156.66.10: icmp_seq=3 ttl=46 time=37.6 ms
64 bytes from 39.156.66.10: icmp_seq=4 ttl=46 time=38.8 ms
--- baidu.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3013ms
rtt min/avg/max/mdev = 37.455/38.140/38.764/0.614 ms
- 0
- 0
- 0
- 0
- 0
- 0