深入剖析Kubernetes学习笔记-06 | 白话容器基础(二):隔离与限制

简介: 深入剖析Kubernetes学习笔记-06 | 白话容器基础(二):隔离与限制

一、为什么选择容器而不是虚拟机


使用虚拟化技术作为应用沙盒,就必须要由 Hypervisor 来负责创建虚拟机,这个虚拟机是真实存在的,并且它里面必须运行一个完整的 Guest OS 才能执行用户的应用进程。这就不可避免地带来了额外的资源消耗和占用。

1.1 虚拟机所耗费的资源


一个运行着 CentOS 的 KVM 虚拟机启动后,在不做优化的情况下,虚拟机自己就需要占用 100~200 MB 内存。


用户应用运行在虚拟机里面,它对宿主机操作系统的调用就不可避免地要经过虚拟化软件的拦截和处理,这本身又是一层性能损耗,尤其对计算资源、网络和磁盘 I/O 的损耗非常大

1.2 容器所耗费的资源


容器化后的用户应用,却依然还是一个宿主机上的普通进程,这就意味着这些因为虚拟化而带来的性能损耗都是不存在的;


使用 Namespace 为隔离手段的容器并不需要单独的 Guest OS,这就使得容器额外的资源占用几乎可以忽略不计。


“敏捷”和“高性能”是容器相较于虚拟机最大的优势,也是它能够在 PaaS 这种更细粒度的资源管理平台上大行其道的重要原因。

二、更精确的隔离方式


Linux Namespace 的隔离机制相比于虚拟化技术也有很多不足之处,其中最主要的问题就是:隔离得不彻底。

2.1 容器共享宿主机的操作系统内核。


尽管你可以在容器里通过 Mount Namespace 单独挂载其他不同版本的操作系统文件,比如 CentOS 或者 Ubuntu,但这并不能改变共享宿主机内核这意味着,如果你要在 Windows 宿主机上运行 Linux 容器,或者在低版本的 Linux 宿主机上运行高版本的 Linux 容器,都是行不通的。


而相比之下,拥有硬件虚拟化技术和独立 Guest OS 的虚拟机就要方便得多了。最极端的例子是,Microsoft 的云计算平台 Azure,实际上就是运行在 Windows 服务器集群上的,但这并不妨碍你在它上面创建各种 Linux 虚拟机出来。


带来的问题:


容器给应用暴露出来的攻击面是相当大的,应用“越狱”的难度自然也比虚拟机低得多。


尽管在实践中我们确实可以使用 Seccomp 等技术,对容器内部发起的所有系统调用进行过滤和甄别来进行安全加固,但这种方法因为多了一层对系统调用的过滤,一定会拖累容器的性能。何况,默认情况下,谁也不知道到底该开启哪些系统调用,禁止哪些系统调用。在生产环境中,没有人敢把运行在物理机上的 Linux 容器直接暴露到公网上

2.2 时间不能被Namespace 化


在 Linux 内核中,有很多资源和对象是不能被 Namespace 化的,最典型的例子就是:时间。


如果你的容器中的程序使用 settimeofday(2) 系统调用修改了时间,整个宿主机的时间都会被随之修改。


这显然不符合用户的预期。相比于在虚拟机里面可以随便折腾的自由度,在容器里部署应用的时候,什么能做,什么不能做,就是用户必须考虑的一个问题。

三、容器的“限制”


3.1 Linux Cgroups


Linux Cgroups 就是 Linux 内核中用来为进程设置资源限制的一个重要功能。

Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。


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


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


Ubuntu 18.04  mount 指令把它们展示出来

root@ubuntu:/home/wx# mount -t cgroup 
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)

它的输出结果,是一系列文件系统目录。如果你在自己的机器上没有看到这些目录,那你就需要自己去挂载 Cgroupscpuset、cpu、 memory 这样的子目录,也叫子系统。这些都是这台机器当前可以被 Cgroups 进行限制的资源种类

root@ubuntu:/home/wx# ls /sys/fs/cgroup/cpu
cgroup.clone_children  cpuacct.stat       cpuacct.usage_percpu       cpuacct.usage_sys   cpu.cfs_quota_us  docker             system.slice
cgroup.procs           cpuacct.usage      cpuacct.usage_percpu_sys   cpuacct.usage_user  cpu.shares        notify_on_release  tasks
cgroup.sane_behavior   cpuacct.usage_all  cpuacct.usage_percpu_user  cpu.cfs_period_us   cpu.stat          release_agent      user.slice

fs_period cfs_quota 这两个参数需要组合使用,可以用来限制进程在长度为 cfs_period 的一段时间内,只能被分配到总量为 cfs_quota 的 CPU 时间。

3.2 如何使用


需要在对应的子系统下面创建一个目录

root@ubuntu:/home/wx# cd /sys/fs/cgroup/cpu
root@ubuntu:/sys/fs/cgroup/cpu# pwd
/sys/fs/cgroup/cpu
root@ubuntu:/sys/fs/cgroup/cpu# ls container/
cgroup.clone_children  cpuacct.stat   cpuacct.usage_all     cpuacct.usage_percpu_sys   cpuacct.usage_sys   cpu.cfs_period_us  cpu.shares  cpu.uclamp.max  notify_on_release
cgroup.procs           cpuacct.usage  cpuacct.usage_percpu  cpuacct.usage_percpu_user  cpuacct.usage_user  cpu.cfs_quota_us   cpu.stat    cpu.uclamp.min  tasks
root@ubuntu:/sys/fs/cgroup/cpu# 

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


现在,我们在后台执行这样一条脚本:

root@ubuntu:/sys/fs/cgroup/cpu# while : ; do : ; done &
[1] 15035

top 指令来确认一下 CPU 有没有被打满

top - 07:08:29 up  7:23,  1 user,  load average: 0.97, 0.35, 0.12
Tasks: 316 total,   2 running, 247 sleeping,   0 stopped,   0 zombie
%Cpu(s): 97.0 us,  3.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st

查看 container 目录下的文件,看到 container 控制组里的 CPU quota 还没有任何限制(即:-1),CPU period 则是默认的 100 ms(100000 us):长度为 100 ms的时间内,只能被分配到总量为 cfs_quota 的 CPU 时间是没有限制。

root@ubuntu:/sys/fs/cgroup/cpu#  cat /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us 
-1
root@ubuntu:/sys/fs/cgroup/cpu# 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 带宽。


除 CPU 子系统外,Cgroups 的每一项子系统都有其独有的资源限制能力,比如:

  1. blkio,为块设备设定I/O 限制,一般用于磁盘等设备;
  2. cpuset,为进程分配单独的 CPU 核和对应的内存节点;
  3. memory,为进程设定内存使用的限制。

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

root@ubuntu:/sys/fs/cgroup/cpu# 
root@ubuntu:/sys/fs/cgroup/cpu# echo 15035 > /sys/fs/cgroup/cpu/container/tasks 

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

top - 07:14:06 up  7:28,  1 user,  load average: 0.69, 0.80, 0.42
Tasks: 315 total,   2 running, 247 sleeping,   0 stopped,   0 zombie
%Cpu(s): 20.4 us,  5.4 sy,  0.0 

计算机的 CPU 使用率立刻降到了 20%(%Cpu0 : 20.3 us)


除 CPU 子系统外,Cgroups 的每一项子系统都有其独有的资源限制能力,比如:

  1. blkio,为块设备设定I/O 限制,一般用于磁盘等设备;
  2. cpuset,为进程分配单独的 CPU 核和对应的内存节点;
  3. memory,为进程设定内存使用的限制。

Linux Cgroups 的设计就是一个子系统目录加上一组资源限制文件的组合而对于 Docker 等 Linux 容器项目来说,它们只需要在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录),然后在启动容器进程之后,把这个进程的 PID 填写到对应控制组的 tasks 文件中就可以了。


而至于在这些控制组下面的资源文件里填上什么值,就靠用户执行 docker run 时的参数指定了,比如这样一条命令:

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 带宽。


如何删除cgroup的配置?

04aedd78a6bc4cbfbaf84b33ec3f8a5d.png

四、总结


一个正在运行的 Docker 容器,其实就是一个启用了多个 Linux Namespace 的应用进程,而这个进程能够使用的资源量,则受 Cgroups 配置的限制。容器是一个“单进程”模型。

问题: /proc 文件系统目录存储的是记录当前内核运行状态的一系列特殊文件,用户可以通过访问这些文件,查看系统以及当前正在运行的进程的信息,比如 CPU 使用情况、内存占用率等


它显示的信息居然是宿主机的 CPU 和内存数据,而不是当前容器的数据?如何解决?


lxcfs

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
5天前
|
存储 Kubernetes C++
【专栏】Kubernetes VS Docker Swarm了解两者特点,助力选取合适容器编排工具
【4月更文挑战第27天】对比Kubernetes和Docker Swarm:K8s在可扩展性和自动化方面出色,有强大社区支持;Swarm以简易用著称,适合初学者。选择取决于项目需求、团队技能和预期收益。高度复杂项目推荐Kubernetes,快速上手小项目则选Docker Swarm。了解两者特点,助力选取合适容器编排工具。
|
4天前
|
存储 Java Serverless
ACK One Argo 工作流集群:玩转容器对象存储
ACK One Argo 工作流集群:玩转容器对象存储
ACK One Argo 工作流集群:玩转容器对象存储
|
4天前
|
存储 Kubernetes 监控
使用Kubernetes进行容器编排:技术详解与实践
【5月更文挑战第16天】Kubernetes,简称K8s,是开源容器编排系统,用于自动化部署、扩展和管理容器化应用。核心概念包括节点、Pod(最小部署单元)、服务、标签和副本集。其特点有高可用性、可扩展性、自动化和可移植性。实践使用涉及安装配置集群、编写YAML部署清单、应用部署、监控管理和扩展更新。Kubernetes帮助提升应用的可用性、可扩展性和可移植性。
|
5天前
|
分布式计算 Kubernetes 监控
容器服务Kubernetes版产品使用合集之怎么实现把 spark 跑在k8s
容器服务Kubernetes版,作为阿里云提供的核心服务之一,旨在帮助企业及开发者高效管理和运行Kubernetes集群,实现应用的容器化与微服务化。以下是关于使用这些服务的一些建议和合集,涵盖基本操作、最佳实践、以及一些高级功能的使用方法。
28 1
|
5天前
|
Kubernetes Java 调度
Java容器技术:Docker与Kubernetes
Java容器技术:Docker与Kubernetes
38 0
|
5天前
|
运维 Kubernetes Linux
10分钟搭建Kubernetes容器集群平台(kubeadm)
10分钟搭建Kubernetes容器集群平台(kubeadm)
|
5天前
|
Kubernetes Ubuntu Linux
Kubernetes(K8S)集群管理Docker容器(部署篇)
Kubernetes(K8S)集群管理Docker容器(部署篇)
|
5天前
|
Kubernetes 应用服务中间件 Docker
Kubernetes学习-集群搭建篇(二) 部署Node服务,启动JNI网络插件
Kubernetes学习-集群搭建篇(二) 部署Node服务,启动JNI网络插件
|
1天前
|
运维 监控 Kubernetes
Kubernetes 集群的监控与日志管理最佳实践
【5月更文挑战第19天】 在现代微服务架构中,容器编排平台如Kubernetes已成为部署、管理和扩展应用程序的关键工具。随着其应用范围不断扩大,集群的稳定性和性能监控变得至关重要。本文将探讨针对Kubernetes集群的监控策略,并深入分析日志管理的实现方法。通过介绍先进的技术堆栈和实用工具,旨在为运维专家提供一套完整的解决方案,以确保集群运行的透明度和可靠性。
28 3
|
1天前
|
存储 运维 监控
Kubernetes 集群的监控与性能优化策略
【5月更文挑战第19天】 在微服务架构日益普及的背景下,容器编排工具如Kubernetes已成为部署、管理和扩展服务的关键平台。然而,随着集群规模的增长和服务的复杂化,有效的监控和性能优化成为确保系统稳定性和高效性的重要挑战。本文将探讨针对Kubernetes集群监控的最佳实践,并提出一系列性能优化策略,旨在帮助运维人员识别潜在的瓶颈,保障服务的持续可靠性及响应速度。

推荐镜像

更多