问题描述
到目前为止,我一直以为容器技术(例如docker)可提供所需的隔离和OS级虚拟化。而且,容器中运行的应用程序受到-名称空间,cgroups,apparmour / selinux,功能的限制,它们无法找出它们所在的主机环境。但是,这种理解似乎并非100%正确。
如Wiki-OS-level virtualization
OS级虚拟化是一种操作系统范式,其中 内核允许存在多个已隔离用户空间实例。 这样的实例称为容器(LXC,Solaris容器,Docker), 区域(Solaris容器),虚拟专用服务器(OpenVZ), 分区,虚拟环境(VE),虚拟内核(DragonFly BSD)或监狱(FreeBSD监狱或chroot监狱),1看起来像真实的 从计算机中运行的程序的角度来看。一种 在普通操作系统上运行的计算机程序可以查看全部 资源(连接的设备,文件和文件夹,网络共享,cpu 电源,可量化的硬件功能)。 但是, 在容器内部运行的程序只能看到容器的 内容和分配给该容器的设备。
从上面的引用看来,它似乎只增加了隔离和抽象,没有像virtualiztion这样的东西。
由于Java团队不得不向JVM添加容器支持,因此它不直接查看主机环境,而是将ITSELF限制为docker提供的隔离/抽象。
参考:
- Java (prior to JDK8 update 131) applications running in docker container CPU / Memory issues?给出了很好的答案,解释了JVM对linux容器的支持。
Linux容器支持首先出现在JDK 10中,然后移植到 8u191,
这是否意味着在容器环境中运行的C程序可以绕过限制并访问/读取主机环境详细信息。当然,当它尝试(即使用此信息)进行操作时除了允许容器执行的任何操作之外,容器引擎可能会杀死容器本身的进程。
因此,如果我正在开发一个C / C ++应用程序,该应用程序请求/查询诸如cpu / MEM / Devices等主机资源,则我的责任是通过添加容器支持在容器环境中按预期运行该应用程序。
解决方法
尽管我怀疑这将是一个流行的答案,但我的观点是,必须在容器环境中运行的应用程序必须提供明确指定资源限制的方法。依靠系统查询的信息是错误的。
容器不是完整的虚拟化环境,通常不会完全隐藏底层平台。尽管容器在网络,文件系统和用户级别可能且通常与主机隔离,但这并不意味着它们真正独立。我遇到的一个典型问题是,容器无法获得它自己对系统平均负载的贡献,仅是主机的平均负载。
没有完全虚拟化的事实并不意味着主机不能强制执行限制-通常可以而且可以做到。但这意味着容器无法轻松地找到它们的内容,而不是以一种健壮的,与平台无关的方式。
容器可以使用各种启发式方法。例如,它可能能够解析/proc/self/cgroup
。根据实现方式,这可能会或可能不会提供有用的信息。仅当主机使用控制组时,这种方法才会提供有用的信息-大多数当前的实现都是这样做的,但这并不意味着它是强制性的。
当前使用的容器框架有很多,并且这个数目可能会增加。很难预测将来必须使用哪种方法来使应用程序成为容器可验证的。我认为,与为开发的每个软件进行持续的维护任务相比,更好的方法是为用户提供一种控制限制的方法。
,在容器环境中,通常可以更好地构建可以运行多个副本的小型互连容器。然后,您可以根据工作负载调整环境大小,而不必根据工作环境调整工作负载。
一个更容易考虑的示例是处理异步任务的工作进程。在非容器环境中,典型的设置是询问主机它有多少个内核,然后启动那么多线程。正是由于您提到的各种问题,这不能很好地转换为容器。相反,通常最好使工作进程为单线程,然后根据需要启动任意数量的副本。
特别是如果您在云环境中运行Kubernetes,这样做有一些真正的优势。在Kubernetes部署中,您可以指定容器的replicas:
数量,并动态更改它,因此您完全不必依赖于硬件配置。您可以使用称为horizontal pod autoscaler的Kubernetes片段根据队列长度自动设置部署计数。当工作负载对于当前集群而言太大时,您可以使用名为cluster autoscaler的Kubernetes的不同部分来自动请求更多的云计算节点。这是一个基本的假设,即各个容器(Kubernetes Pods)很小,无状态,并且在任何硬件设置下的行为都相同。
您引用的JVM内存限制问题面临类似的问题。 default JVM behavior要将25%的系统内存用于堆,但是现在的问题变成了,如何确定面对每个容器的资源限制需要多少内存?但是,大多数应用程序运行时都没有像这样的与系统相关的硬内存限制。您谈论C程序,并且malloc()
可以正常工作,直到达到内核强制的(物理或cgroup)内存限制为止。
因此,如果我正在开发一个C / C ++应用程序,该应用程序请求/查询诸如CPU / MEM / Devices之类的主机资源...
...在像Docker这样的隔离系统中运行它是不合适的。直接在主机上运行。