当前位置: 代码网 > 服务器>服务器>Linux > 【K8S学习笔记】

【K8S学习笔记】

2024年07月28日 Linux 我要评论
在2013年,虚拟机和云计算已经是比较普遍的技术和服务了,那时主流用户的普遍用法,就是租一批 AWS 或者 OpenStack 的虚拟机,然后像以前管理物理服务器那样,用脚本或者手工的方式在这些机器上部署应用,这就是Paas提供的“应用托管”的能力。Linux 下的 /proc 目录存储的是记录当前内核运行状态的一系列特殊文件,用户可以通过访问这些文件,查看系统以及当前正在运行的进程的信息,比如 CPU 使用情况、内存占用率等,这些文件也是 top 指令查看系统信息的主要数据来源。

一、容器技术发展史

1. docker 崛起的原因

  1. docker镜像机制解决了paas打包问题;
  1. docker 容器同开发者之间有着与生俱来的密切关系;
  1. 当时 paas 概念已经深入人心

2. docker 公司的发展历程

docker 公司在 2014 年发布的 swarm 项目是以一个完整的整体来对外提供集群管理功能的产品。swarm 的最大亮点,则是它完全使用 docker 项目原本的容器管理 api 来完成集群管理。

同时,docker收购了fig 项目(后改名为compose),成了 docker 公司到目前为止第二大受欢迎的项目。

docker compose、swarm 和 machine 共称为docker“三件套”,使得 docker 公司在重新定义 paas 的方向上走出了最关键的一步。

3. docker 公司的尘埃落定

google、redhat 等开源基础设施领域玩家们,共同牵头发起了一个名为 cncf(cloud native computing foundation)的基金会。这个基金会的目的是以 kubernetes 项目为基础,建立一个由开源基础设施领域厂商主导的、按照独立基金会方式运营的平台级社区,来对抗以 docker 公司为核心的容器商业生态。

cncf 社区为了打造基于 k8s 的生态做出了两方面努力

  1. 解决 kubernetes 项目在编排领域的竞争力的问题
  1. cncf 社区必须以 kubernetes 项目为核心,覆盖足够多的场景

面对 kubernetes 社区的崛起和壮大,docker 公司只能选择逐步放弃开源社区而专注于自己的商业化转型。从 2017 年开始,docker 公司先是将 docker 项目的容器运行时部分 containerd 捐赠给 cncf 社区,标志着 docker 项目已经全面升级成为一个 paas 平台;紧接着,docker 公司宣布将 docker 项目改名为 moby,然后交给社区自行维护,而 docker 公司的商业产品将占有 docker 这个注册商标。

二、容器技术基础

容器本身没有价值,有价值的是“容器编排”。

容器技术的核心功能,就是通过约束和修改进程的动态表现,从而为其创造出一个“边界”。对于 docker 等大多数 linux 容器来说,cgroups 技术是用来制造约束的主要手段,而 namespace 技术则是用来修改进程视图的主要方法。

一个正在运行的 docker 容器,其实就是一个启用了多个 linux namespace 的应用进程,而这个进程能够使用的资源量,则受 cgroups 配置的限制。这也是容器技术中一个非常重要的概念,即:容器是一个“单进程”模型

1. namespace(看的视图的限制)

linux系统中创建进程可以fork,也可以clone,clone系统调用可以指定新的命名空间。当我们用 clone() 系统调用创建一个新进程时,就可以在参数中指定 clone_newpid 参数,比如:

int pid = clone(main_function, stack_size, clone_newpid | sigchld, null); 

这时,新创建的这个进程将会“看到”一个全新的进程空间,在这个进程空间里,它的 pid 是 1。之所以说“看到”,是因为这只是一个“障眼法”,在宿主机真实的进程空间里,这个进程的 pid 还是真实的数值,比如 100。

除了刚刚用到的 pid namespace,linux 操作系统还提供了 mount、uts、ipc、network 和 user 这些 namespace,用来对各种不同的进程上下文进行“障眼法”操作。比如,mount namespace,用于让被隔离进程只看到当前 namespace 里的挂载点信息;network namespace,用于让被隔离进程看到当前 namespace 里的网络设备和配置。

在创建容器进程时,指定了这个进程所需要启用的一组 namespace 参数。这样,容器就只能“看”到当前 namespace 所限定的资源、文件、设备、状态,或者配置。而对于宿主机以及其他不相关的程序,它就完全看不到了。所以说,容器其实是一种特殊的进程而已

docker 为容器启用的6项 namespace

namespace系统调用参数隔离的内容
utsclone_newuts主机名域名
ipcclone_newipc信号量、消息队列与共享内存
pidclone_newpid进程编号
networkclone_newnet网络设备、网络栈、端口等
mountclone_newns挂载点
userclone_newuser用户与组

namespace 技术实际上修改了应用进程看待整个计算机“视图”,即它的“视线”被操作系统做了限制,只能“看到”某些指定的内容。但对于宿主机来说,这些被“隔离”了的进程跟其他进程并没有太大区别。

2. cgroups(用的资源的限制)

2.1 容器与虚拟机的对比

优势:

  • 敏捷
  • 高性能

劣势:

  • 隔离的不彻底
    • 既然容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作系统内核。
    • 在 linux 内核中,有很多资源和对象是不能被 namespace 化的,最典型的例子就是:时间。
2.2 linux cgroups

linux cgroups 就是 linux 内核中用来为进程设置资源限制的一个重要功能。它的全称是 linux control group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 cpu、内存、磁盘、网络带宽等等。

此外,cgroups 还能够对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。

在 linux 中,cgroups 给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。

linux cgroups 的设计还是比较易用的,简单粗暴地理解呢,它就是一个子系统目录加上一组资源限制文件的组合。而对于 docker 等 linux 容器项目来说,它们只需要在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录),然后在启动容器进程之后,把这个进程的 pid 填写到对应控制组的 tasks 文件中就可以了。

2.2.1 实验演示

(1)查看cgroup内容

$ mount -t cgroup 
cpuset on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cpu on /sys/fs/cgroup/cpu type cgroup (rw,nosuid,nodev,noexec,relatime,cpu)
cpuacct on /sys/fs/cgroup/cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct)
blkio on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
memory on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
...

在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。这些都是可以被 cgroups 进行限制的资源种类。而在子系统对应的资源种类下,就可以看到该类资源具体可以被限制的方法。比如,对 cpu 子系统来说,我们就可以看到如下几个配置文件,这个指令是:

$ ls /sys/fs/cgroup/cpu
cgroup.clone_children cpu.cfs_period_us cpu.rt_period_us  cpu.shares notify_on_release
cgroup.procs      cpu.cfs_quota_us  cpu.rt_runtime_us cpu.stat  tasks

输出中的 cpu.cfs_period_uscpu.cfs_quota_us 就是可以组合使用的配置,用来限制进程在长度为 cfs_period 的一段时间内,只能被分配到总量为 cfs_quota 的 cpu 时间。

除 cpu 子系统外,cgroups 的每一个子系统都有其独有的资源限制能力,比如:

  • blkio,为​​​块​​​设​​​备​​​设​​​定​​​i/o 限​​​制,一般用于磁盘等设备;
  • cpuset,为进程分配单独的 cpu 核和对应的内存节点;
  • memory,为进程设定内存使用的限制。

(2)创建cgroup控制组
需要在对应的子系统下面创建一个目录,比如,我们现在进入 /sys/fs/cgroup/cpu 目录下:

root@ubuntu:/sys/fs/cgroup/cpu$ mkdir container
root@ubuntu:/sys/fs/cgroup/cpu$ ls container/
cgroup.clone_children cpu.cfs_period_us cpu.rt_period_us  cpu.shares notify_on_release
cgroup.procs      cpu.cfs_quota_us  cpu.rt_runtime_us cpu.stat  tasks

这个目录就称为一个“控制组”。操作系统会在你新创建目录下,自动生成该子系统对应的资源限制文件。

(3)使用cgroup
现在在后台执行这样一条脚本:

$ while : ; do : ; done &
[1] 226

它执行了一个死循环,可以把计算机的 cpu 吃到 100%,根据它的输出,我们可以看到这个脚本在后台运行的进程号(pid)是 226。

可以用 top 指令来确认一下 cpu 有没有被打满:

$ top
%cpu0 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

可以看到 cpu 的使用率已经 100% 了(%cpu0 :100.0 us)。

通过查看 container 目录下的文件,看到 container 控制组里的 cpu quota 还没有任何限制(即:-1),cpu period 则是默认的 100 ms(100000 us):

$ cat /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us 
-1
$ cat /sys/fs/cgroup/cpu/container/cpu.cfs_period_us 
100000

可以通过修改这些文件的内容来设置限制。比如,向 container 组里的 cfs_quota 文件写入 20 ms(20000 us):

$ echo 20000 > /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us

它意味着在每 100 ms 的时间里,被该控制组限制的进程只能使用 20 ms 的 cpu 时间,也就是说这个进程只能使用到 20% 的 cpu 带宽。

然后把被限制的进程的 pid 写入 container 组里的 tasks 文件,上面的设置就会对该进程生效了:

$ echo 226 > /sys/fs/cgroup/cpu/container/tasks 

用 top 指令查看一下:

$ top
%cpu0 : 20.3 us, 0.0 sy, 0.0 ni, 79.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

可以看到,计算机的 cpu 使用率立刻降到了 20%(%cpu0 : 20.3 us)。

2.2.2 docker 容器的cgroup演示

执行 docker run 时指定 cpu 相关设置参数:

$ docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash

在启动这个容器后,可以通过查看 cgroups 文件系统下,cpu 子系统中,“docker”这个控制组里的资源限制文件的内容来确认:

$ cat /sys/fs/cgroup/cpu/docker/5d5c9f67d/cpu.cfs_period_us 
100000
$ cat /sys/fs/cgroup/cpu/docker/5d5c9f67d/cpu.cfs_quota_us 
20000

这表明这个 docker 容器,只能使用到 20% 的 cpu 带宽。

2.3 cgroups 的缺点

cgroups 对资源的限制能力也有很多不完善的地方,被提及最多的自然是 /proc 文件系统的问题。

linux 下的 /proc 目录存储的是记录当前内核运行状态的一系列特殊文件,用户可以通过访问这些文件,查看系统以及当前正在运行的进程的信息,比如 cpu 使用情况、内存占用率等,这些文件也是 top 指令查看系统信息的主要数据来源。

如果在早期没有完整隔离的容器里执行 top 指令,就会发现,它显示的信息是宿主机的 cpu 和内存数据,而不是当前容器的数据。造成这个问题的原因就是,/proc 文件系统并不知道用户通过 cgroups 给这个容器做了什么样的资源限制,即:/proc 文件系统是全局针对整个系统的,它不了解 cgroups 限制的存在。

lxcfs 最初是为了增强 lxc(linux 容器)和 lxd(容器的轻量级虚拟化管理器)的容器体验而设计的。尽管 docker 最初是基于 lxc 构建的,但在 0.9 版本之后,docker 引入了自己的容器运行时,称为 libcontainer(现在是容器的标准运行时 runc 的一部分),并逐渐摒弃了对 lxc 的依赖。使用 lxcfs 来提供容器内部的 /proc 和 /sys 文件系统的隔离视图,是一种补充方式,主要用于提升 lxc/lxd 容器的用户体验。docker 的用户如果需要 lxcfs 类似的功能,通常需要手动进行配置和集成,因为 docker 默认提供的隔离机制已经能够满足大多数使用场景的需求。

2.3.1 lxcfs

lxcfs 是通过文件挂载的方式,把 cgroup 中关于系统的相关信息读取出来,通过 docker 的 volume 挂载给容器内部的 proc 系统。 然后让 docker 内的应用读取 proc 中信息的时候以为就是读取的宿主机的真实的 proc。

lxcfs 的工作原理架构图:
在这里插入图片描述
当我们把宿主机的 /var/lib/lxcfs/proc/memoinfo 文件挂载到 docker 容器的 /proc/meminfo 位置后,容器中进程读取相应文件内容时,lxcfs 的 /dev/fuse 实现会从容器对应的 cgroup 中读取正确的内存限制。从而使得应用获得正确的资源约束。 cpu 的限制原理也是一样的。

3. 容器镜像 rootfs

三、kubernetes 集群的搭建与实践

四、容器编排与 kubernetes 核心特性剖析

五、kubernetes 开源社区与生态

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com