Network namespace 在逻辑上是网络堆栈的一个副本,它有自己的路由、防火墙规则和网络设备。默认情况下,子进程继承其父进程的 network namespace。也就是说,如果不显式创建新的 network namespace,所有进程都从 init 进程继承相同的默认 network namespace。

每个新创建的 network namespace 默认有一个本地环回接口 lo,除此之外,所有的其他网络设备(物理/虚拟网络接口,网桥等)只能属于一个 network namespace。每个 socket 也只能属于一个 network namespace。

说明:本文的演示环境为 ubuntu 16.04。

ip netns 命令
ip netns 命令用来管理 network namespace。本文将使用 ip netns 命令来创建和操作 network namespace。有关 ip netns 命令的详细介绍请参考笔者的博文《Linux ip netns 命令》。

创建 network namespace

我们先查一下看默认的 network namespace 的 ID:

$ readlink /proc/$$/ns/net

然后通过 ip netns add 命令创建名为 mynet 的 network namespace:

$ sudo ip netns add mynet

从上图可以看出,在名为 mynet 的 network namespace 创建成功后,/var/run/netns 目录下多了一个名为 mynet 文件。ip netns exec 子命令可以在对应的 network namespace 中执行命令,下面我们就通过它在 mynet network namespace 中创建一个 bash 进程,并查看 network namespace 的 ID:

$ sudo ip netns exec mynet bash
# readlink /proc/$$/ns/net

这是一个完全不同的 network namespace ID,说明当前的 bash 进程运行在一个隔离的 network 环境中。接下来让我们看看新的 network namespace 中都有什么:

# ip addr

每个新创建的 network namespace 默认有一个本地环回接口 lo,并且这个接口是处于关闭状态的。下面我们就启动这个接口:

# ip link set lo up

启动 lo 接口后我们可以看到其 IP 地址,并且能够正确的响应 ping 命令。

在两个 network namespace 之间通信

network namespace 之间是相互隔离的,我们可以使用 veth 设备把两个 network namespace 连接起来进行通信。veth 设备是虚拟的以太网设备。它们可以充当 network namespace 之间的通道,也可以作为独立的网络设备使用。veth 设备总是被成对的创建,并且这一对设备总是连接在一起的,所以一般把称之为 veth pair。需要注意的是,veth pair 无法单独存在,删除其中一个,另一个也会自动消失。接下来的示例我们就演示如何使用 veth pair 在两个 network namespace 直接通信。示例中我们使用 ip link 命令来创建和管理 veth pair。

第一步,先创建两个 network namespace net0 和 net1

$ sudo ip netns add net0
$ sudo ip netns add net1

第二步,创建一对命名的 veth 设备
默认情况下会自动为 veth pair 生成名称,这里为了易于辨识,我们在创建时指定 veth pair 的名称:

$ sudo ip link add vethmother type veth peer name vethfather

如图所示,veth pair 在主机上表现为两个网卡。

第三步,把这一对 veth pair 分别放到 network namespace net0 和 net1中

$ sudo ip link set vethmother netns net0
$ sudo ip link set vethfather netns net1
$ sudo ip netns exec net0 ip addr
$ sudo ip netns exec net1 ip addr

查看 net0 和 net1 中的网络资源,发现各自多了一个网卡,也就是 veth 设备的两个端点。注意,当我们把 veth pair 分配到 network namespace 中后,在主机上就看不到它们了:

此时主机的网卡中已经看不到刚才的 veth pair 身影了。

第四步,给这些 veth pair 分配 IP 并启用它们

$ sudo ip netns exec net0 ip link set vethmother up
$ sudo ip netns exec net0 ip addr add 10.0.1.1/ dev vethmother
$ sudo ip netns exec net0 ip route

$ sudo ip netns exec net1 ip link set vethfather up
$ sudo ip netns exec net1 ip addr add 10.0.1.2/ dev vethfather
$ sudo ip netns exec net1 ip route

下面通过 ping 命令来验证两个 network namespace 是否可以通信:

$ sudo ip netns exec net0 ping -c  10.0.1.2

至此,我们构建了一个如下结构的虚拟网络:

通过 bridge 连接 network namespace

虽然 veth pair 可以实现两个 network namespace 之间的通信,但是当需要在多个 network namespace 之间通信的时候,光靠 veth pair 就不行了。我们可以使用 Linux 提供的虚拟交换机,来完成这样的功能。下面的示例演示如何通过虚拟交换机(这里就是一个虚拟网桥)连接多个 network namespace。

第一步,先添加一个叫 mybridge0 的网桥

$ sudo ip link add mybridge0 type bridge
$ sudo ip link set dev mybridge0 up
$ sudo ip addr

对主机来说其实就是新添加了一个网络接口(network interface):

第二步,创建 network namespace 和 veth 设备
创建 network namespace net0:

$ sudo ip netns add net0

创建 veth 设备:

$ sudo ip link add veth0 type veth peer name veth0p 

把其中的一个 veth 放置到 net0 中,设置 IP 并启动它:

$ sudo ip link set dev veth0p netns net0
$ sudo ip netns exec net0 ip link set dev veth0p name eth0
$ sudo ip netns exec net0 ip addr add 10.0.1.1/ dev eth0
$ sudo ip netns exec net0 ip link set dev eth0 up
$ sudo ip netns exec net0 ip addr

上图显示 network namespace net0 中的 eth0 网卡已经启动了。下面把 veth 设备的另一端连接到网桥 mybridge0 上:

$ sudo ip link set dev veth0 master mybridge0
$ sudo ip link set dev veth0 up

第三步,重复第二步创建 net1 和 net2,并连接到网桥
给 mybridge0 设置 IP:

$ sudo ip link set dev mybridge0 down
$ sudo ip addr add 10.0.1.0/ dev mybridge0
$ sudo ip link set dev mybridge0 up
$ ip addr

通过 bridge link 命令查看网桥的信息如下:

这时就可以在不同的 network namespace 之间通信了:

$ sudo ip netns exec net0 ping -c  10.0.1.3

我们创建的网络拓扑结构如下所示:

总结

通过 network namespace 可以创建相互独立的网络栈,从而实现网络的隔离。本文只是简单的介绍了 network namespace 的创建以及如何在 network namespace 之间通信,其中 network namespace 之间通过 bridge 通信的方式已经与 docker 网络的 bridge 模式非常类似了。

参考:
Network namespace man page
Linux Namespace系列(06):network namespace (CLONE_NEWNET)
Network namespace 简介

Linux Namespace : Network的更多相关文章

  1. 理解Docker(3):Docker 使用 Linux namespace 隔离容器的运行环境

    本系列文章将介绍Docker的有关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...

  2. Docker之Linux Namespace

    Linux Namespace 介绍 我们经常听到说Docker 是一个使用了Linux Namespace 和 Cgroups 的虚拟化工具,但是什么是Linux Namespace 它在Docke ...

  3. Docker基础技术:Linux Namespace(下)

    在 Docker基础技术:Linux Namespace(上篇)中我们了解了,UTD.IPC.PID.Mount 四个namespace,我们模仿Docker做了一个相当相当山寨的镜像.在这一篇中,主 ...

  4. Docker基础技术:Linux Namespace(上)

    时下最热的技术莫过于Docker了,很多人都觉得Docker是个新技术,其实不然,Docker除了其编程语言用go比较新外,其实它还真不是个新东西,也就是个新瓶装旧酒的东西,所谓的The New “O ...

  5. Docker 基础技术:Linux Namespace(下)

    导读 在Docker基础技术:Linux Namespace(上篇)中我们了解了,UTD.IPC.PID.Mount 四个namespace,我们模仿Docker做了一个相当相当山寨的镜像.在这一篇中 ...

  6. Docker 基础技术之 Linux namespace 详解

    Docker 是"新瓶装旧酒"的产物,依赖于 Linux 内核技术 chroot .namespace 和 cgroup.本篇先来看 namespace 技术. Docker 和虚 ...

  7. Docker 基础技术之 Linux namespace 源码分析

    上篇我们从进程 clone 的角度,结合代码简单分析了 Linux 提供的 6 种 namespace,本篇从源码上进一步分析 Linux namespace,让你对 Docker namespace ...

  8. Linux Namespace : UTS

    UTS namespace 用来隔离系统的 hostname 以及 NIS domain name.UTS 据称是 UNIX Time-sharing System 的缩写. hostname 与 N ...

  9. Linux Namespace : 简介

    在初步的了解 docker 后,笔者期望通过理解 docker 背后的技术原理来深入的学习和使用 docker,接下来的几篇文章简单的介绍下 linux namespace 的概念以及基本用法. na ...

随机推荐

  1. python线程同步原语--源码阅读

    前面两篇文章,写了python线程同步原语的基本应用.下面这篇文章主要是通过阅读源码来了解这几个类的内部原理和是怎么协同一起工作来实现python多线程的. 相关文章链接:python同步原语--线程 ...

  2. 编写寄宿于windows服务的WCF服务

    由于业务中有些任务需要在后台静默长期运行,或者有些服务队响应的要求比较苛刻,这样的WCF服务就不适合寄宿于IIS中.IIS每隔一段时间w3wp进程会闲置超时,造成服务的运行停止,因此这种耗时或者定时任 ...

  3. SQL Server 2012还原一直卡在ASYNC_IO_COMPLETION浅析

    在SQL Server 2012(11.0.7001.0)下面在还原一个数据库(备份文件40多G大小,实际数据库大小300G),在还原过程中,出现一直等待ASYNC_IO_COMPLETION,如下测 ...

  4. Percona XtraBackup 备份还原篇

    Percona XtraBackup 安装介绍篇已经对Percona XtraBackup的功能和安装做了比较详细的介绍,那么本篇我们直接进入主题,如何使用XtraBackup做备份.还原,下面主要介 ...

  5. A Java Runtime Environment (JRE) or Java Development Kit (JDK) must be available in order to run Eclipse. No Java virtual machine was found after searching the following locations: /usr/local/eclipse/

    linux系统下jdk是已经安装好的情况之下软件出现 A Java Runtime Environment (JRE) or Java Development Kit (JDK) must be av ...

  6. [20180822]session_cached_cursors与子游标堆0.txt

    [20180822]session_cached_cursors与子游标堆0.txt --//前几天测试刷新共享池与父子游标的问题,--//链接: http://blog.itpub.net/2672 ...

  7. ping百度域名时的收获

    ping百度 你会发现ping www.baidu.com的时候,会转为ping www.a.shifen.com.但是ping baidu.com的时候却是普通的ip地址,而且ip地址还会变化.那么 ...

  8. 详解 JSONP跨域请求的实现

          跨域问题是由于浏览器为了防止CSRF攻击(Cross-site request forgery跨站请求伪造),避免恶意攻击而带来的风险而采取的同源策略限制.当一个页面中使用XMLHTTPR ...

  9. 【C编程基础】C程序常用函数

    基础知识 1.const const 修饰的数据类型是指常类型,常类型的变量或对象的值是不能被更新的. ; 或 ; //在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再改变它了 ...

  10. ES5-ES6-ES7_字符串与JOSN格式的数据相互转换以及深度克隆新对象

    这篇文章主要来讲HTML5中的新方法:parse()把字符串转换成josn格式的数据和stringify()把josn格式的数据转换成字符串 eval()方法的回顾 eval()方法可以将任何字符串解 ...