前言笔者在容器云平台初建时,也讨论过容器虚拟集群和物理集群的优缺点。在容器云平台的应用实践过程中,虚拟节点和物理节点也逐步部署。随着实践的深入,虚拟节点和物理节点的不同资源配置也带来了一些问题和思考。一开始觉得,既然容器是轻量级的,那么每个节点都不需要配置这么高的资源。然而,很快就被现实打脸了。节点资源分配不当,不仅增加了管理的复杂性,也带来了资源的浪费。另外,由于容器云平台自身功能的限制,以及整体架构和整体资源的限制,很难做到真正的弹性调度和按需扩展。比如宿主机上经常存在虚拟机资源竞争,但是从容器云平台上看到的是容器节点的资源使用率不高,但是应用请求异常。因此,这不是一个简单的容器云问题。需要实现各个层面的联动,如虚拟化平台与容器云平台的联动,基础设施资源管理平台与容器云平台的联动,实现异构资源调度。从虚拟机节点到物理机节点部署基于虚拟化平台的容器云,相对容易实现容器节点的扩缩容。信息在容器云平台上往往是不可见的,无法及时有效地均衡虚拟化主机上容器节点的负载。笔者一直建议使用多云管理平台(也就是虚拟化平台)来管理不同的基础设施资源,但是目前市面上的云管理平台基本都是大杂烩,并没有真正理解云的定位和范围管理。由于多种原因,难以实现基础设施资源的自动弹性扩展和均衡调度。此外,虚拟化层还造成了约20%的机器性能损失,造成了很大的浪费。比如Java应用,对资源的需求就比较大。如果基于SpringCloud框架开发的微服务部署在资源配置比较少的虚拟机上,容器经常会因为资源不足而被逐出,看到很多处于Evicted状态的容器。再者,随着容器节点的增加,暴露出很多问题,比如Master节点配置(随着节点数量的增加,Master节点资源短缺响应变慢)、etcd配置(pod、services等对象越来越多)、Ingress配置(高可用、负载均衡等不同需求带来的不同配置)、Portal配置(Portal组件划分、组件集中部署或分布式部署、组件资源配额)等问题。一方面,国内很多容器平台的应用可能是肤浅的,缺乏真正的实践经验,借鉴的不多,导致很多功能不完善;适应云计算和云原生的概念也会产生冲突,制约容器云的深入应用和实践。为了实现更好的可视性和可管理性,以及更好的性能和资源节约,经过一段时间的实践,我们将部分物理服务器部署到容器虚拟集群中,用于部署和运行重要的业务应用,形成了虚实结合的节点部署方式簇。混合节点集群私有云环境往往无法充分配置各类资源,因此大多为通用资源,用于部署各种业务应用。容器云平台不仅要考虑节点的敏捷扩展,还要考虑关键业务应用的稳定运行和执行效率。物理服务器的采购往往需要一个周期,需要提前准备好相应的资源。与虚拟化相比,物理节点扩展不是那么方便,也难以实现资源复用。这是物理节点不足的地方。但是物理节点没有性能损耗,适合运行一些比较重要的业务,或者对处理性能要求比较高的业务。因此,可以在容器集群中同时部署虚拟节点和物理节点,实现混合节点集群。部署业务应用时,根据业务应用的特点,将其调度到合适的节点。什么样的资源分配适合一个节点?坦率地说,目前还没有一个明确的标准,往往与具体业务密切相关。在笔者的场景下,虚拟机可以配置16C64G、16C48G或32C64G,磁盘200G,CPU与内存的比例为1:4、1:3或1:2。根据业务运行的资源消耗需求,经过一段时间的运行观察,可以根据实际资源使用情况调整节点资源配置和容器资源配置。在交易高峰时段,CPU经常处于满载状态,但在其他时间,CPU往往处于较低的使用水平。共享分区、独享分区、节点容量、资源分片、垂直扩展能力、水平扩展能力、迁移规则、服务优先级,甚至异构资源的成本等等,都可能影响pod的调度。这实际上带来了一个物理节点资源分配的问题。如果不对物理机进行虚拟化,则无法从虚拟层实现复用(但也减少了虚拟化的损失)。另外,如果物理节点出现异常,需要维护重启,会影响其上的服务。如果部署更多的服务,影响会更大。因此,容器节点的资源分配并不是越大越好,需要结合实践和实际找到一个平衡点。容器物理集群配置什么样的配置适合物理集群中的节点?可能需要考虑几个方面。一开始笔者也想当然的认为很多低端PC都可以用,但是从机房的效率来说,低端PC显然不太适合。毕竟需要占用很多机房座位,成本其实很高。但是如果配置太高,一个容器节点通常不适合部署很多容器。k8s建议不要超过110个pod。另外,如果配置太高,节点数量会比较少,灵活调度的范围也会比较小。特别是如果多个重要的容器部署在同一个节点上,一旦节点出现异常,影响可能会非常大。但物理节点相对有效地减少了资源碎片化和资源虚拟化损失,资源利用率相对较高。根据之前的实践和实际情况,采购了一批96C512G4T服务器,搭建容器物理集群,部署一些重要的业务应用。使用物理节点对应用资源的调度能力要求更高。资源调度可以有不同的规则,比如均衡调度?还是单节点优先级调度?或者预留一些资源用于均衡调度等;还有大pod和小pod均衡调度,serviceaffinity和non-affinity调度的需求。当节点数量比较少的时候,可能需要重点关注应用pod的均衡调度。深入理解容器使用场景我们都知道容器是轻量级、无状态、生命周期短的。但是在实际应用中可能会发现,一个业务应用容器未必是轻量级的,需要持久化的数据非常多,往往需要长时间持续稳定运行。大家可能也经常会遇到几G或者十几G的镜像,直接把容器当作虚拟机使用。虽然这是一些坏习惯,但问题确实存在。理论上,容器应该尽可能删除无用的组件和文件,让容器尽可能的轻量化,但是在实际项目中,很多厂商并不会做这个工作,因为清理起来很费时间,规则也很多需要遵循,需要很多额外的测试;此外,在业务异常处理过程中可能会用到一些工具或组件。将这些工具和组件安装到容器中,会导致这些容器变得更重,同时也会增加安全接触面,带来更多的安全漏洞或潜在的安全漏洞和安全风险。比如Java服务打包时,应该使用JDK镜像还是JRE镜像?跑java,JRE就够了,用JDK其实浪费了很多资源。笔者一直强调,数据库、Kafka、Redis、ES等都不适合部署在容器中。当然,在测试环境中,为了快速搭建业务测试环境,快速回到初始状态进行回归测试是非常方便的。但是生产环境追求的是稳定和可靠(这就是GoogleSRE的价值所在),这与测试环境的敏捷需求是不一样的。不同场景采用的解决方案可能不同。因此,除了在容器中实现小环境的一致性外,企业内部的生产环境和测试环境之间可能还存在差异。在生产环境中,稳定性和可靠性比弹性更重要。因此,在生产环境中,除了适合部署在物理机上的数据库和中间件之外,一些重要的业务也可以使用容器物理节点来更好地满足性能需求。笔者曾尝试配置不同的容器节点来满足不同业务应用的需求,但资源分配好后,无法控制每个团队的使用。尤其是有很多厂商和外包商对容器和相关技术的理解并不深刻。设置资源配置、调度配置等参数,不知道如何预估业务服务的资源需求,所以经常会不自觉地配置大资源,避免资源带来的问题,但这也造成了很多问题。资源浪费(分配的资源被独占,无法与其他服务共享)。因此,还需要及时监测、提醒和培训,调整不合理的资源配置。容器的迁移、重启、驱逐都会导致Pod重建,造成短时间的中断;如果业务服务无法启动,比如初始化连接失败,无法连接kafka或者数据库,可能会频繁重建Pod,k8s自身的一些bug也会导致系统出现一些问题。部分资源耗尽,导致节点异常。在实际运行中,发现容器服务会创建成百上千个进程。由于容器POD的封装,如果不检查这些指标,可能无法发现问题,导致环境异常频繁,尤其是生产环境。不稳定的业务不仅是糟糕的体验,而且是财务损失。所以,容器的生命周期短,是可以自我恢复的,如果不注意封装在里面的业务应用和运行环境,还是会造成很多问题。一个建议是每个人都喜欢最佳实践。事实上,在不同的环境、不同的场景、不同的需求下,应该采取的解决方案也可能不同,所以笔者始终建议根据实际考虑。经验可以作为参考,但不可照搬。容器云平台在使用虚拟节点和物理节点时各有优缺点。但随着管理手段的提升和政策的支持,物理集群可能会越来越多。物理集群的配置也需要根据具体的业务需求来确定。如果每个服务对资源的需求不是很大,可以配置稍微低一点的物理节点;如果部署的容器对资源有比较大的需求,比如部署Kafka、ES等中间件容器,一个Pod可能需要32C64G甚至更多的资源,可能需要配置更高。随着应用资源调度能力的逐步提升,实现不同业务的分时复用,有效提高资源利用率可能会越来越普遍。一些公司通过应用程序的混合部署提高了资源效率。比如白天主要处理交易业务,晚上主要处理批处理业务,忙闲时的资源得到充分利用。这可能更适合容器物理节点。
