V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wewin
V2EX  ›  推广

Linux 容器和 Namespace

  •  
  •   wewin · 2020-11-26 13:52:29 +08:00 · 1164 次点击
    这是一个创建于 1218 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如今云原生技术可以说是互联网最火的概念之一,作为云原生技术的重要基石 -- “容器” 技术,想必从业者早有学习并大量的运用在工作和日常开发中。

    假如有人问你 “什么是容器?”, 你的答案是什么?

    容器就是 Docker 吗?它和虚拟化技术有什么区别和联系?它的实现原理又是什么?

    这篇文章主要通过 容器和虚拟化技术的对比,容器和 Linux Namespace 的关系,以及 Namespace 的初体验 三个模块让大家更了解什么是容器,以及容器实现的底层技术支撑 -- Liunx Namespace 。

    容器和虚拟化

    有 Linux 学习经验的同学,想必有使用 VMware 和 VirtualBox 这种软件来安装 Linux 虚拟机的经历。一般是这样的流程,我们先在 windows 机器上安装 VMware 或者 VirtualBox 这类 Hypervisor 虚拟化软件,然后使用这类虚拟化软件将 Linux 的某种发行版镜像安装成为一个 Linux 虚拟机,这样我们就拥有了一个 Linux 操作系统。

    这种虚拟化软件是一种运行在基础物理服务器和操作系统之间的中间软件层,可允许多个操作系统和应用共享硬件,通过这种方式我们得到的虚拟机软硬件、内核一应俱全,可以说是功能完备的操作系统,它和宿主机隔离,我们在操作系统里可以放心大胆的做任何的修改,而不用担心对宿主机造成损害,这中资源的隔离型和功能的相似性,和容器表象上可以说是特别的相似。

    刚开始接触 Linux 容器的我,习惯性的拿容器和虚拟机对比,认为容器就是一种轻量级的虚拟化技术,只是少了硬件资源的虚拟化,外加运行应用程序所必须的最小的文件系统。不知道有多少人也曾有过和我一样的理解,不得不说这种理解确实对刚接触容器时,理解容器有不少的帮助,但是这种说法却是不妥的,因为容器的实现机制和 Hypervisor 这种虚拟化技术是有本质却别的。

    容器和 Namespace

    容器本质上只是 Linux 上运行的特殊的进程,之所以说特殊,是因为它和操作系统上的其他进程环境进行了隔离,就像一个集装箱一样,站在容器里面,只能看到它本身。容器技术的基础是 Linux namespacecgroups 内核特性。

    隔离的特性确保了不同容器进程互不干扰,拥有各自独立的运行环境。我们知道,在操作系统上 PID 这种东西是唯一的,我们无法拥有一个 PID = 1 的进程 A, 同时拥有一个 PID = 1 的进程 B ;端口号也是唯一的,我们无法让多个进程同时监听同一个端口( fork 子进程的特殊方式除外)。我们也无法让操作系统 hostname 为 server1, 同时让 hostname 为 server2 。但是我们可以在容器 A 里存在一个进程他的 PID = 1, 同时容器 B 里也存在一个进程他的 PID 也等于 1,这就是容器隔离性的体现,它自己就是自己的全世界,开辟任意的空间(自己的文件系统),拥有自己的网络设备,拥有自己的 hostname 。

    这种隔离性依靠的就是内核特性 -- Namespace,Namespace 可以让一个进程运行在独立的命名空间中,命名空间里的进程和系统进程相互隔离,不同命名空间中的进程之间相互隔离,所以我们需要了解容器,就需要先了解下 Namespace.

    namespace 是内核 2.4 开始有的特性,namespace 一共有如下几种:

    |Namespace|隔离的资源| |---|---| |Cgroup|Cgroup root directory| |IPC|System V IPC,POSIX message queues| |Network|网络设备,端口| |Mount|挂载点| |PID|进程 ID| |Time|时钟| |User|用户和用户组 ID| |UTS|主机名、域名|

    需要注意的是以上的类型的 namespace 是从内核 2.4 开始逐步加入的,2.4 实现了 mount,2.6 加入了 IPC 、Network 、PID 、和 UTS,User 则是从 2.6 开始出现,但到了 3.8 才宣布完成,Cgroup 则是在 4.6 中才有

    上面我们提到的,不同容器中可以拥有相同的 PID,就是因为 PID 这种隔离特性的 namespace, User 和 UTS 这种隔离特性的 namespace 则可以让同一台主机上的不同容器具有相同的 user id 、group id 和 主机名。Namespace 这种内核特性,就是让一组进程运行在一个独立的空间中,让其和操作系统上的进程隔离。

    namespace 初体验

    相信很多朋友第一次接触 namespace 也是一脸懵逼,没关系,我们可以直接上手对 namespace 来个直观的感受

    以下的操作在 ubuntu16.03 ,内核主动升级到了 5.8.12-050812-generic 的系统中完成的

    开始之前,需要说明的是 Linux 提供了诸如 clone 、setns 、unshare 、ioctl 这些系统调用 API 来实现对 Namespace 和其进程的操作,不过这是后话,本次初体验我们是使用 Linux 中一个和系统调用函数 unshare 同名的命令行工具(它实际上是调用了系统调用 unshare )

    看看它的用法:

    # unshare -h
    
    Usage:
     unshare [options] [<program> [<argument>...]]
    
    Run a program with some namespaces unshared from the parent.
    
    Options:
     -m, --mount[=<file>]      unshare mounts namespace
     -u, --uts[=<file>]        unshare UTS namespace (hostname etc)
     -i, --ipc[=<file>]        unshare System V IPC namespace
     -n, --net[=<file>]        unshare network namespace
     -p, --pid[=<file>]        unshare pid namespace
     -U, --user[=<file>]       unshare user namespace
     -C, --cgroup[=<file>]     unshare cgroup namespace
     -f, --fork                fork before launching <program>
         --mount-proc[=<dir>]  mount proc filesystem first (implies --mount)
     -r, --map-root-user       map current user to root (implies --user)
         --propagation slave|shared|private|unchanged
                               modify mount propagation in mount namespace
     -s, --setgroups allow|deny  control the setgroups syscall in user namespaces
    
     -h, --help                display this help
     -V, --version             display version
    

    UTS Namespace 初体验

    UTS Namespace 可以实现 hostname 和 domainname 的隔离

    # hostname      # 检查当前的 hostname 是 server0
    server0
    # unshare -u /bin/sh      # 创建一个新的进程,并处于 UTS namespace 中 
    # hostname new-hostname      # 修改 hostname
    # hostname      # 当前进程的 hostname 已经改变
    new-hostname
    # exit      # 退出  UTS namespace
    # hostname      # 可以确定原本的 hostname 并未改变
    server0
    

    通过上面的例子我们可以看到 UTS Namespace 的隔离特性,它可以让进程拥有自己独立的 hostname,位于 UTS Namespace 中的进程,修改 hostname 不会影响到主机原本的 hostname.

    PID Namespace 初体验

    PID Namespace 可以实现 PID 的隔离

    # ps -aux |wc -l      # 系统原本的进程数
    146
    # unshare -u /bin/sh     # 没有使用 -p 参数
    # ps -aux |wc -l     # UTS Namespace 没有 pid 的隔离
    147
    # exit
    # unshare -fp --mount-proc /bin/bash     # PID Namespace, --mount-proc 选项以确保外壳程序将在新创建的名称空间中获得 PID 1, -f 标志从 unshare 以下位置派生 shell 
    # ps -aux |wc -l
    4
    

    通过上面的例子,我们特意对比了 UTS 和 PID 两种 namespace,可以更加直观的了解到 PID Namespace 的隔离特性。位于 PID Namespace 中的进程,它可以拥有和主机 PID 重复的进程。

    Network Namespace 初体验

    Network 可以进行网络的隔离

    # ifconfig -a |grep flags  # 原本主机的网卡数量
    br-0218842a6d4f: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
    br-9a4009fc0074: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
    br-ccc197daa6b7: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
    cni0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
    docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
    enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
    enp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
    flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
    lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
    vethb960cbb3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
    vethe6e2d00a: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
    # unshare -n /bin/bash # 启动 Network Namespace
    # ifconfig -a # 启动 Network Namespace 只有 lo 这种网络设备
    lo: flags=8<LOOPBACK>  mtu 65536
            loop  txqueuelen 1000  (Local Loopback)
            RX packets 0  bytes 0 (0.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 0  bytes 0 (0.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    

    通过上例我们可以看到,主机的网卡有多个,而位于 Network Namespace 中的进程只有一个 lo 网卡,网络设备和主机的网路设备进行了隔离。

    通过以上的例子,相信大家对 Namespace 的隔离特性有了很直观的了解,容器技术的隔离性质正是基于 Namespace 这种内核特性实现,是一种内核级别的特性。

    上面通过 unshare 指令我们对 Namespace 有了初步的体验,相信大家对容器的隔离实现也会有了不同的认识。下一个章节,我会用代码的方式操作 Namespace, 让大家对 Namespace 有更加深入的了解,感兴趣的朋友,请关注公众号 “思图邦”,及时接收更新。

    当然我们知道容器除了资源的隔离,还有一大特性是资源的限制,其资源的限制则是依赖于 cgroups 这一内核特性,之后的章节我也会对 cgroups 展开做一个说明,感谢关注。

    公众号:思图邦

    思图邦

    思图邦

    这里两个的二维码是一样的

    感谢大家阅读,如果有问题或需要补充的,请在评论区留言。

    7 条回复    2020-11-27 23:07:13 +08:00
    wewin
        1
    wewin  
    OP
       2020-11-26 13:54:45 +08:00
    欢迎一起交流见解
    julyclyde
        2
    julyclyde  
       2020-11-26 17:32:12 +08:00   ❤️ 1
    wewin
        3
    wewin  
    OP
       2020-11-26 17:49:50 +08:00
    @julyclyde 你是怎么界定这是一条广告的?
    Livid
        4
    Livid  
    MOD
       2020-11-26 22:53:07 +08:00
    @wewin 这个主题已经被移动到 /go/promotions

    请阅读 V2EX 的节点使用规则 https://www.v2ex.com/help/node

    如果持续违规,你的账号将会被禁用。
    Livid
        5
    Livid  
    MOD
       2020-11-26 22:53:27 +08:00
    @julyclyde 谢谢举报。
    julyclyde
        6
    julyclyde  
       2020-11-27 17:52:57 +08:00
    @wewin 恕我冒昧
    我只是举报,并不“界定”

    各人有各自的判断标准
    我觉得长篇大论、设问 /自问自答、技术方面无原创、内容中也没有值得特别注意、大多数人都会忽视而踩坑的点,最后还带个引流的,就属于广告

    最后不带引流但是符合前面几条的,算是没什么意义的重复内容
    wewin
        7
    wewin  
    OP
       2020-11-27 23:07:13 +08:00
    @julyclyde 文章有几个小伙伴收藏了,如果他们不是为了恶心自己而收藏的,我就觉得我写出来是有意义的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3821 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 00:54 · PVG 08:54 · LAX 17:54 · JFK 20:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.