容器基础(二): 使用Namespace进行边界隔离
Linux Namespace
容器技术可以认为是一种沙盒(sandbox), 为了实现沙盒/容器/应用间的隔离,就需要一种技术来对容器界定边界,从而让容器不至于互相干扰。当前使用的技术就是Namespace。Namespace定义如下:
Namespace是Linux 内核用来隔离内核资源的方式, 是对全局系统资源的一种封装隔离,使得处于不同namespace的进程拥有独立的全局系统资源,改变一个namespace中的系统资源只会影响当前namespace里的进程,对其他namespace中的进程没有影响。
目前, Linux内核里面实现了7种不同类型的namespace:
名称 宏定义 隔离内容
Cgroup CLONE_NEWCGROUP Cgroup root directory (since Linux 4.6)
IPC CLONE_NEWIPC System V IPC, POSIX message queues (since Linux 2.6.)
Network CLONE_NEWNET Network devices, stacks, ports, etc. (since Linux 2.6.)
Mount CLONE_NEWNS Mount points (since Linux 2.4.)
PID CLONE_NEWPID Process IDs (since Linux 2.6.)
User CLONE_NEWUSER User and group IDs (started in Linux 2.6. and completed in Linux 3.8)
UTS CLONE_NEWUTS Hostname and NIS domain name (since Linux 2.6.)
和namespace相关的函数有三个:
clone: 创建一个新的进程并把他放到新的namespace中
int clone(int (*child_func)(void *), void *child_stack
, int flags, void *arg); flags:
指定一个或者多个上面的CLONE_NEW*(当然也可以包含跟namespace无关的flags),
这样就会创建一个或多个新的不同类型的namespace, 并把新创建的子进程加入新创建的这些namespace中。
setns: 将当前进程加入到已有的namespace中
int setns(int fd, int nstype); fd:
指向/proc/[pid]/ns/目录里相应namespace对应的文件,
表示要加入哪个namespace nstype:
指定namespace的类型(上面的任意一个CLONE_NEW*):
. 如果当前进程不能根据fd得到它的类型,如fd由其他进程创建,并通过UNIX domain socket传给当前进程,那么就需要通过nstype来指定fd指向的namespace的类型
. 如果进程能根据fd得到namespace类型,比如这个fd是由当前进程打开的,那么nstype设置为0即可
unshare: 使当前进程退出指定类型的namespace,并加入到新创建的namespace(相当于创建并加入新的namespace)
int unshare(int flags); flags:
指定一个或者多个上面的CLONE_NEW*, 这样当前进程就退出了当前指定类型的namespace并加入到新创建的namespace
clone和unshare的功能都是创建并加入新的namespace, 他们的区别是:
> unshare是使当前进程加入新的namespace
> clone是创建一个新的子进程,然后让子进程加入新的namespace,而当前进程保持不变
简单的示例程序如下,clone时指定CLONE_NEWIPC/CLONE_NEWPID等参数, 由于没有自定义文件系统, 这个示例程序不使用chroot/pivot_root:
➜ cat namespace.c
#define _GNU_SOURCE
#include <sched.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/mount.h> #define CHECK_EXIST(ret_val, error_msg) \
do { \
if (ret_val == -) { \
perror(error_msg); \
exit(-); \
} \
} while () static int child_func(void *hostname) {
// set hostname
CHECK_EXIST(sethostname((char *)hostname, strlen((char *)hostname)), "sethostname"); // 挂载proc, 后续ps命令则只能看到自身进程
CHECK_EXIST(mount("proc", "/proc", "proc", , NULL), "mount-proc"); // exec /bin/bash and wait input
CHECK_EXIST(execlp("bash", "bash", (char *) NULL), "execlp"); return ;
} //子进程的栈空间
static char s_child_stack[ * ]; int main(int argc, char *argv[]) {
pid_t child_pid; if (argc < ) {
printf("Usage: %s <child-hostname>\n", argv[]);
return -;
} /*
* 创建并启动子进程并传入hostname给子进程
*
* flags参数如下:
* 设置CLONE_NEWPID设置pid namespace
* 设置CLONE_NEWUTS设置新的UTS namespace,
* 设置子进程退出后返回给父进程的信号为SIGCHLD, 跟namespace无关
*/
child_pid = clone(
child_func,
//栈是从高位向低位增长,所以这里要指向高位地址
s_child_stack + sizeof(s_child_stack),
CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWIPC | SIGCHLD,
argv[]); CHECK_EXIST(child_pid, "clone"); waitpid(child_pid, NULL, ); return ;
}
➜
从结果来看:
指定CLONE_NEWPID, 然后子进程挂载proc,子进程里面就只能看到自己的进程,且第一个bash的pid=1;
指定CLONE_NEWIPC, 父子进程的IPC也被隔离了;
➜ ipcs -q
--------- 消息队列 -----------
键 msqid 拥有者 权限 已用字节数 消息
➜ ipcmk -Q
消息队列 id:0
➜ ipcs -q
--------- 消息队列 -----------
键 msqid 拥有者 权限 已用字节数 消息
0x34d432ae 0 root 644 0 0
➜ ./namespace sdocker
root@sdocker:/home/jason/demo/namespace# hostname
sdocker
root@sdocker:/home/jason/demo/namespace# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 00:39 pts/0 00:00:00 bash
root 3 1 0 00:39 pts/0 00:00:00 ps -ef
root@sdocker:/home/jason/demo/namespace# ipcs -q
--------- 消息队列 -----------
键 msqid 拥有者 权限 已用字节数 消息
root@sdocker:/home/jason/demo/namespace# exit
exit
➜ ipcs -q
--------- 消息队列 -----------
键 msqid 拥有者 权限 已用字节数 消息
0x34d432ae 0 root 644 0 0
➜
容器基础(二): 使用Namespace进行边界隔离的更多相关文章
- C++ 顺序容器基础知识总结
0.前言 本文简单地总结了STL的顺序容器的知识点.文中并不涉及具体的实现技巧,对于细节的东西也没有提及.一来不同的标准库有着不同的实现,二来关于具体实现<STL源码剖析>已经展示得全面细 ...
- docker容器基础
一.docker容器基础6种名称空间:UTS.MOunt.IPC.PID.User.Net (1) Linux Namespaces:namespace 系统调用参数 隔离内容 内核版本 UTS ...
- 容器的进程与namespace、rootfs
一:容器是什么 容器的本质是一种特殊的进程. 在linux容器中有三个重要的概念:Namespace.Cgroups.rootfs. Namespace做隔离,让进程只能看到Namespace中的世界 ...
- 【原创】探索容器底层知识之Namespace
一.先谈谈进程 在正式介绍Namespace之前,先介绍下进程,因为容器本质上是进程,但是在介绍进程之前,先理清下“程序”和“进程”的关系,这是IT从业人员在日常工作中经常碰到的两个词汇,举个通俗点的 ...
- Bootstrap <基础二十九>面板(Panels)
Bootstrap 面板(Panels).面板组件用于把 DOM 组件插入到一个盒子中.创建一个基本的面板,只需要向 <div> 元素添加 class .panel 和 class .pa ...
- Bootstrap <基础二十二>超大屏幕(Jumbotron)
Bootstrap 支持的另一个特性,超大屏幕(Jumbotron).顾名思义该组件可以增加标题的大小,并为登陆页面内容添加更多的外边距(margin).使用超大屏幕(Jumbotron)的步骤如下: ...
- Bootstrap<基础二> 网格系统
Bootstrap 提供了一套响应式.移动设备优先的流式网格系统,随着屏幕或视口(viewport)尺寸的增加,系统会自动分为最多12列. 什么是网格(Grid)? 摘自维基百科: 在平面设计中,网格 ...
- 2、JavaScript 基础二 (从零学习JavaScript)
11.强制转换 强制转换主要指使用Number.String和Boolean三个构造函数,手动将各种类型的值,转换成数字.字符串或者布尔值. 1>Number强制转换 参数为原始类型值的转换规 ...
- day 66 Django基础二之URL路由系统
Django基础二之URL路由系统 本节目录 一 URL配置 二 正则表达式详解 三 分组命名匹配 四 命名URL(别名)和URL反向解析 五 命名空间模式 一 URL配置 Django 1.11 ...
随机推荐
- mask r-cnn
mask R-cnn, kaiming he的新作.可以同时完成object detection和segmentation,还可以做pose estimation,简直就是功能多多啊.在coco上测试 ...
- 03-UI控件浏览
UI控件浏览 可能用得上的UI控件 为了便于开发者打造各式各样的优秀app,UIKit框架提供了非常多功能强大又易用的UI控件 下面列举一些在开发中可能用得上的UI控件(红色表明最常用,蓝色代表一般, ...
- 牛客小白月赛2 H 武 【Dijkstra】
链接:https://www.nowcoder.com/acm/contest/86/H来源:牛客网 题目描述 其次,Sεlιнα(Selina) 要进行体力比武竞赛. 在 Sεlιнα 所在的城市, ...
- [vijos p1028] 魔族密码
描述 风之子刚走进他的考场,就……花花:当当当当~~偶是魅力女皇——花花!!^^(华丽出场,礼炮,鲜花)风之子:我呕……(杀死人的眼神)快说题目!否则……-_-###花花:……咦~~好冷~~我们现在要 ...
- 浅谈PHP中的数组和JS中的数组
最近在做前后端对接的时候,遇到一个问题,前端要求返回的数据格式是左边的,但是我通过json_encode返回到的数据格式是右边的 注意:数据格式从"[]"(数组)变成了&quo ...
- JS下载文件常用的方式
下载附件(image,doc,docx, excel,zip,pdf),应该是实际工作中经常遇到一个问题:这里使用过几种方式分享出来仅供参考; 初次写可能存在问题,有问题望指出 主要了解的几个知识 ...
- float 浮动详解
浮动(float):浮动原先设定时主要是用于文本环绕图像设定的,后来发现其在css布局中有很大的帮助,故渐渐使用浮动. 浮动后的元素脱离了文档的普通流,使得浮动的元素不占据文档的位置,其他元素可以覆盖 ...
- laravel EncryptCookies中间件导致无法获取自定义cookie
解决办法: \app\Http\Middleware\EncryptCookies.php 添加过滤cookie key protected $except = [ 'token' ];
- Linux系统完整安装在虚拟机Mini
打开VMware Workstation虚拟机,然后如下图一步到位: 此处只是简单的安装Linux系统,要想查看安装后的IP等配置看: https://www.cnblogs.com/gentle-a ...
- <Docker学习>2.Centos7安装docker
Docker CE 支持 64 位版本 CentOS 7,并且要求内核版本不低于 3.10. CentOS 7 满足最低内核的要求,但由于内核版本比较低,部分功能(如 overlay2 存储层驱动)无 ...