你已经了解过Kubernetes了(或正在考虑探索一些Kubernetes部署)。了解它有很多很好的理由,你可能已经很清楚,Kubernetes是负责管理容器,将工作负载调度到集群上,处理可伸缩性和冗余,自动执行滚动(更新)和回滚。它是一个与基础设施无关的系统,通过使用声明式语句来描述系统和应用应处于的状态,并驱动所托管的元素达到该状态。这样子使管理功能强大且可扩展的系统变得更加容易。当然,这里所说的“易于管理”有一定的学习曲线,但是为了获得现代基于容器的软件开发的好处,即提供可扩展性和基础架构可移植性的基础架构,这是非常值得的。
虽然Kubernetes确实可以实现容器的操作可扩展性和管理,但它并不直接帮你管理Kubernetes本身所依赖的基础设施。Kubernetes本身就是一个应用(或者说是一组应用),这些应用需要在某处运行起来。尽管你可能听过,Kubernetes它不是个操作系统,但仍依赖于要安装在节点上的Linux或Windows系统。Kubernetes可以在例如AWS或GCE这类云服务商,或者是VMware这类虚拟化平台上运行,但所有这些仍然需要首先安装操作系统。(某些例如AWS EKS无需管理控制平面节点,但仍需要为工作节点设置Linux服务器。)
在操作上,重点是Kubernetes和它运行的工作负载,这本该如此,但这会导致一个在Kubernetes部署上常见的问题。虽然Kubernetes会定期打补丁和升级,但是关于底层操作系统的维护,更新,安全和操作往往被遗忘或忽视,至少在安全审计之前是这样的。我经常听SRE和系统管理员说,要同时管理Linux和Kubernetes,这导致额外的工作。就像一般的Linux操作系统一样,Kubernetes也需要打补丁、更新、保护和控制用户访问等等。但是,仅仅因为这些任务是在Kubernetes级别上完成的,并不意味着它们在操作系统级别上可被忽略。不过,选择合适的底层操作系统发行版,可以在很大程度上减少维护操作系统的工作量,减轻不及时更新的影响。
因此,考虑到你需要先安装Linux才能在其上运行Kubernetes,这将涉及底层的操作系统,你应该选择运行哪个Linux发行版呢?可选的方案有很多,但它们通常分为两种,即容器优化的操作系统,或通用的操作系统。
通用Linux操作系统
这些是正常类型的Linux。
大部分人都熟悉运行通用类型Linux操作系统,例如Ubuntu、Debian、CentOS、RHEL或是Fedora。这是在Kubernetes集群中运行通用操作系统的主要优势之一,你的系统管理员将熟悉如何安装、更新和加固你的Linux发行版。可以使用现有的工具集来启动服务器,安装操作系统,并将其配置为基本的安全级别。现有的补丁管理和安全检测工具应该可以在这些系统上正常运行,即使在其上运行Kubernetes。
然而……
使用通用类型Linux系统,随之而来的是常见的Linux管理开销。这意味着用户账号管理,补丁管理,内核更新,服务防火墙,SSH安全,禁止root登陆,禁用未使用的守护进程,内核调优等等,都需要完成并保持最新。如前所述,这些任务中的大部分可以使用现有的工具例如Ansible,Chef,Puppet来完成,然而,更新清单或控制文件,使服务器配置文件适合Kubernetes主节点和工作节点,可以说并非易事。
另一个问题是操作系统更改与Kubernetes维护的协调。经常会出现不协调的情况,以至于在安装后操作系统仍保持原样。随着时间的推移,Kubernetes会(希望)升级,但底层的操作系统仍可能保持原样,慢慢地在各种包和已安装的内核中积累了已知的CVE(常见的漏洞和暴露)的负担。
理想情况下,你希望自动化平台(如Ansible或Puppet)与Kubernetes进行协调,以便可以在不影响Kubernetes操作的情况下升级节点的操作系统。这意味着操作系统需要:
- 设置节点为不可调度以便新工作负载不会调度到该节点上
- 驱逐该节点以让所有运行的Pod移动到其他节点
- 更新并给节点打补丁
- 设置节点为可调度
当然,该系统需要保证在同一时刻不会有过多的节点在更新,以保证集群的工作负载能力不会受到负面影响(节点也不要太少,以免大型集群的更新速度慢于补丁和更新的发布速度)。你可能希望协调操作系统更新与Kubernetes更新,以减少重启和中断,但你仍然需要在短时间内支持更关键的操作系统更新。
通用类型Linux操作系统的最大优势是工作人员对它的熟悉程度。这意味着他们将熟悉部署,同时也具备排障技术。他们可以安装并使用常用的操作系统工具例如tcpdump、strace、lsof等等。配置可以很轻易地更改,以纠正错误和测试替代方案(这既是好事,同时也是坏事!)缺点是需要保持系统管理的开销,以及需要与Kubernetes基础设施和操作协调更新。
容器专用操作系统
美国国家标准与技术研究所(NIST)关于定义容器专用的操作系统有一个很好的总结,列出了一些优点。
“容器专用主机操作系统是一种明确设计为只运行容器的极简主义操作系统,其禁用了所有其他服务和功能,并采用只读文件系统和其他加固做法。当采用容器专用操作系统,攻击面通常要比通用类型操作系统小得多,因此攻击和破坏容器专用主机操作系统的机会较少。综上,如果可以,各个组织都应尽可能使用容器专用主机操作系统。”引自“NIST Special Publication 800-190 Application Container Security Guide”
总结一下,显而易见的一点就是,操作系统运行的软件和包越少,攻击面越小,漏洞也越少。这让容器专用操作系统从一开始就明显更安全,即使缺少频繁打补丁。
容器专用操作系统也可以采用其他的安全方式,例如将根文件系统(最好是所有文件系统)设为只读,减轻任何漏洞可能带来的影响。
容器专用操作系统通常不运行(或不支持)包管理。这减少了安装或更新包引起冲突导致节点或服务停止运行的机会。由于没有Chef和Puppet等管理工具,运行不完整对系统运行稳定性造成不利影响的机会减少。取而代之的是,一个应用了所有更新和配置的完整的操作系统镜像被安装在一个备用的启动机制中,并在下一次重启时被启动,或回退到之前已知的工作良好的镜像。这意味着,节点的配置在任何时候都是完全已知的,任何版本都可以从使用的版本控制系统中还原。
一些容器专用的操作系统更像通用Linux发行版,例如VMware公司的PhotonOS与普通Linux发行版相比,安装的包数量较少,但仍然包括包管理器、SSH访问,并且不会将文件系统挂载为只读。人们有时会困惑的一点是,通用Linux系统的“云优化”版本仍然是通用Linux系统,如Ubuntu发布的“云镜像”,是“由Ubuntu工程部门定制的,可以在公共云上运行”。然而,这些仍然是完整的Linux发行版,安装了所有的包,只是多了一个cloud-init包,这样可以更容易地配置启动,而无需人工干预。
CoreOS是第一个被普遍采用的容器专用操作系统,并普及了在容器中运行所有进程以提高安全性和隔离性的理念。CoreOS取消了软件包管理器,并使用重启到两个只读/usr分区中的一个,以确保更新是原子的,并可以回滚。不过自从CoreOS被RedHat收购后,该项目就被终结了。
当前的容器专用操作系统都采用最小的姿态(在操作系统中安装的软件包很少);锁定(在一定程度上);在容器中运行进程(为了更好的安全性、稳定性和服务隔离),并提供原子更新(通过启动到一个可启动分区,并更新另一个分区)。这样的例子有:
- Google的Container-Optimized OS,支持只读的根文件系统,但允许SSH,且只在GCP中运行。
- RancherOS,其运行SSH,不使用只读文件系统来保护根分区
- K3OS,也是由Rancher开发的,但没有运行完整的Kubernetes发行版。管理是通过kubectl,但支持SSH。
- AWS Bottlerocket是另一个具有不可改变的根文件系统和支持SSH的操作系统,也就是至少在初期,它专注于AWS的工作负载。
Talos是一个例外,它是容器专用操作系统中意见最大的一个。和其他系统一样,Talos操作系统也是最小化的,没有包管理器,只使用只读文件系统(除了/var和/etc/kubernetes,以及一两个短暂可写(重启时重置)的特殊文件,如/etc/resolv.conf),并通过升级控制器与K8s集成升级。
然而,Talos操作系统比其他系统更进一步地提出了不可变基础设施的理念,它取消了所有SSH和控制台访问,并使所有的OS访问和管理通过API驱动。在运行Kubernetes的节点上,你想做的所有事情都有API调用,查看所有的容器,检查网络设置等。但在节点上你没办法做不该做的事情,比如卸载文件系统。Talos还选择完全重写Linux Init系统,它只做一件事,那就是启动Kubernetes。
不能管理任何用户定义的服务(这些都应该通过Kubernetes管理),这进一步提高了安全性(没有SSH,没有控制台),减少了维护(没有用户,没有补丁),降低了任何CVE的影响(因为文件系统是不可变的,是短暂的)。你可能不同意放弃SSH访问,限制SRE的动作,强迫节点完全不可变的观点是可取的,但这也是不久前反对不可变容器的论点,这值得探究。拥有一个API管理的操作系统也非常适合大规模的操作和管理,如果你需要检查一个节点、一类节点或者所有节点上的某个容器的日志,那就是使用不同参数的同一个API调用而已。
总结
如果你已经采用了容器管理是“牛而非宠物(即生产软件基础设施可随时替换)”的观点,即在部署更新或修复时,销毁容器并启用一个新版本,那么确保对支持容器的基础设施采用同样的方法是有意义的。采用类似于容器的管理模式,销毁和重新配置节点以进行更新,而不是打补丁,这可能需要一些培训,但是采用容器专用的操作系统有助于采用这种模式,减少管理开销,并提高安全性。容器专用操作系统还有助于提高运行稳定性,系统管理员或开发人员无需更改配置以使其工作,从而消除了人为错误或错误配置导致下一次升级失败的可能性。
鉴于许多企业仍处于Kubernetes采用生命周期的早期,现在是熟悉这个下一代操作系统的好时机。通过将操作系统与Kubernetes紧密结合在一起,可以将整个Kubernetes集群作为一台计算机来对待,减少开销,并促进增强安全性。这让人们的注意力仍然集中在计算基础设施所提供的工作负载和价值上,是向API驱动的数据中心迈出的又一步。