Kubernetes的软件包管理器-Helm:过去,现在,将来

注意事项 佩雷夫 :在本文中,我们打开了一系列有关Kubernetes软件包管理器的出版物,我们在日常工作中积极使用它们-Helm。 该材料的原始作者是Helm项目的创始人之一Matt Butcher,他在Microsoft从事开源项目,并撰写了8本技术书籍(特别是“ Go in Practice”)。 但是,本文以我们的评论(有时是广泛的评论)作为补充,并且很快将以关于Helm的新注释(以更实际的重点)进一步扩展。 更新 (09/03/2018):续集问世-“ 熟悉Kubernetes的软件包管理器-Helm ”。



6月,Helm从Kubernetes的领导项目职位移交给了Cloud Native Computing Foundation(CNCF)。 CNCF正在成为同类最佳开源云本机工具的母公司。 因此,Helm成为这样一个基金会的一部分是非常荣幸的。 在CNCF的主持下,我们的第一个重要项目确实是大规模的:我们创建了Helm 3。

头盔简史


Helm最初是作为Deis开源项目出现的。 它是根据Homebrew (macOS的软件包管理器- 大约是Transl。建模的,Helm 1的任务为用户提供了一个便利的机会,可以在Kubernetes上快速安装他们的第一个工作负载。 Helm的官方公告于2015年第一届KubeCon旧金山会议上发布。

注意事项 trans 。:从第一个版本dm(Deployment Manager)开始,选择了YAML语法来描述Kubernetes资源,并且在编写配置时支持Jinja模板和Python脚本。

一个简单的Web应用程序模板可能如下所示:

Yaml
resources: - name: frontend type: github.com/kubernetes/application-dm-templates/common/replicatedservice:v1 properties: service_port: 80 container_port: 80 external_service: true replicas: 3 image: gcr.io/google_containers/example-guestbook-php-redis:v3 - name: redis type: github.com/kubernetes/application-dm-templates/storage/redis:v1 properties: null 

在描述推出的应用程序的组件时,会指出名称,使用的模板以及该模板的必要参数。 在上面的示例中, frontendredis使用官方存储库中的模板。

在此版本中,由于模板的参数和嵌套,您可以使用来自公共知识库的资源,创建自己的模板存储库并构建复杂的应用程序。

Helm 1体系结构由三个组件组成。 下图说明了它们之间的关系:



  1. Manager执行Web服务器的功能(通过REST API与客户端通信),管理Kubernetes集群中的部署,并用作数据仓库。
  2. expandybird组件将用户配置呈现为扁平形式,即 应用Jinja模板并执行Python脚本。
  3. 收到平面配置后, resourcifier修复程序对kubectl进行必要的调用,并将状态和错误消息(如果有)返回给manager

为了了解Helm第一版的功能,我将在dm命令上提供帮助
dm的帮助输出
 Usage: ./dm [<flags>] <command> [(<template-name> | <deployment-name> | (<configuration> [<import1>...<importN>]))] Commands: expand Expands the supplied configuration(s) deploy Deploys the named template or the supplied configuration(s) list Lists the deployments in the cluster get Retrieves the supplied deployment manifest Lists manifests for deployment or retrieves the supplied manifest in the form (deployment[/manifest]) delete Deletes the supplied deployment update Updates a deployment using the supplied configuration(s) deployed-types Lists the types deployed in the cluster deployed-instances Lists the instances of the named type deployed in the cluster templates Lists the templates in a given template registry (specified with --registry) registries Lists the registries available describe Describes the named template in a given template registry getcredential Gets the named credential used by a registry setcredential Sets a credential used by a registry createregistry Creates a registry that holds charts Flags: -apitoken string Github api token that overrides GITHUB_API_TOKEN environment variable -binary string Path to template expansion binary (default "../expandybird/expansion/expansion.py") -httptest.serve string if non-empty, httptest.NewServer serves on this address and blocks -name string Name of deployment, used for deploy and update commands (defaults to template name) -password string Github password that overrides GITHUB_PASSWORD environment variable -properties string Properties to use when deploying a template (eg, --properties k1=v1,k2=v2) -regex string Regular expression to filter the templates listed in a template registry -registry string Registry name (default "application-dm-templates") -registryfile string File containing registry specification -service string URL for deployment manager (default "http://localhost:8001/api/v1/proxy/namespaces/dm/services/manager-service:manager") -serviceaccount string Service account file containing JWT token -stdin Reads a configuration from the standard input -timeout int Time in seconds to wait for response (default 20) -username string Github user name that overrides GITHUB_USERNAME environment variable --stdin requires a file name and either the file contents or a tar archive containing the named file. a tar archive may include any additional files referenced directly or indirectly by the named file. 

现在回到有关头盔历史的原始文本...

几个月后,我们与Google的Kubernetes Deployment Manager团队合作,开始了Helm 2的工作。目标是通过添加以下内容,使Helm易于使用:

  1. 用于定制的图表模板(“图表”-Helm生态系统中包装的类似物- 大约翻译
  2. 团队的集群管理;
  3. 完整的图表存储库;
  4. 稳定且签名的软件包格式;
  5. 坚决支持语义版本控制并保持版本之间的向后兼容性。

为了实现这些目标,已将第二个组件添加到Helm生态系统中。 它成为内部的Tiller集群,提供了Helm图表的安装及其管理。

注意事项 perev。:因此,在Helm的第二个版本中,集群中剩余的唯一组件负责安装生命周期( release ),并且配置准备已提交给Helm客户端。

如果在使用第一个Helm版本时重启集群导致服务数据完全丢失(因为它们已存储在RAM中),则在Helm 2中所有数据都存储在ConfigMaps ,即 Kubernetes内部的资源。 另一个重要步骤是从同步API(每个请求都被阻止)过渡到使用异步gRPC。

自2016年推出《头盔2》以来,Kubernetes项目经历了爆炸性的增长和重大的新机遇。 已添加基于角色的访问控制(RBAC)。 引入了许多新的资源类型。 发明的第三方资源(自定义资源定义,CRD)。 最重要的是,有最佳实践。 经过所有这些更改,Helm继续满足Kubernetes用户的需求。 但是我们很清楚,是时候对其进行重大更改,以便继续满足这个发展中的生态系统的需求了。

因此,我们来到了Helm3。接下来,我将讨论项目路线图上的一些创新。

问候卢阿


在头盔2中,我们介绍了模板。 在Helm 2开发的早期,我们支持Go,Jinja模板,干净的Python代码,甚至还提供了ksonnet支持的原型。 但是,用于模板的许多引擎的出现带来了比其解决的问题更多的问题。 因此,我们已经选择了一个。

Go模板具有四个优点:

  1. 内置在Go中 ;
  2. 模板是在严格限制的沙箱环境中执行的;
  3. 我们可以在引擎中插入任意函数和对象
  4. 他们与YAML运作良好。

尽管我们在Helm中保留了接口以支持其他模板引擎,但Go模板已成为我们的默认标准。 接下来的几年经验表明,许多公司的工程师如何使用Go模板创建了数千张图表。

我们了解到他们的失望:

  1. 该语法难以阅读且文档记录不充分。
  2. 语言问题,例如不可变的变量,复杂的数据类型和限制性的可见性规则,已经将简单的事情变成了复杂的事情。
  3. 无法在模板中定义功能使创建可重用库变得更加困难。

最重要的是,使用模板语言,我们将Kubernetes对象“截断”为它们的线表示形式。 (换句话说,模板开发人员必须将Kubernetes资源作为YAML格式的文本文档进行管理。)

处理对象,而不是YAML片段


一次又一次,我们听到用户的要求,要求能够将Kubernetes资源作为对象而不是字符串进行检查和修改。 同时,他们坚持认为,无论我们为此选择哪种实施方式,都应该易于学习并在生态系统中得到良好维护。

经过几个月的研究,我们决定提供一种内置的脚本语言,可以将其打包在沙箱中并进行自定义。 在排名前20位的语言中,只有一种符合要求。

1993年,一群巴西IT工程师创建了一种轻量级的脚本语言,以嵌入其工具中。 Lua的语法很简单,得到了广泛的支持,并且长期以来一直在前20种语言名列前茅 。 IDE和文本编辑器都支持它,其中有许多手册和教程。 在这样一个现有的生态系统中,我们想开发我们的解决方案。

我们在Helm Lua上的工作仍处于概念验证阶段,我们期望语法既熟悉又灵活。 比较旧方法和新方法,您可以看到我们的发展方向。

这是Helm 2中带有Alpine的炉膛模板的示例

 apiVersion: v1 kind: Pod metadata: name: {{ template "alpine.fullname" . }} labels: heritage: {{ .Release.Service }} release: {{ .Release.Name }} chart: {{ .Chart.Name }}-{{ .Chart.Version }} app: {{ template "alpine.name" . }} spec: restartPolicy: {{ .Values.restartPolicy }} containers: - name: waiter image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} command: ["/bin/sleep", "9000"] 

在这个简单的模板中,您可以立即看到所有内置模板指令,例如{{ .Chart.Name }}

这是Lua代码的初始版本中相同炉床的定义:

 unction create_alpine_pod(_) local pod = { apiVersion = "v1", kind = "Pod", metadata = { name = alpine_fullname(_), labels = { heritage = _.Release.Service or "helm", release = _.Release.Name, chart = _.Chart.Name .. "-" .. _.Chart.Version, app = alpine_name(_) } }, spec = { restartPolicy = _.Values.restartPolicy, containers = { { name = waiter, image = _.Values.image.repository .. ":" .. _.Values.image.tag, imagePullPolicy = _.Values.image.pullPolicy, command = { "/bin/sleep", "9000" } } } } } _.resources.add(pod) end 

无需查看本示例的每一行来了解正在发生的事情。 很明显,在代码中对其进行了定义。 但是,我们没有将YAML字符串与内置模板指令一起使用,而是将其定义为Lua中的对象。

让我们缩短这段代码


由于我们直接处理对象(而不是处理大量文本),因此我们可以充分利用脚本编写的优势。 创建出现在此处的共享库的机会看起来非常吸引人。 我们希望通过引入专门的库(或允许社区创建它们),可以将上述代码简化为以下形式:

 local pods = require("mylib.pods"); function create_alpine_pod(_) myPod = pods.new("alpine:3.7", _) myPod.spec.restartPolicy = "Always" -- set any other properties _.Manifests.add(myPod) end 

在此示例中,我们使用将资源定义为对象的能力,可以轻松设置属性,同时保持代码的简洁性和可读性。

模板... Lua ...为什么不全部在一起?


尽管这些模板并不是对所有任务都那么出色,但是它们仍然具有某些优势。 Go中的模板是一种稳定的技术,具有已建立的用户群和许多现有图表。 许多图表开发人员声称喜欢编写模板。 因此,我们不会删除模板支持。

相反,我们希望同时使用模板和Lua。 Lua脚本在渲染之前和之后都可以访问Helm模板,这将允许高级图表开发人员在现有图表上执行复杂的转换,同时保留使用模板创建Helm图表的简单功能。

Lua上脚本的支持使我们感到非常鼓舞,但与此同时,我们摆脱了Helm架构的重要组成部分...

向蒂勒说再见


在Helm 2的开发过程中,我们引入了Tiller作为Deployment Manager的集成组件。 对于在同一集群上工作的团队,Tiller发挥了重要作用:它使得与许多不同管理员的同一组发行版进行交互成为可能。

但是,蒂勒充当了巨大的sudo服务器,为所有有权访问蒂勒的人赋予了广泛的权利。 我们的默认安装方案是许可配置。 因此,DevOps和SRE工程师必须学习在多租户群集中安装Tiller的其他步骤。

而且,随着CRD的出现,我们不再能够可靠地依靠Tiller来维持状态或充当Helm发布信息的中心枢纽。 我们只能将此信息存储为Kubernetes中的单独条目。

无需耕iller机本身即可实现耕iller机的主要目标。 因此,在Helm 3计划阶段做出的第一个决定就是完全放弃Tiller。

安全改善


没有Tiller,Helm安全模型将得到根本简化。 用户身份验证由Kubernetes委托。 还有授权。 Helm权限定义为Kubernetes权限(通过RBAC),并且群集管理员可以在任何所需的详细信息级别限制Helm权限。

版本,ReleaseVersions和状态存储


在没有Tiller的情况下,要维持集群中各个发行版的状态,我们需要一种新的方式让所有客户端进行交互(基于发行版管理)。

为此,我们引入了两个新条目:

  1. Release -用于特定图表的特定安装。 如果我们运行helm install my-wordpress stable/wordpress ,则会在此WordPress安装的整个生命周期中创建并维护一个名为my-wordpress的版本。
  2. ReleaseVersion每次更新Helm图表时,都需要考虑已更改的内容以及更改是否成功。 ReleaseVersion与发行版绑定,仅存储包含有关更新,回滚和删除信息的记录。 当我们运行helm upgrade my-wordpress stable/wordpress ,原始的Release对象保持不变,但是会ReleaseVersion一个子ReleaseVersion对象,其中包含有关更新操作的信息。

ReleasesReleaseVersions将存储在与图表对象相同的名称空间中。

有了这些功能,Helm用户团队将能够跟踪群集中Helm安装的记录,而无需使用Tiller。

但是,等等,还不止这些!


在本文中,我尝试讨论了Helm 3中的一些主要更改。但是,此列表根本不完整。 Helm 3计划还包括其他更改,例如,图表格式的改进,图表存储库的性能改进以及图表开发人员可以使用的新事件系统。 通过清除代码库并更新在过去三年中失去相关性的组件,我们还将Eric Raymond称为代码考古

注意事项 佩雷夫 :这是一个悖论,但是Helm 2软件包管理器在installupgrade成功后,即 具有success释放状态并不能保证应用程序资源已成功推出(例如,不存在诸如ImagePullError错误)。 也许新的事件模型将允许您添加资源的附加挂钩并更好地控制部署过程-我们很快就会发现。

随着Helm加入CNCF,我们不仅受到Helm 3的启发,还受到Chart博物馆 ,出色的Chart Testing实用程序, 官方Chart资料库以及CNCF在Helm主持下的其他项目的启发。 我们相信,对于Linux良好的软件包管理器而言,良好的Kubernetes软件包管理对于云原生生态系统同样重要。

译者的PS


另请参阅我们的博客:

Source: https://habr.com/ru/post/zh-CN417079/


All Articles