1. Liunx veth-pair 和 network namespace

Docker 中容器的访问需要依赖 veth-pair 和 network namespace 等技术。network namespace(网络命名空间)代表的是独立的网络协议栈,不同的网络命令空间相互隔离,无法访问。而 veth-pair 可以打破这种限制,实现不同网络命令空间的相互访问。
 
构建包含 veth-pair 和 network namespace 的示意图如下:
 
创建网络命名空间 ns1 和 ns2:
[root@lianhua netns]$ ip netns add ns1
[root@lianhua netns]$ ip netns add ns2
[root@lianhua netns]$ ip netns list
ns2
ns1
 
默认情况下创建的网络命名空间只有一个 loopback 接口,将它 up 起来:
[root@lianhua netns]$ ip netns exec ns1 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 [root@lianhua netns]$ ip netns exec ns1 ip link set dev lo up
[root@lianhua netns]$ ip netns exec ns1 ip a
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
 
创建 veth-pair 设备 veth-ns1-a 和 veth-ns2-b,并将 veth-pair 分别加到对应的 network namespace 中:
[root@lianhua netns]$ ip link add veth-ns1-a type veth peer name veth-ns2-b
[root@lianhua netns]$ ip link set veth-ns1-a netns ns1
[root@lianhua netns]$ ip link set veth-ns2-b netns ns2 [root@lianhua netns]$ ip netns exec ns1 ip a
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
307: veth-ns1-a@if306: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 8a:a2:45:23:aa:28 brd ff:ff:ff:ff:ff:ff link-netnsid 1 [root@lianhua netns]$ ip netns exec ns2 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
306: veth-ns2-b@if307: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 5e:a9:4e:d9:e2:5d brd ff:ff:ff:ff:ff:ff link-netnsid 0
 
veth 设备在网络命名空间中的表现是一个网络接口,可以把它们想象成一根“网线”,网线一头连在 ns1,一头连在 ns2。将接口 up 起来:
[root@lianhua netns]$ ip netns exec ns1 ip link set dev veth-ns1-a up
[root@lianhua netns]$ ip netns exec ns2 ip link set dev veth-ns2-b up
[root@lianhua netns]$ ip netns exec ns1 ip a
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
307: veth-ns1-a@if306: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 8a:a2:45:23:aa:28 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::88a2:45ff:fe23:aa28/64 scope link
valid_lft forever preferred_lft forever
 
为接口配置 ip:
[root@lianhua netns]$ ip netns exec ns1 ip addr add 162.0.0.1/24 dev veth-ns1-a
[root@lianhua netns]$ ip netns exec ns2 ip addr add 162.0.0.2/24 dev veth-ns2-b
[root@lianhua netns]$ ip netns exec ns1 ip a
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
307: veth-ns1-a@if306: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 8a:a2:45:23:aa:28 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet 162.0.0.1/24 scope global veth-ns1-a
valid_lft forever preferred_lft forever
inet6 fe80::88a2:45ff:fe23:aa28/64 scope link
valid_lft forever preferred_lft forever
 
进入到网络命名空间 ns1 中访问 ns2:
[root@lianhua netns]$ ip netns exec ns1 ping 162.0.0.2
PING 162.0.0.2 (162.0.0.2) 56(84) bytes of data.
64 bytes from 162.0.0.2: icmp_seq=1 ttl=64 time=0.066 ms
64 bytes from 162.0.0.2: icmp_seq=2 ttl=64 time=0.027 ms --- 162.0.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.027/0.046/0.066/0.020 ms
[root@lianhua netns]$ ip netns exec ns1 ip route
162.0.0.0/24 dev veth-ns1-a proto kernel scope link src 162.0.0.1
 
可以看到,veth-pair 实现了从网络命令空间 ns1 到 ns2 的访问。
 
值得注意的是,在真实的 docker 网络模式下 veth-pair 打通的是容器 network namespace 和宿主机 root namespace 之间互相访问的限制,veth-pair 的一头在宿主机,一头在容器中(在容器中的一头会被 docker 更改接口名为 eth0)。

2. 容器网络原理

Docker 容器通过 namespace 做资源隔离,其中通过 network namespace 做网络资源隔离,docker 容器实质上可看作一个 network namespace。基于此,构建容器网络示意图如下:
 
创建网络命名空间 ns5,veth-pair 和网桥 lxcbr1:
[root@lianhua ~]$ ip netns add ns5
[root@lianhua ~]$ ip link add veth5.1 type veth peer name veth5.2
[root@lianhua ~]$ brctl addbr lxcbr1
[root@lianhua ~]$ brctl stp lxcbr1 off
 
将 veth5.2 添加到 ns5 内,veth5.1 连到网桥 lxcbr1:
[root@lianhua ~]$ ip link set veth5.2 netns ns5
[root@lianhua ~]$ ip netns exec ns5 ip link set dev veth5.2 up [root@lianhua ~]$ ip link set dev veth5.1 up
[root@lianhua ~]$ brctl addif lxcbr1 veth5.1
 
在网桥 lxcbr1 上添加 ip,该 ip 将作为 ns5 网络接口的网关:
[root@lianhua ~]$ ifconfig lxcbr1 172.11.0.1/24 up

# 类似 docker 机制,将 veth5.2 改名为 eth0
[root@lianhua ~]$ ip netns exec ns5 ip link set dev veth5.2 down
[root@lianhua ~]$ ip netns exec ns5 ip link set dev veth5.2 name eth0
[root@lianhua ~]$ ip netns exec ns5 ip link set dev eth0 up [root@lianhua ~]$ ip netns exec ns5 ip a
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
312: eth0@if313: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether ea:23:3f:8f:9d:07 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::e823:3fff:fe8f:9d07/64 scope link
valid_lft forever preferred_lft forever
[root@lianhua ~]$ ip netns exec ns5 ifconfig eth0 172.11.0.2/24 up
 
为 network namespace 配置默认路由:
[root@lianhua ~]$ ip netns exec ns5 route add default gw 172.11.0.1
[root@lianhua ~]$ ip netns exec ns5 ip route
default via 172.11.0.1 dev eth0
172.11.0.0/24 dev eth0 proto kernel scope link src 172.11.0.2
 
进入 ns5 内访问宿主机:
[root@lianhua ~]$ ip netns exec ns5 ping 192.168.0.69
PING 192.168.0.69 (192.168.0.69) 56(84) bytes of data.
64 bytes from 192.168.0.69: icmp_seq=1 ttl=64 time=0.041 ms
64 bytes from 192.168.0.69: icmp_seq=2 ttl=64 time=0.026 ms --- 192.168.0.69 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.026/0.033/0.041/0.009 ms

3. 容器到 network namespace 的映射

前面介绍了,容器访问实际上是 network namespace 中 veth 设备的访问。那么我们在真实创建的容器中查看对应的 network namesapce:
[root@lianhua ~]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
459df1132c4b caps1371 "/bin/bash" 6 days ago Up 6 days test2
94a3abcf7e54 caps1371 "/bin/bash" 6 days ago Up 6 days test1
[root@lianhua ~]$ ip netns list
 
宿主机上有两个容器,但是为什么看不到容器对应的 network namespace?
这是因为 ip nets 无法查看 docker 创建的 network namespace,进行如下适配即可看到容器对应的 network namespace。
 
查找容器对应的进程号:
[root@lianhua ~]$ docker inspect --format '{{ .State.Pid }}' test1
43163
[root@lianhua ~]$ docker inspect --format '{{ .State.Pid }}' test2
43265
 
建立容器到 network namespace 的映射:
# 创建 /var/run/netns 目录,ip netns 会查找该目录下的 network namespace
[root@lianhua ~]$ mkdir -p /var/run/netns
[root@lianhua ~]$ ln -s /proc/43163/ns/net /var/run/netns/test1
[root@lianhua ~]$ ln -s /proc/43265/ns/net /var/run/netns/test2
 
show network namespace:
[root@lianhua ~]$ ip netns list
test2 (id: 3)
test1 (id: 2) [root@lianhua ~]$ ip netns exec test1 ip a
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
298: eth0@if299: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:19:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.25.0.2/16 brd 172.25.255.255 scope global eth0
valid_lft forever preferred_lft forever
302: eth1@if303: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:1a:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.26.0.3/16 brd 172.26.255.255 scope global eth1
valid_lft forever preferred_lft forever [root@lianhua ~]$ ip netns exec test2 ip a
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
300: eth0@if301: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:1a:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.26.0.2/16 brd 172.26.255.255 scope global eth0
valid_lft forever preferred_lft forever
 
在 network namespace 中 show 出了容器的网络接口。掌握了 veth-pair,network namespace 和容器的实现机制,那么我们就可以给正在运行的容器添加接口(veth-pair)了。
进一步的,查看 test1 和 test2 的网络 id 是否一致:
[root@lianhua ~]$ ip netns exec test1 ls -la /proc/self/ns/
total 0
...
lrwxrwxrwx 1 root root 0 Jan 12 00:42 net -> net:[4026532403] [root@lianhua ~]$ ip netns exec test2 ls -la /proc/self/ns/
total 0
...
lrwxrwxrwx 1 root root 0 Jan 12 00:42 net -> net:[4026532502]
 
net:[] 中括号内是 network namespace 的 id,相同的 network namespace 具有相同的 id,可以看到 test1 和 test2 的 id 是不一样的,验证了它们处于不同的 network namespace 中。
 
 

容器网络原理分析:veth 和 network namespace的更多相关文章

  1. docker容器网络通信原理分析

    概述 自从docker容器出现以来,容器的网络通信就一直是大家关注的焦点,也是生产环境的迫切需求.而容器的网络通信又可以分为两大方面:单主机容器上的相互通信和跨主机的容器相互通信.而本文将分别针对这两 ...

  2. docker容器网络通信原理分析(转)

    概述 自从docker容器出现以来,容器的网络通信就一直是大家关注的焦点,也是生产环境的迫切需求.而容器的网络通信又可以分为两大方面:单主机容器上的相互通信和跨主机的容器相互通信.而本文将分别针对这两 ...

  3. 第 8 章 容器网络 - 068 - 分析 Calico 的网络结构

    分析 Calico 的网络结构 在 host1 中运行容器 bbox1 并连接到 cal_net1: docker container run --network cal_net1 --name bb ...

  4. spring容器启动原理分析1

    在项目的web.xml中配置 <listener> <listener-class>org.springframework.web.context.ContextLoaderL ...

  5. 【转】理解Docker容器网络之Linux Network Namespace

    原文:理解Docker容器网络之Linux Network Namespace 由于2016年年中调换工作的原因,对容器网络的研究中断过一段时间.随着当前项目对Kubernetes应用的深入,我感觉之 ...

  6. 容器网络——从CNI到Calico

    从容器诞生开始,存储和网络这两个话题就一直为大家津津乐道.我们今天这个环境下讲网络这个问题,其实是因为容器对网络的需求,和传统物理.虚拟环境对网络环境需求是有差别的,主要面临以下两个问题: 过去Iaa ...

  7. Docker容器的原理与实践 (下)

    欢迎访问网易云社区,了解更多网易技术产品运营经验. Docker原理分析 Docker架构 镜像原理 镜像是一个只读的容器模板,含有启动docker容器所需的文件系统结构及内容Docker以镜像和在镜 ...

  8. 一文搞懂 Linux network namespace

    本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. 本文通过 IP ...

  9. 【Networking】容器网络大观 && SDN 资料汇总

    SDNLAB技术分享(十五):容器网络大观   SDNLAB君• 16-06-17 •2957 人围观 编者按:本文系SDNLAB技术分享系列,本次分享来自SDN撕X群(群主:大猫猫)群直播,我们希望 ...

  10. [Kubernetes]浅谈容器网络

    Veth Pair 这部分内容主要介绍一个设备: Veth Pair . 作为一个容器,它可以声明直接使用宿主机的网络栈,即:不开启 Network Namespace .在这种情况下,这个容器启动后 ...

随机推荐

  1. 【笔记整理】使用Session会话保持

    import requests if __name__ == '__main__': # Session对象实现了客户端和服务器端的每次会话保持功能. session = requests.Sessi ...

  2. GPT-4多模态大型语言模型发布

    GPT-4 模型是OpenAI开发的第四代大型语言模型(LLM),它将是一个多模态模型,会提供完全不同的可能性-例如文字转图像.音乐甚至视频.GPT 全称为 Generative Pre-traine ...

  3. 分享.Net 设计模式大全

    由于最近项目处于维护阶段,工作没有那么匆忙了.于是开始回头整理一下常用设计模式. 虽说设计模式大家都知道,但是在写代码过程中为了抓项目进度有时候写着写着就变成面向过程开发了--后面维护起来将会相当的悲 ...

  4. 这些常见的python编码习惯,你都会吗

    本文分享自华为云社区<不得不知的十个常见PY编码习惯>,作者:码乐. 简介 语言在发展和变化,编码习惯也在发生改变.这里简单聊聊 17个python中常见的编码习惯或者风格. 1,可变数据 ...

  5. 防火墙添加允许服务器IP和端口方法

    一.检测防火墙命令 systemctl status firewalld 如果显示如下active表示防火墙开启 ● firewalld.service - firewalld - dynamic f ...

  6. JVM学习-Class文件结构

    文章原文:https://gaoyubo.cn/blogs/844dc0e7.html 一.Class类文件的结构 任何一个Class文件都对应着唯一的一个类或接口的定义信息. 但是反过来说,类或接口 ...

  7. SecSolar:为代码“捉虫”,让你能更专心写代码

    摘要:在"更健壮.更安全"的路上,CloudIDE又迈出了关键的一步:推出了代码安全检测服务SecSolar,以轻量插件的形式,为代码"捉虫",帮助企业和开发者 ...

  8. 华为云SparkRTC面向低时延、大通量传输业务的技术探索

    摘要:网络和移动设备高速发展的今天,人们开始思考如何用更短的时间下载更大的文件,追求更快的速度.当下在稳定的基础上有什么方法可以提升速度呢? 本文分享自华为云社区<华为云SparkRTC面向低时 ...

  9. Gartner 权威预测未来4年网络安全的8大发展趋势

    翻译:SEAL安全 原文标题: Gartner Unveils the Top Eight Cybersecurity Predictions for 2022-23 原文链接: https://ww ...

  10. BitSail“拍了拍”你,并给你一份快速入门指南

    本 Quick Guide 面向 BitSail 新手入门使用人员,从源码编译.产物结构.如何提交作业.实机演示等多方面带领大家迅速入门 BitSail,从 0 到 1 了解并完成 BitSail 基 ...