Docker-namespace
namespace
namespace 是 Linux 内核用来隔离内核资源的方式。通过 namespace 可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的资源,这两拨进程根本就感觉不到对方的存在。具体的实现方式是把一个或多个进程相关资源指定在同一个 namespace 中。
Linux namespaces 是对全局系统资源的一种封装隔离,使得处于不同 namespace 的进程拥有独立的全局系统资源,改变一个 namespace 中的系统资源只会影响当前namespace 里的进程,对其他 namespace 中的进程没有影响。
Linux 提供了多个 API 用来操作 namespace,它们是 clone()、 setns() 和 unshare() 函数,为了确定隔离的到底是哪项 namespace,在使用这些 API 时,通常需要指定一些调用参数:CLONE_NEWIPC、 CLONE_NEWNET、 CLONE_NEWNS、CLONE_NEWPID、 CLONE_NEWUSER、 CLONE_NEWUTS 和 CLONE_NEWCGROUP。如果要同时隔离多个 namespace,可以使用 | (按位或)组合这些参数。
namespace | 系统调用参数 | 被隔离的全局系统资源 |
---|---|---|
UTS | CLONE_NEWUTS | 主机名和域名 |
IPC | CLONE_NEWIPC | 信号量、消息队列和共享内存 |
PID | CLONE_NEWPID | 进程编号 |
Network | CLONE_NEWNET | 网络设备、网络栈、端口等 |
Mount | CLONE_NEWNS | 文件系统挂载点 |
User | CLONE_NEWUSER | 用户和用户组 |
以上命名空间在容器环境下的隔离效果:
UTS:每个容器能看到自己的 hostname,拥有独立的主机名和域名。
IPC:同一个 IPC namespace 的进程之间能互相通讯,不同的 IPC namespace 之间不能通信。
PID:每个 PID namespace 中的进程可以有其独立的 PID,每个容器可以有其 PID 为 1 的 root 进程。
Network:每个容器用有其独立的网络设备, IP 地址, IP 路由表, /proc/net 目录,端口号。
Mount:每个容器能看到不同的文件系统层次结构。
User:每个 container 可以有不同的 user 和 group id。
基础命令
dd 命令
dd 可从标准输入或文件中读取数据,根据指定的格式来转换数据,再输出到文件、设备或标准输出。
语法:dd OPTION
参数如下:
- if=文件名:输入文件名,默认为标准输入。即指定源文件。
- of=文件名:输出文件名,默认为标准输出。即指定目的文件。
- ibs=bytes:一次读入 bytes 个字节,即指定一个块大小为 bytes 个字节。obs=bytes:一次输出 bytes 个字节,即指定一个块大小为 bytes 个字节。bs=bytes:同时设置读入/输出的块大小为 bytes 个字节。
- cbs=bytes:一次转换 bytes 个字节,即指定转换缓冲区大小。
- skip=blocks:从输入文件开头跳过 blocks 个块后再开始复制。 seek=blocks:从输出文件开头跳过 blocks 个块后再开始复制。
- count=blocks:仅拷贝 blocks 个块,块大小等于 ibs 指定的字节数。
- conv=<关键字>,关键字可以有以下 11 种:
- conversion:用指定的参数转换文件。
- ascii:转换 ebcdic 为 ascii
- ebcdic:转换 ascii 为 ebcdic
- ibm:转换 ascii 为 alternate ebcdic
- block:把每一行转换为长度为 cbs,不足部分用空格填充
- unblock:使每一行的长度都为 cbs,不足部分用空格填充
- lcase:把大写字符转换为小写字符
- ucase:把小写字符转换为大写字符
- swap:交换输入的每对字节
- noerror:出错时不停止
- notrunc:不截短输出文件
- sync:将每个输入块填充到 ibs 个字节,不足部分用空(NUL)字符补齐
示例:
从 /dev/zero 文件里一次读取8k大小的内容,总共读取1024次,并把每次读取到的数据写入到test1.img文件中。
mkfs
作用:用于在设备上创建 Linux 文件系统,俗称格式化,比如我们使用 U 盘的时候可以格式化。
语法:
mkfs [-V] [-t fstype] [fs-options] filesys [blocks]
常见参数:
- -t fstype:指定要建立何种文件系统;如 ext3, ext4
- filesys :指定要创建的文件系统对应的设备文件名;
- blocks:指定文件系统的磁盘块数。
- -V : 详细显示模式
- fs-options:传递给具体的文件系统的参数。
示例:
mkfs -t ext4 test1.img // 格式化镜像文件为 ext4
mkfs -t ext4 /dev/sda6 // 将sda6分区格式化为 ext4 格式
df
作用:命令用于显示目前在 Linux 系统上的文件系统磁盘使用情况统计。
语法:
df [OPTION]... [FILE]...
常见参数:
-
-a, --all 包含所有的具有 0 Blocks 的文件系统
-
-h, --human-readable 使用人类可读的格式(预设值是不加这个选项的...)
-
-H, --si 很像 -h, 但是用 1000 为单位而不是用 1024
-
-t, --type=TYPE 添加过滤条件,只列出文件系统是 TYPE
-
-T, --print-type 显示文件系统的形式
mount
作用:mount 命令用于加载文件系统到指定的加载点。此命令的也常用于挂载光盘,使我们可以访问光盘中的数据,因为你将光盘插入光驱中, Linux 并不会自动挂载,必须使用 Linux mount 命令来手动完成挂载。
Linux 系统下不同目录可以挂载不同分区和磁盘设备,它的目录和磁盘分区是分离的, 可以自由组合(通过挂载)
不同的目录数据可以跨越不同的磁盘分区或者不同的磁盘设备。
挂载的实质是为磁盘添加入口(挂载点)。
常见用法:
mount [-l]
mount [-t vfstype] [-o options] device dir
常见参数:
-
-l:显示已加载的文件系统列表;
-
-t: 加载文件系统类型支持常见系统类型的 ext3,ext4,iso9660,tmpfs,xfs 等,大部分情况
可以不指定, mount 可以自己识别
-
-o options 主要用来描述设备或档案的挂接方式。
-
loop:用来把一个文件当成硬盘分区挂接上系统
-
ro:采用只读方式挂接设备
-
rw:采用读写方式挂接设备
-
-
device: 要挂接(mount)的设备。
-
dir: 挂载点的目录
示例:
bash
// 将 /dev/hda1 挂在 /mnt 之下。
mount /dev/hda1 /mnt
// 将镜像挂载到/mnt/testext4 下面,需要确保挂载点也就是目录存在
mkdir -p /mnt/testext4
mount ./fdimage.img /mnt/testext4
unshare
作用:unshare 主要能力是使用与父程序不共享的名称空间运行程序。
语法:
unshare [options] program [arguments]
常用参数:
参数 | 含义 |
---|---|
-i, --ipc | 不共享 IPC 空间 |
-m, --mount | 不共享 Mount 空间 |
-n, --net | 不共享 Net 空间 |
-p, --pid | 不共享 PID 空间 |
-u, --uts | 不共享 UTS空间 |
-U, --user | 不共享用户 |
-V,--version | 版本查看 |
--fork | 执行 unshare 的进程 fork 一个新的子进程,在子进程里执行unshare 传入的参数 |
--mount-prot | 执行子进程前,将 proc 有限挂载过去 |
示例:
hostname 隔离
bash
[root@VM-0-11-centos ~]# unshare -u /bin/bash
[root@VM-0-11-centos ~]# hostname test
[root@VM-0-11-centos ~]# hostname
test
[root@VM-0-11-centos ~]# exit
exit
[root@VM-0-11-centos ~]# hostname
VM-0-11-centos
pid 隔离试验
出错是因为如果不建新进程,新的 namespace 会用执行 unshare 命令的进程 的 PID 作为新的空间的父进程,而这个 unshare 进程并不在新的 namespace 中,所以会报个错 Cannot allocate memory。
加上 --fork选项后,还是不能满足要求,通过ps -ef还是可以查看到其他进程的信息
可以通过加上 mount-proc选项, 加上 mount-proc选项是因为 Linux 下的每个进程都有一个对应的 /proc/PID 目录,该目录包含了大量的有关当前进程的信息。 对一个 PID namespace 而言, /proc 目录只包含当前 namespace 和它所有子孙后代 namespace 里的进程的信息。创建一个新的 PID namespace 后,如果想让子进程中的 top、 ps 等依赖 /proc 文件系统的命令工作,还需要挂载 /proc 文件系统。而文件系统隔离是 mount namespace 管理的,所以 linux特意提供了一个选项
--mount-proc 来解决这个问题。如果不带这个我们看到的进程还是系统的进程信息。
执行 ps -ef 查看进程信息,我们可以看到此时进程空间内的内容已经变了,而且启动进程也变成了我们的 bash 进程。说明我们已经看不到主机上的进程空间了,我们的进程空间发生了隔离。
完整pid隔离示例:
unshare --fork --pid --mount-proc /bin/bash
mount 隔离
首先先执行 unshare --mount --fork /bin/bash 或者直接 unshare --mount即可
--fork 选项用于在创建新的命名空间时将新的子进程创建在新的命名空间中。
如果你想要在新的命名空间中执行一些任务,那么使用 --fork 选项可能是有用的。
但是,如果你只是想创建一个新的 mount 命名空间,而不需要在其中运行新的进程,你可以不使用
--fork 选项。
并使用 dd命令创建一个新文件
dd if=/dev/zero of=test.img bs=8k count=10240
并创建一个文件挂载点文件夹
mkdir testmount
最后将镜像挂载到新创建的文件夹下面
mount -t ext4 ./test.img ./testmount
最后通过查看新创建的bash和开启mount中的bash可以发现是存在mount隔离的