【原创】探索容器底层知识之Namespace
一、先谈谈进程
在正式介绍Namespace之前,先介绍下进程,因为容器本质上是进程,但是在介绍进程之前,先理清下“程序”和“进程”的关系,这是IT从业人员在日常工作中经常碰到的两个词汇,举个通俗点的例子帮助大家理解,“程序”可以看成是一张机械图,图上的内容都是手工画上去的,相当于是计算机的输入,在机械图未正式设计出产品的时候,它是静态的,而当工程师按照机械图正式设计各个零部件、组合、啮合到最后产品成型的整个动态过程,可看成是一个进程,因此进程可认为是程序运行起来后的计算机执行环境的总和,是静态程序的具体实现。
二、容器的namespace
在上节中介绍了什么是进程,可通过ps命名查看当前宿主机正在运行的进程,如下图所示
[root@k8s-master James]# ps
PID TTY TIME CMD
pts/ :: su
pts/ :: bash
pts/ :: ps
容器本质上对于Linux操作系统来说,和上述进程一样,但是会在进程上加入了很多namespace来实现进程、挂载点、网络、用户信息之间的隔离,这样容器看上去就像一个沙箱,在沙箱内部只能看到和操作限定namespace下的系统资源,以PID namespace为例,我们先创建1个容器
[root@k8s-master James]# docker run -it -d busybox /bin/sh
01a0fd62d2110e54b0c3635b2897e7c18e6b78f026fa57b4214d7662dd3b38ba
[root@k8s-master James]# docker exec -it 01a0fd62d2110e54b0c3635b2897e7c18e6b78f026fa57b4214d7662dd3b38ba /bin/sh
/ # ps
PID USER TIME COMMAND
1 root 0:00 /bin/sh
6 root 0:00 /bin/sh
11 root 0:00 ps
这条命名的意思是我想启动一个容器执行/bin/bash命令,并分配一个伪终端的交互窗口和容器进行交互,docker run是创建和启动容器的意思,-it表示就是分配一个伪终端的输入和输出交互窗口,busybox是镜像,/bin/bash是操作程序。当创建成功后,输入ps可查看容器中正在运行的进程,可以看到有2个进程,PID代表进程的唯一编号,可以看到1号PID的操作程序为/bin/bash,之前谈到容器也是一种进程,回到宿主机查看下此容器的进程
[root@k8s-master James]# docker container top 01a0fd62d2110e54b0c3635b2897e7c18e6b78f026fa57b4214d7662dd3b38ba
UID PID PPID C STIME TTY TIME CMD
root : pts/ :: /bin/sh
其PID为24691了,此PID在容器中不存在,也就是说容器中只能看到自己程序执行后的进程,而看不到其他容器和宿主机上的进程,且容器里面的进程编号PID也做了障眼法般的处理,与宿主机上的PID不一致,而实现这个技术的就是PID namespace,而容器类似的还有NET、IPC、MNT、UTS、USER的namespace,其对应隔离的内容如下表所示:
namespace | 隔离的内容 |
---|---|
PID | 进程 |
IPC | 信号量、消息队列和共享内容 |
UTS | 主机名、域名 |
NET | 网络设备、网络栈、端口 |
MNT | 文件系统 |
User | 用户和用户组 |
网络相对比较复杂,我们再详细深入看下,从上表可以看出不同的网络命名空间可以隔离网络设备、网络栈、端口等,为了达到这个目标,LINUX系统就需要支持虚拟化网络协议栈的多个实例,且这些独立的协议栈可处于不同的网络命名空间来进行隔离,达到彼此无法进行通信隔离的效果,如果想要不同的网络命名空间设备进行通信,应如何操作呢?答案是:veth设备对,什么是veth设备对,你可以认为是一根管道,一端连接一个网络命名空间的协议栈,另外一端连接另外一个网络命名空间的协议栈来实现通信,那如何建立veth设备对呢?接下来一起操作下
在root用户下,先创建一个网络命名空间
[root@k8s-master zhanglei]# ip netns add net_test1
[root@k8s-master zhanglei]# ip netns list
net_test1
再创建一个设备对veth:
[root@k8s-master zhanglei]# ip link add veth0 type veth peer name veth1
[root@k8s-master zhanglei]# ip link show
: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu qdisc noop state DOWN mode DEFAULT group default qlen
可以看到veth0和veth1的设备对已经生成,veth的设备支持在不同的网络命名空间进行转移,将veth0设备住转移到net_test1命名空间
[root@k8s-master zhanglei]# ip link set veth0 netns net_test1
此时在宿主机上ip link show,因不同的网络命名空间设备是隔离的,且veth0设备已经被移动到net_test1网络命名空间,因此将无法在宿主机网络命名空间再次找到veth0
[root@k8s-master zhanglei]# ip netns exec net_test1 ip link show
: lo: <LOOPBACK> mtu qdisc noop state DOWN mode DEFAULT group default qlen
link/loopback ::::: brd :::::
: tunl0@NONE: <NOARP> mtu qdisc noop state DOWN mode DEFAULT group default qlen
link/ipip 0.0.0.0 brd 0.0.0.0
: veth0@if59: <BROADCAST,MULTICAST> mtu qdisc noop state DOWN mode DEFAULT group default qlen
link/ether :c0::4d:: brd ff:ff:ff:ff:ff:ff link-netnsid
同时我们将另veth1设置到命名空间net_test2里面
[root@k8s-master zhanglei]# ip netns add net_test2
[root@k8s-master zhanglei]# ip netns show
net_test2
net_test1 (id: )
[root@k8s-master zhanglei]# ip link set veth1 netns net_test2
[root@k8s-master zhanglei]# ip netns exec net_test2 ip link show
: lo: <LOOPBACK> mtu qdisc noop state DOWN mode DEFAULT group default qlen
link/loopback ::::: brd :::::
: tunl0@NONE: <NOARP> mtu qdisc noop state DOWN mode DEFAULT group default qlen
link/ipip 0.0.0.0 brd 0.0.0.0
: veth1@if60: <BROADCAST,MULTICAST> mtu qdisc noop state DOWN mode DEFAULT group default qlen
link/ether 7e::da:3a:: brd ff:ff:ff:ff:ff:ff link-netns net_test1
到这里,veth0和veth1这个设备对已经配置在不同的网络命名空间了,但是此时还不能通信,就像电线已经搭好,但是还未通电,谁来扮演通电的角色呢?答案就是:IP
[root@k8s-master zhanglei]# ip netns exec net_test1 ip addr add 10.1.1.1/ dev veth0
[root@k8s-master zhanglei]# ip netns exec net_test2 ip addr add 10.1.1.2/ dev veth1
[root@k8s-master zhanglei]# ip netns exec net_test1 ip link set dev veth0 up
[root@k8s-master zhanglei]# ip netns exec net_test2 ip link set dev veth1 up
[root@k8s-master zhanglei]# ip netns exec net_test1 ping 10.1.1.2
PING 10.1.1.2 (10.1.1.2) () bytes of data.
bytes from 10.1.1.2: icmp_seq= ttl= time=0.097 ms
bytes from 10.1.1.2: icmp_seq= ttl= time=0.061 ms
bytes from 10.1.1.2: icmp_seq= ttl= time=0.032 ms
bytes from 10.1.1.2: icmp_seq= ttl= time=0.024 ms
[root@k8s-master zhanglei]# ip netns exec net_test2 ping 10.1.1.1
PING 10.1.1.1 (10.1.1.1) 56(84) bytes of data.
64 bytes from 10.1.1.1: icmp_seq=1 ttl=64 time=0.030 ms
64 bytes from 10.1.1.1: icmp_seq=2 ttl=64 time=0.090 ms
64 bytes from 10.1.1.1: icmp_seq=3 ttl=64 time=0.032 ms
64 bytes from 10.1.1.1: icmp_seq=4 ttl=64 time=0.033 ms
[root@k8s-master zhanglei]# ip netns exec net_test2 ping 10.1.1.1
PING 10.1.1.1 (10.1.1.1) () bytes of data.
bytes from 10.1.1.1: icmp_seq= ttl= time=0.030 ms
bytes from 10.1.1.1: icmp_seq= ttl= time=0.090 ms
bytes from 10.1.1.1: icmp_seq= ttl= time=0.032 ms
bytes from 10.1.1.1: icmp_seq= ttl= time=0.033 ms
如上,给每个设备配备1个ip地址,配备成功后再启动设备,然后就可以进行相互的通信了,前面提到每个容器拥有自己单独的网络命名空间,而网络命名空间之间的通信是通过设备对,而上面演示的就是命名空间通过设备对进行通信的全过程,
事实上容器之间、容器与宿主机之间都是通过设备对的方式进行通信的,当然实际上容器网络命名空间的创建、设备对的创建、IP的分配并不是手动进行的,都是容器在创建的时候会自动完成,对用户来说是无感知的,这里是方便展示内部原理,采用的手动的形式。
三、总结
本文主要重点介绍了容器PID和NET 命名空间(namespace)的隔离原理,其他namespace的隔离原理类似,容器本质上一种特殊的进程,它虽然提供了隔离技术,但与虚拟机的隔离技术要区别开来,虚拟机是在宿主机上通过Hypervisor虚拟了一个独立的GuestOS,它的隔离是彻底的,虚拟机上的进程在宿主机上无法查看;而容器本质上是宿主机上的进程,它的隔离机制是通过在进程上加入不同的namespace参数来实现资源、文件、设备、状态,或者配置的隔离,两者隔离的本质是有差异的,你或许有个疑问,既然容器是宿主机上的一个进程,而不同的进程可以相互共享宿主机的内核,一旦一个容器的应用逃逸影入侵宿主机,是不是会有可能会影响宿主机或者其他容器应用呢,事实上,的确存在这样的安全隐患,由此看来,容器的隔离性并不像虚拟机般隔离的彻底。
【原创】探索容器底层知识之Namespace的更多相关文章
- centos7下安装docker(10容器底层--cgroup和namespace)
cgroup和namespace是实现容器底层的重要技术 cgroup:实现资源限制 namespace:实现资源隔离 1.cgroup:control group Linux操作系统通过cgroup ...
- C++ 顺序容器基础知识总结
0.前言 本文简单地总结了STL的顺序容器的知识点.文中并不涉及具体的实现技巧,对于细节的东西也没有提及.一来不同的标准库有着不同的实现,二来关于具体实现<STL源码剖析>已经展示得全面细 ...
- 写给Android App开发人员看的Android底层知识(1)
这个系列的文章一共8篇,我酝酿了很多年,参考了很多资源,查看了很多源码,直到今天把它写出来,也是战战兢兢,生怕什么地方写错了,贻笑大方. (一)引言 早在我还是Android菜鸟的时候,有很多技术我都 ...
- 6.Docker容器底层实现了解与安全机制
原文地址: 点击直达 0x00 底层实现 我们以 Docker 基础架构来探究Docke底层的核心技术,简单的包括: Linux 上的命名空间(Namespaces) 控制组(Control grou ...
- 写给Android App开发人员看的Android底层知识(5)
(十)Service Service有两套流程,一套是启动流程,另一套是绑定流程.我们做App开发的同学都应该知道. 1)在新进程启动Service 我们先看Service启动过程,假设要启动的Ser ...
- JS底层知识理解之执行上下文篇
JS底层知识理解之执行上下文篇 一.什么是执行上下文(Execution Context) 执行上下文可以理解为当前代码的执行环境,它会形成一个作用域. 二.JavaScript引擎会以什么方式去处理 ...
- Java底层知识学习:Bytecode and JMM
最近在跟着耗子哥的程序员练级指南学习Java底层知识,结合<深入理解Java虚拟机>这本书在看,写笔记,看资料,成长中…… 目前看完了第二章JMM和各内存区OOM的情况 一篇图文并茂介绍字 ...
- 容器的进程与namespace、rootfs
一:容器是什么 容器的本质是一种特殊的进程. 在linux容器中有三个重要的概念:Namespace.Cgroups.rootfs. Namespace做隔离,让进程只能看到Namespace中的世界 ...
- 极客时间-左耳听风-程序员攻略-Java底层知识
Java 字节码相关 字节码编程,也就是动态修改或是动态生成 Java 字节码.Java 的字节码相当于汇编,其中的一些细节. Java Zone: Introduction to Java Byte ...
随机推荐
- SpringXMl文件不提示的解决方法
applicationContext.xml没有提示的解决方法 1.配置spring-beans-4.1.xsd文件 (1)找到spring-beans-4.1.xsd的文件的位置,例如: (2)复制 ...
- js 读取word和txt(react版) + 正则分割段落
show the code 前提:需要mammoth包~ import React, { useState, useReducer } from 'react'; import { Button, A ...
- Spring学习总结(8)-接口多个实现类的动态调用
需求描述:当一个接口有2个以上的实现类时,调用方需要根据参数选择只其中一个实现类 Spring版本:5.1.8.RELEASE 1. 接口和实现类 /** * 接口 */ public interfa ...
- MyBatis-Plus使用(1)-概述+代码生成器
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发.提高效率而生. 官网:https://mp.baomidou.com ...
- 利用Python操作MySQL数据库
前言 在工作中,我们需要经常对数据库进行操作,比如 Oracle.MySQL.SQL Sever 等,今天我们就学习如何利用Python来操作 MySQL 数据库. 本人环境:Python 3.7.0 ...
- 32-关键字:abstract
abstract: 抽象的 1.可以用来修饰:类.方法 2.具体的:abstract修饰类:抽象类 * > 此类不能实例化 * > 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对 ...
- CF习题集三
CF习题集三 一.CF8C Looking for Order 题目描述 \(Lena\)喜欢秩序井然的生活.一天,她要去上大学了.突然,她发现整个房间乱糟糟的--她的手提包里的物品都散落在了地上.她 ...
- 使用Vscode进行Python开发环境配置
Vscode是是一个强大的跨平台工具,我自己电脑是mac,公司电脑是win而且是内部环境,导致公司安装软件很费劲.好在vscode许多插件能直接离线安装,省去了很多麻烦. 很多人学习python,不知 ...
- 数据洞察 | Python解读地摊——你想好摆摊去卖什么了吗?
知乎上有一个问题:疫情结束后,你最想做的一件事是什么? 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案例的人,却不知道如何去 ...
- Spark Streaming——Spark第一代实时计算引擎
虽然SparkStreaming已经停止更新,Spark的重点也放到了 Structured Streaming ,但由于Spark版本过低或者其他技术选型问题,可能还是会选择SparkStreami ...