#云原生征文#Docker使用Linux内核的技术分析

网友投稿 235 2022-10-19

#云原生征文#Docker使用Linux内核的技术分析

@[toc](目录

一、Docker简介

Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。Docker 包括三个基本概念:镜像(Image):Docker 镜像(Image),就相当于是一个 root 文件系统。容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。

二、什么是容器

三、什么是Docker

Docker实际上是一家公司,Docker是公司的一个容器管理产品。Docker的使用是安装一个Docker引擎,安装完Docker引擎之后,就可以在容器中配置应用运行所需的依赖环境,接着安装App就可以运行起来了运行起来了。

四、Docker的基本原理

Docker是一个开源的软件项目,让用户程序部署在一个相对隔离的环境运行,借此在Linux操作系统上提供一层额外的抽象,以及操作系统层虚拟化的自动管理机制。需要额外指出的是,Docker并不等于容器(containers),Docker只是容器的一种,其他的种类的容器还有Kata container,Rocket container等等Docker利用Linux中的核心分离机制,例如Cgroups,以及Linux的核心Namespace(名字空间)来创建独立的容器。一句话概括起来Docker就是利用Namespace做资源隔离,用Cgroup做资源限制,利用Union FS做容器文件系统的轻量级虚拟化技术。Docker容器的本质还是一个直接运行在宿主机上面的特殊进程,看到的文件系统是隔离后的,但是操作系统内核是共享宿主机OS,所以说Docker是轻量级的虚拟化技术。

五、Linux Namespaces

Linux Namespace 是Linux 提供的一种内核级别环境隔离的方法,使其中的进程好像拥有独立的操作系统环境。Linux Namespace 有 Mount Namespace,UTS Namespace, IPC Namespace, PID Namespace, Network Namespace, User Namespace, Cgroup Namespace。

分类 系统调用参数 隔离内容
Mount Namespace CLONE_NEWNS 文件系统挂载点
UTS Namespace CLONE_NEWUTS Hostname和domain name
IPC Namespace CLONE_NEWIPC 进程间通信方式,例如消息队列
PID Namespace CLONE_NEWPID 进程ID编号
Network Namespace CLONE_NEWNET 网络设备,协议栈,路由表,防火墙规则,端口等
User Namespace CLONE_NEWUSER 用户及组ID
Cgroup Namespace CLONE_NEWCGROUP Cgroup根目录

上述系统调用参数CLONE_NEWNS等主要应用于以下三个系统调用:

1.clone

#define _GNU_SOURCE #include #include #include #include #include #include #include #define CLONE_FAILURE -1 #define CLONE_SUCCESS 0 #define ERR_RETURN(msg, ret_val) \ do { \ perror(msg); return ret_val; \ } while (0) static int childFunc(void *arg) { struct utsname uts; if (sethostname(arg, strlen(arg)) == -1) { ERR_RETURN("sethostname", CLONE_FAILURE); } if (uname(&uts) == -1) { ERR_RETURN("uname", CLONE_FAILURE); } printf("uts.nodename in child: %s\n", uts.nodename); /* Keep the namespace open for a while, by sleeping. This allows some experimentation--for example, another process might join the namespace. */ sleep(2); return 0; /* Child terminates now */ } #define STACK_SIZE (1024 * 1024) /* Stack size for cloned child */ int main(int argc, char *argv[]) { char *stack; /* Start of stack buffer */ char *stackTop; /* End of stack buffer */ pid_t pid; struct utsname uts; if (argc < 2) { fprintf(stderr, "Usage: %s \n", argv[0]); return CLONE_FAILURE; } /* Allocate stack for child */ stack = malloc(STACK_SIZE); if (stack == NULL) { ERR_RETURN("malloc", CLONE_FAILURE); } stackTop = stack + STACK_SIZE; /* Assume stack grows downward */ /* Create child that has its own UTS namespace; child commences execution in childFunc() */ // 注意第3个参数 pid = clone(childFunc, stackTop, CLONE_NEWUTS | SIGCHLD, argv[1]); if (pid == -1) { ERR_RETURN("clone", CLONE_FAILURE); } printf("clone() returned %ld\n", (long) pid); /* Parent falls through to here */ sleep(1); /* Give child time to change its hostname */ /* Display hostname in parent's UTS namespace. This will be different from hostname in child's UTS namespace. */ if (uname(&uts) == -1) { ERR_RETURN("uname", CLONE_FAILURE); } printf("uts.nodename in parent: %s\n", uts.nodename); if (waitpid(pid, NULL, 0) == -1) { /* Wait for child */ ERR_RETURN("waitpid", CLONE_FAILURE); } printf("child has terminated\n"); return CLONE_FAILURE; }

代码编译运行结果:

test$ gcc clone.c test$ sudo ./a.out hello clone() returned 45468 uts.nodename in child: hello uts.nodename in parent: Box child has terminated

2.unshare

int unshare(int flags) 使进程脱离某个Namespace,flags参数和clone的用法一致。

3.setns

int setns(int fd, int nstype) 使进程进入某个已经存在的Namespace。经常用于从宿主机进入已经启动的容器Network Namespace,然后设置它的网络。

六、Linux Cgroups

Docker 容器运行起来是一个直接运行在宿主机上面的进程,那么如果限定每个容器最多消耗多少CPU资源呢?如果一个容器疯狂的消耗资源岂不是会影响同一宿主机上面其他的容器?所以Docker就需要一个限制容器能够使用资源上限的机制,那就是Linux Cgroup技术。Linux Cgroup 全称是Linux Control Group。它最主要的作用是限制一个进程组能够使用的资源上限,包括CPU,MEM,DISK,NET等等。

1.编写一个计算密集型的程序:

#include "stdio.h" #include "stdlib.h" #include "time.h" int main(int argc, char *argv[]){ long long i = 0; clock_t start_time; clock_t finish_time; clock_t real_time; float current_time; float program_time; start_time=clock(); current_time=(float)start_time / CLOCKS_PER_SEC; printf("Program start time: %f\n",current_time); for(i = 0;i < 1024 * 1024 * 16;i++){ real_time=clock(); current_time=((float)real_time / CLOCKS_PER_SEC); } finish_time=clock(); current_time=(float)finish_time/CLOCKS_PER_SEC; printf("Program finish time:%f\n",current_time); program_time=(float)(finish_time-start_time)/CLOCKS_PER_SEC; printf("Program complete time: %f\n",program_time); return 0; }

2.使用cgroups之前

编译运行程序:

test$ gcc main.c -o main test$ ./main &

top命令查看:

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 45561 weimin 20 0 2496 576 512 R 100.0 0.0 3:06.87 main

CPU占有率100%程序运行时间:Program complete time: 3.908352

3.使用cgroup之后

test$ sudo mkdir /sys/fs/cgroup/cpu/hello_cpu

创建后,系统会自动生成一堆文件:

test$ ll /sys/fs/cgroup/cpu/hello_cpu/ total 0 drwxr-xr-x 2 root root 0 5月 20 10:27 ./ dr-xr-xr-x 3 root root 0 5月 16 08:05 ../ -rw-r--r-- 1 root root 0 5月 20 10:27 cgroup.clone_children -rw-r--r-- 1 root root 0 5月 20 10:27 cgroup.procs -r--r--r-- 1 root root 0 5月 20 10:27 cpuacct.stat -rw-r--r-- 1 root root 0 5月 20 10:27 cpuacct.usage -r--r--r-- 1 root root 0 5月 20 10:27 cpuacct.usage_all -r--r--r-- 1 root root 0 5月 20 10:27 cpuacct.usage_percpu -r--r--r-- 1 root root 0 5月 20 10:27 cpuacct.usage_percpu_sys -r--r--r-- 1 root root 0 5月 20 10:27 cpuacct.usage_percpu_user -r--r--r-- 1 root root 0 5月 20 10:27 cpuacct.usage_sys -r--r--r-- 1 root root 0 5月 20 10:27 cpuacct.usage_user -rw-r--r-- 1 root root 0 5月 20 10:27 cpu.cfs_period_us -rw-r--r-- 1 root root 0 5月 20 10:27 cpu.cfs_quota_us -rw-r--r-- 1 root root 0 5月 20 10:27 cpu.shares -r--r--r-- 1 root root 0 5月 20 10:27 cpu.stat -rw-r--r-- 1 root root 0 5月 20 10:27 cpu.uclamp.max -rw-r--r-- 1 root root 0 5月 20 10:27 cpu.uclamp.min -rw-r--r-- 1 root root 0 5月 20 10:27 notify_on_release -rw-r--r-- 1 root root 0 5月 20 10:27 tasks

配置cgroup子系统,设置只能使用10%的CPU时间片。修改cup.cfs_period_us, cpu.cfs_quota_us两个文件。

hello_cpu$ sudo chmod 777 * hello_cpu$ sudo echo 100000 > cpu.cfs_period_us hello_cpu$ sudo echo 10000 > cpu.cfs_quota_us

sudo apt install cgroup-tools

使用cgroup工具运行程序

test$ cgexec -g cpu:hello_cpu ./main &

top命令查看cpu占有率平均在10%左右:

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 47221 weimin 20 0 2496 516 448 R 10.3 0.0 0:02.32 main

运行时间:Program complete time: 10.011074 限制CPU占有率之后,程序的运行时间明显增长。

七、Linux Selinux

SELinux(security enhanced linux)安全增强型Linux系统,它是一个linux内核模块,也是Linux的一个安全子系统。Selinux的主要作用就是最大限度地减小系统中服务进程可访问的资源(最小权限原则)

【本文正在参加云原生有奖征文活动】,活动链接:https://ost./posts/12598

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:springboot实现通过路径从磁盘直接读取图片
下一篇:docker_存储卷
相关文章

 发表评论

暂时没有评论,来抢沙发吧~