这里的 "namespace" 指的是 Linux namespace 技术,它是 Linux 内核实现的一种隔离方案。简而言之,Linux 操作系统能够为不同的进程分配不同的 namespace,每个 namespace 都具有独立的资源分配,从而实现了进程间的隔离。如果你的 Linux 安装了 GCC,可以通过运行 man namespaces
命令来查看相关文档,或者你也可以访问在线手册获取更多信息。
下图为各种 namespace 的参数,支持的起始内核版本,以及隔离内容。
Namespace
系统调用参数
内核版本
隔离内容
UTS (Unix Time-sharing System)
CLONE_NEWUTS
Linux 2.4.19
主机名与域名
IPC (Inter-Process Communication)
CLONE_NEWIPC
Linux 2.6.19
信号量、消息队列和共享内存
PID (Process ID)
CLONE_NEWPID
Linux 2.6.19
进程编号
Network
CLONE_NEWNET
Linux 2.6.24
网络设备、网络栈、端口等等
Mount
CLONE_NEWNS
Linux 2.6.29
挂载点(文件系统)
User
CLONE_NEWUSER
Linux 3.8
用户和用户组
PID Namespace:
Net Namespace:
IPC Namespace:
MNT Namespace:
UTS Namespace:
User Namespace:
涉及到三个系统调用(system call)的 API:
查看当前系统的 namespace
lsns –t
查看某进程的 namespace
ls -la /proc/
进入某 namespace 运行命令
nsenter -t
Test:
# Linux命令行中,可以使用`unshare`命令结合`clone()`创建一个新的进程,并在其中使用命名空间隔离参数。
# 创建一个新的进程,并在其中使用命名空间隔离参数
unshare --pid --net -- sleep 600
ps -ef|grep sleep
root 37915 34572 0 08:53 pts/1 00:00:00 sudo unshare --pid --net -- sleep 600
root 37916 37915 0 08:53 pts/3 00:00:00 sudo unshare --pid --net -- sleep 600
root 37917 37916 0 08:53 pts/3 00:00:00 sleep 600
zhy 37919 37896 0 08:53 pts/2 00:00:00 grep --color=auto sleep
sudo lsns -t net
[sudo] password for zhy:
NS TYPE NPROCS PID USER NETNSID NSFS COMMAND
4026531840 net 277 1 root unassigned /sbin/init
4026532656 net 1 37347 root 0 /run/docker/netns/c986b82be683 bash
4026532718 net 1 37917 root unassigned sleep 600
sudo nsenter -t 37917 -n ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
docker 启动一个 ubuntu
docker run --rm -it docker.m.daocloud.io/ubuntu:22.10 bash
用另一个窗口 找到这个进程
ps -ef|grep ubuntu
查看这个进程的 namespace
ls -la /proc/37247/ns/
total 0
dr-x--x--x 2 zhy zhy 0 May 27 08:24 .
dr-xr-xr-x 9 zhy zhy 0 May 27 08:23 ..
lrwxrwxrwx 1 zhy zhy 0 May 27 08:24 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 zhy zhy 0 May 27 08:24 ipc -> 'ipc:[4026531839]'
lrwxrwxrwx 1 zhy zhy 0 May 27 08:24 mnt -> 'mnt:[4026531841]'
lrwxrwxrwx 1 zhy zhy 0 May 27 08:24 net -> 'net:[4026531840]'
lrwxrwxrwx 1 zhy zhy 0 May 27 08:24 pid -> 'pid:[4026531836]'
lrwxrwxrwx 1 zhy zhy 0 May 27 08:24 pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 zhy zhy 0 May 27 08:24 time -> 'time:[4026531834]'
lrwxrwxrwx 1 zhy zhy 0 May 27 08:24 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 zhy zhy 0 May 27 08:24 user -> 'user:[4026531837]'
lrwxrwxrwx 1 zhy zhy 0 May 27 08:24 uts -> 'uts:[4026531838]'
查看namespace
sudo lsns -t pid
NS TYPE NPROCS PID USER COMMAND
4026531836 pid 275 1 root /sbin/init
4026532654 pid 1 37347 root bash
sudo lsns -t net
NS TYPE NPROCS PID USER NETNSID NSFS COMMAND
4026531840 net 275 1 root unassigned /sbin/init
4026532656 net 1 37347 root 0 /run/docker/netns/c986b82be683 bash
为什么查出来执行 bash
的 pid 和 ps -ef
的不一样?
一个是docker run
的进程 PID
一个是 容器内部 'bash' 进程的 PID 这个进程是由docker run
的进程通过进程复制(process cloning)创建的子进程。
在 ubuntu 中执行 ip addr
在主机执行 nsenter -t <pid> -n ip addr
ip addr
1: lo:
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
11: eth0@if12:
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 08:23 pts/0 00:00:00 bash
root 360 1 0 09:12 pts/0 00:00:00 ps -ef
sudo nsenter -t 37347 -n -- ip addr # -n 进入网络namespace执行
1: lo:
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
11: eth0@if12:
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
sudo nsenter -t 37347 -a -- ps -ef # -a 进入所有namespace执行
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 08:23 pts/0 00:00:00 bash
root 359 0 0 09:12 ? 00:00:00 ps -ef
Linux cgroups 的全称是 Linux Control Groups,它是 Linux 内核的特性,主要作用是限制、记录和隔离进程组(process groups)使用的物理资源(cpu、memory、IO 等)。
可以做到对 cpu,内存等资源实现精细化的控制,容器技术就使用了 cgroups 提供的资源限制能力来完成cpu,内存等部分的资源控制。
subsystem 是一组资源控制的模块,一般包含有:
Cgroup v2手册
是否加载了Cgroup v2内核模块
cat /sys/fs/cgroup/cgroup.controllers
cpuset cpu io memory hugetlb pids rdma misc
执行一段go代码
package main
func main() {
go func() { for{} }()
for {}
}
/*
执行 go run test.go
top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
39268 zhy 20 0 709572 868 584 R 200.0 0.0 2:12.27 test
可以看到使用了2个cpu 因为开个两个goroutine for阻塞
*/
限制cpu
sudo mkdir /sys/fs/cgroup/test
sudo echo "100000 100000" | sudo tee /sys/fs/cgroup/test/cpu.max >/dev/null
sudo echo "39268" | sudo tee /sys/fs/cgroup/test/cgroup.procs >/dev/null
# top
# PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
# 39268 zhy 20 0 709572 868 584 R 100.3 0.0 7:45.04 test
# 马上就只占用一个cpu了
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define BLOCK_SIZE (100 * 1024 * 1024)
#define NUM_ALLOCATIONS 10
#define SLEEP_SECONDS 30
char* allocMemory(int size) {
char* out = (char*)malloc(size);
memset(out, 'A', size);
return out;
}
int main() {
int i;
for (i = 1; i <= NUM_ALLOCATIONS; i++) {
char* block = allocMemory(i * BLOCK_SIZE);
printf("Allocated memory block of size %dMB at address: %p\n", i * 100, block);
sleep(SLEEP_SECONDS);
}
return 0;
}
/*
ps -p 3243 -o rss=,unit=M,cmd=
M
308512 session-4.scope ./test2
*/
限制内存
sudo echo "300000000" |sudo tee /sys/fs/cgroup/test/memory.max >/dev/null
sudo echo "64417" | sudo tee /sys/fs/cgroup/test/cgroup.procs >/dev/null
#cat memory.current
#299839488
联合文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下 (unite several directories into a single virtual filesystem)。
联合文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
另外,不同 Docker 容器就可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率。
最新版 Docker 使用的是 overlay2。
现在主流基本都是 overlayFS
OverlayFS 属于文件级的存储驱动,包含了最初的 Overlay 和更新更稳定的 overlay2。
Overlay 只有两层:upper 层和 lower 层,Lower 层代表镜像层,upper 层代表容器可写层。
mkdir test && cd test
mkdir upper lower merged work
echo "file1 from lower" > lower/file1.txt
echo "file2 from lowerr" > lower/file2.txt
echo "file3 from lower" > lower/file3.txt
echo "file2 from upper" > upper/file2.txt
echo "file4 from upper" > upper/file4.txt
current_dir=$(pwd)
sudo mount -t overlay -o lowerdir="$current_dir/lower",upperdir="$current_dir/upper",workdir="$current_dir/work" overlay "$current_dir/merged"
cat merged/file1.txt
file1 from lower
cat merged/file2.txt
file2 from upper
cat merged/file3.txt
file3 from lower
cat merged/file4.txt
file4 from upper
每一条指令是一层, 下层可以共用
典型的Linux文件系统组成如下:
Bootfs(引导文件系统)
Rootfs(根文件系统)
Linux
Docker 启动
由于镜像具有共享特性,所以对容器可写层的操作需要依赖存储驱动提供的写时复制和用时分配机制,以此来 支持对容器可写层的修改,进而提高对存储和内存资源的利用率。
写时复制 即 Copy-on-Write。
用时分配
按需分配空间,而非提前分配,即当一个文件被创建出来后,才会分配空间。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章