构建容器之为什么要理解用户空间和内核空间问题

原文:Architecting Containers Part 1: Why Understanding User Space vs. Kernel Space Matters

你是不是被指定开发一个基于容器的应用程序基础框架?如果是这样,你很可能需要理解容器可以为开发人员,架构师和团队带来什么样的价值。事实上,你可能已经阅读了容器相关的资料,并且对更深入地探索该技术感到兴奋。然而,在开始讨论生产环境中的容器体系结构和如何部署之前,开发人员,架构师和系统管理员都需要知道的三件重要的事情是:

  • 所有应用程序(包括容器化应用程序)都依赖于底层内核
  • 内核通过系统调用为这些应用程序提供一个 API 接口
  • 这个 API 的版本管理很重要,因为它是用户空间和内核空间之间交流的关键
  • 虽然容器有时被当作虚拟机对待,但重要的是,要注意它与虚拟机之间的不同,内核是程序和它们需要访问的资源之间唯一的抽象层。接下来,让我们看看为什么。

进程系统调用:

因为容器也是进程,它们也需要进行系统调用:

好吧,你已经了解了一个进程是什么,容器也都是进程。但是容器镜像里面的文件和程序又是什么呢?这些文件和程序构成了所谓的用户空间。当一个容器启动时,一个程序从容器镜像加载到内存中。一旦容器中的程序运行,它仍然需要通过系统调用进入内核空间。用户空间和内核空间以确定的方式进行通信的能力至关重要。

用户空间(User Space)

用户空间是指内核以外的所有其他的代码。大多数类 Unix 系统(包括 Linux)都预先打包了各种实用的程序,编译语言和图形化工具 - 这些都是用户空间内的应用程序。我们通常称之为 “用户区”。

用户区程序包含用 C,Java,Python,Ruby 和其他语言编写的程序。在容器化的世界里,这些程序通常以 Docker 等容器镜像格式交付。当你从 Red Hat 镜像仓库中拉取并运行 Red Hat Enterprise Linux 7 容器镜像时,你正在使用预先打包的最小化的 Red Hat Enterprise Linux 7,包含运行在用户空间中的,诸如 bash,awk,grep 和 yum 等实用的程序(这样你可以安装其他软件)。

docker run -i -t rhel7 bash

所有的用户程序(容器化或者不是容器化)都通过操作数据来运行,但是这些数据存在哪里呢?这些数据可能来自 CPU 和外部设备的寄存器,但通常存储在内核和磁盘中。用户程序通过向被称之为系统调用的内核发出特殊请求来访问数据。例如,分配内存(变量)或打开文件。内存和文件通常存储不同用户的敏感信息,因此必须通过系统调用,通过内核请求访问。

内核空间(Kernel Space)

内核提供了安全性,硬件和内部数据结构的抽象。Python,C,Ruby 和其他语言通常通过 open() 系统调用来获取文件句柄。你不希望程序能够对 XFS 文件系统进行位级别的修改,因此内核提供系统调用并处理的驱动程序。实际上,这个系统调用非常常见,它是 POSIX 库的一部分。

请注意,在下面的图中,bash 发出一个请求其自身进程标示的 getpid() 调用。另外请注意,cat 命令请求通过文件 open() 调用访问 /etc/hosts。在下一篇文章中,我们将深入探讨这是如何在一个容器化的世界中进行的,但请注意,一些代码存在与用户空间中,而另一些则存在与内核中。

常规的用户空间程序会随时调用系统调用以完成工作,例如:

ls
ps
top
bash

这些用户空间程序几乎直接映射到系统调用,例如:

chroot
sync
mount/umount
swapon/swapoff

深挖一层,以下是上述程序调用的一些示例的系统调用。通常,这些函数通过库(如 glibc)或通过解释器(如 Ruby,Python 或 Java 虚拟机)调用。

open (files)
getpid (processes)
socket (network)

一个典型的程序通过类似下图的抽象层访问内核中的资源:

要了解 Linux 内核中可用的系统调用,请查看 syscalls 手册页。有趣的是,我在我的红帽企业 Linux 7 笔记本电脑上调用了这个命令,但是我使用的是红帽企业 Linux 6 容器镜像(又称用户空间),因为我想看看在旧内核中添加/删除的系统调用:

docker run -t -i rhel6-base man syscalls
SYSCALLS(2)                Linux Programmer’s Manual               SYSCALLS(2)
NAME
syscalls - Linux system calls
SYNOPSIS
Linux system calls.
DESCRIPTION
The system call is the fundamental interface between an application and the kernel.
System call                 Kernel        Notes
------------------------------------------------------------------------------
_llseek(2)                  1.2
_newselect(2)
_sysctl(2)
accept(2)
accept4(2)                  2.6.28
access(2)
acct(2)
add_key(2)                  2.6.11
adjtimex(2)
afs_syscall(2)                            Not implemented
alarm(2)
alloc_hugepages(2)          2.5.36        Removed in 2.5.44
bdflush(2)                                Deprecated (does nothing) since 2.6
bind(2)
break(2)                                  Not implemented
brk(2)
cacheflush(2)               1.2           Not on i386

从技术手册注意到,某些系统调用(又称接口)已经在不同版本的内核中增加或者删除了。Linus Torvalds et.al.(Linux之父)说过,要非常小心地保持这些系统调用的行为有良好的理解和稳定的功能。从红帽企业版 Linux 7(内核 3.10)开始,共有 382 个系统调用可用。有时会添加新的系统调用,并且旧的系统调用不推荐使用;在考虑容器基础架构的生命周期以及将在其中运行的应用程序时应该考虑这一点。

结论

有一些重要的关键点,需要你了解用户空间和内核空间:

  • 应用程序包含业务逻辑,但依赖于系统调用。
  • 编译应用程序后,应用程序使用(即依赖于)的系统调用集被嵌入到二进制文件中(在更高级别的语言中,这是解释器或 JVM 干的事情)。
  • 容器不会抽象出对用户空间或内核空间的需求,以共享同一组通用的系统调用。
  • 在一个容器化的世界里,这个用户空间捆绑起来并运送到不同的主机,从笔记本到生产服务器。
  • 未来几年,这将会带来挑战。

随着时间的推移,保证今天建成的容器将运行在明天的容器主机上将时一个挑战。想象一下,今年是 2024 年(也许我们最终会有真正的 hoverboards),并且你仍然有一个基于容器的应用程序,需要在生产环境中运行红帽企业版 Linux 7 用户空间。如何安全地升级底层容器主机和基础设施?容器化的应用程序能否在市场上任何最新的容器主机上运行?

在容器架构第二部分:为什么用户空间很重要,我们将探讨用户空间/内核空间关系如何影响架构决策以及如何最大限度地减少这些挑战。与此同时,如果你有任何想法或疑问,请随时在下面评论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值