美国时间 2019 年 11 月 13 日,Helm 团队宣布 Helm 3 第一个稳定版本发布。Helm 3 以 Helm 2 的核心功能为基础,对 Chart repo、发行版管理、安全性和 library Charts 进行了改进。
相比 Helm 2,Helm 3 最明显的变化是 Tiller 的删除,它新增丰富功能,某些功能已被弃用或重构,与 Helm 2 不再兼容。此外,Helm 3 还引入了一些新的实验功能,包括 OCI 支持。
Helm Go SDK 已重构为通用,目标是共享和重用 Go 社区开源代码。
Helm V2安装
1.Helm 客户端安装
Helm 的安装方式很多,这里采用二进制的方式安装。更多安装方法可以参考 Helm 的官方帮助文档 -https://helm.sh/docs/intro/install/
方式一:使用官方提供的脚本一键安装
curl -LO https://git.io/get_helm.sh # Helm V2 -https://v2.helm.sh/docs/using_helm/#installing-helm
$ chmod 700 get_helm.sh
$ ./get_helm.sh
方式二:手动下载安装
#从官网下载最新版本的二进制安装包到本地:https://github.com/kubernetes/helm/releases
tar -zxvf helm-2.16.6.tar.gz
# 解压压缩包
mv helm-2.16.6/helm /usr/local/bin/helm
helm help # 验证
更换仓库:
若遇到Unable to get an update from the “stable” chart repository (https://kubernetes-charts.storage.googleapis.com) 错误, 手动更换stable 存储库为阿里云的存储库
# 先移除原先的仓库
helm repo remove stable
# 添加新的仓库地址
helm repo add stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
# 更新仓库
helm repo update
2)查看在存储库中可用的所有 Helm charts:helm search repo stable
3)更新charts列表:helm repo update
2. Helm 服务端安装Tiller
Tiller 是以 Deployment 方式部署在 Kubernetes 集群中的
$ helm init # 这个命令会在本地初始化配置,同时在远程 k8s 上的 kube-system 中安装服务端应用,也就是 Tiller
参数:
–client-only:也就是不安装服务端应用,这在 CI&CD 中可能需要,因为通常你已经在 k8s 集群中安装好应用了,这时只需初始化 helm 客户端即可;
–history-max:最大历史,当你用 helm 安装应用的时候,helm 会在所在的 namespace 中创建一份安装记录,随着更新次数增加,这份记录会越来越多;
–tiller-namespace:默认是 kube-system,你也可以设置为其它 namespace;
# 创建服务端
helm init --service-account tiller --upgrade -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.16.6 --stable-repo-url https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
# 创建TLS认证服务端,参考地址:https://github.com/gjmzj/kubeasz/blob/master/docs/guide/helm.md
helm init --service-account tiller --upgrade -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.16.6 --tiller-tls-cert /etc/kubernetes/ssl/tiller001.pem --tiller-tls-key /etc/kubernetes/ssl/tiller001-key.pem --tls-ca-cert /etc/kubernetes/ssl/ca.pem --tiller-namespace kube-system --stable-repo-url https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
给 Tiller 授权
Helm 的服务端 Tiller 是一个部署在 Kubernetes 中 Kube-System Namespace 下 的 Deployment,它会去连接 Kube-Api 在 Kubernetes 里创建和删除应用。
而从 Kubernetes 1.6 版本开始,API Server 启用了 RBAC 授权。目前的 Tiller 部署时默认没有定义授权的 ServiceAccount,这会导致访问 API Server 时被拒绝。所以我们需要明确为 Tiller 部署添加授权。
pods “tiller-deploy-57d54b6d77-“ is forbidden: error looking up service account kube-system/tiller: serviceaccount “tiller” not found
创建 Kubernetes 的服务帐号和绑定角色
kubectl create serviceaccount --namespace kube-system tiller
kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
为 Tiller 设置帐号
# 使用 kubectl patch 更新 API 对象kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
创建rbac-config.yaml,并输入以下内容:
apiVersion: v1
kind: ServiceAccount
metadata:
name: tiller
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: tiller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: tiller
namespace: kube-system
然后执行 kubectl create -f rbac-config.yaml
, 查看是否授权成功
$ kubectl get deploy --namespace kube-system tiller-deploy --output yaml|grep serviceAccount
$ kubectl -n kube-system get pods|grep tiller
$ helm version
Helm V3安装
方式一:使用官方提供的脚本一键安装
$ curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 #Helm V3
$ chmod 700 get_helm.sh
$ ./get_helm.sh
方式二:手动下载安装
tar -zxvf helm-v3.1.0-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin/helm
helm help
# 添加官网仓库
helm repo add stable https://kubernetes-charts.storage.googleapis.com/
# 获取最新charts
helm repo update
在Linux下,默认配置的一些目录为:
- Cache Path:$HOME/.cache/helm
- Configuration Path:$HOME/.config/helm
- Data Path:$HOME/.local/share/helm
Helm V3变化
V3架构性变化 - 移除Tiller,简化安全模型,集群管理员可以按照自己认为合适的粒度限制用户权限
在 Helm 2 中,一次基于 Helm 的软件交付会涉及到多个组件:
在 Helm 2 中,Tiller 是作为一个 Deployment 部署在 kube-system 命名空间中,很多情况下,我们会为 Tiller 准备一个 ServiceAccount ,这个 ServiceAccount 通常拥有集群的所有权限。用户可以使用本地 Helm 命令,自由地连接到 Tiller 中并通过 Tiller 创建、修改、删除任意命名空间下的任意资源。
然而在多租户场景下,这种方式也会带来一些安全风险,我们即要对这个 ServiceAccount 做很多剪裁,又要单独控制每个租户的控制,这在当前的 Tiller 模式下看起来有些不太可能。
于是在 Helm 3 中,Tiller 被移除了。新的 Helm 客户端会像 kubectl 命令一样,读取本地的 kubeconfig 文件,使用我们在 kubeconfig 中预先定义好的权限来进行一系列操作。这样做法即简单,又安全。
虽然 Tiller 文件被移除了,但 Release 的信息仍在集群中以 ConfigMap 的方式存储,因此体验和 Helm 2 没有区别。
Tiller 变更引入的新变化 - Release 不再是全局资源, 而是存储在各自命名空间内
在 Helm 2 中,Tiller 自身部署往往在 kube-system 下,虽然不一定是 cluster-admin 的全局管理员权限,但是一般都会有 kube-system 下的权限。当 Tiller 想要存储一些信息的时候,它被设计成在 kube-system 下读写 ConfigMap
在 Helm 3 中,Helm 客户端使用 kubeconfig 作为认证信息直接连接到 Kubernetes APIServer,不一定拥有 cluster-admin 权限或者写 kube-system 的权限,因此它只能将需要存储的信息存在当前所操作的 Kubernetes Namespace 中,继而 Release 变成了一种命名空间内的资源。
Values 支持 JSON Schema 校验器
Helm Charts 是一堆 Go Template 文件、一个变量文件 Values 和一些 Charts 描述文件的组合。Go Template 和 Kubernetes 资源描述文件的内容十分灵活,在开发迭代过程中,很容易出现一些变量未定义的问题。
Helm 3 引入了 JSON Schema 校验,它支持用一长串 DSL 来描述一个变量文件的格式、检查所有输入的变量的格式。当我们运行 helm install 、 helm upgrade 、 helm lint 、 helm template 命令时,JSON Schema 的校验会自动运行,如果失败就会立即报错。
当我们指定一个 JSON Schema 文件为下述时:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"image": {
"description": "Container Image",
"properties": {
"repo": {
"type": "string"
},
"tag": {
"type": "string"
}
},
"type": "object"
},
"name": {
"description": "Service name",
"type": "string"
},
"port": {
"description": "Port",
"minimum": 0,
"type": "integer"
},
"protocol": {
"type": "string"
}
},
"required": [
"protocol",
"port"
],
"title": "Values",
"type": "object"
}
我们看到 JSON Schema 描述文件中指定了 protocol 和 port 为必填字段,于是我们可以指定一个 values.yaml 如下:
name: frontend
protocol: https
port: 443
但事实上,我们也可以指定为如下,因为我们可以在 helm 命令行传入变量参数,例如 helm install —set port=443
name: frontend
protocol: https
试验性功能 - 推送 Charts 到容器镜像仓库中
互联网上有一些 Helm Charts 托管平台,负责分发常见的开源应用,例如 Helm Hub、KubeApps Hub。
在企业环境中,用户需要私有化的 Helm Charts 托管。最常见的方案是部署 ChartMuseum,使其对接一些云存储。当然也有一些较为小众的方案,比如 App-Regsitry 直接复用了 Docker 镜像仓库 Registry V2,再比如 helm-s3 直接通过云存储 S3 存取 Charts 文件。
如今在 Helm 3,Helm 直接支持了推送 Charts 到容器镜像仓库的能力,希望支持满足 OCI 标准的所有 Registry。但这部分还没有完全被开发完,会在未来的 alpha 版本中被完善。
代码复用 - Library Chart 支持
Helm 3 中引入了一种新的 Chart 类型,名为 Library Chart 。它不会部署出一些具体的资源,只能被其他的 Chart 所引用,提高代码的可用复用性。当一个 Chart 想要使用该 Library Chart 内的一些模板时,可以在 Chart.yaml 的 dependencies 依赖项中指定。
其他的一些变化
- Go Import 的路径由 k8s.io/helm 变成了 helm.sh/helm。
- 简化了 Chart 内置变量 Capabilities 的一些属性[2]。
- helm install 不再默认生成一个 Release 的名称,除非指定了 —generate-name 。
- 移除了用于本地临时搭建 Chart Repository 的 helm serve 命令。
- requirements.yaml 被整合到了 Chart.yaml 中,但格式保持不变。
- helm delete 更名为 helm uninstall ,
- helm inspect 更名为 helm show ,
- helm fetch 更名为 helm pull ,但以上旧的命令当前仍能使用
Helm-V3 变化 —Tiller Server Removed
为什么 Helm 要坚持在 K8s 放置一个 Server 端呢?这里其中一个重要的原因,在于 Helm 项目并不只希望做一个简单“ K8s 应用打包工具”。
作为一个地道的 PaaS 服务商,Deis 公司从一开始就知道“应用打包”只是自己完整拼图的入口,而 Tiller 的存在,则是让 Helm 成为未来云原生时代“新 PaaS” 的重要伏笔。
Tiller 这个服务端组件,其实相当于 Helm 在 K8s 内插入的一个应用管理控制器。有了它,Helm 不仅可以很容易在 K8s 侧存储应用相关的状态,还可以基于 Tiller 在 K8s 内逐步构建出一个微型 PaaS 的功能。并且,这些功能的设立和发展,都不需要依赖于 K8s 本身的应用管理能力。
这也解释了为何 Helm 很快就提出了 Release 的概念,发布了 helm upgrade 、 helm rollback 等应用升级和回滚的能力。这些设计,其实都与 Helm 最终 PaaS 化的思路有着千丝万缕的联系。
不过,Helm 的这条演进路线,在 Kubernetes 这个天生以“应用”为中心的基础设施体系里,却实实在在的栽了个跟头。
我们知道,Kubernetes 是围绕着声明式 API 来设计的。Kubernetes 的容器编排理念以及 APIServer 实现与扩展机制,其本质目的都是为了帮助用户屏蔽掉基础设施管理的复杂性,允许用户通过统一而整洁的声明式 API 来描述自己的意图和诉求,这正是 Kubernetes 成为“ The Platform of Platform ”的重要基础。
这也是为何,Kubernetes 从一开始就对容器进行组合,以便借助 Pod 的概念来模拟进程组的行为;并且坚持使用声明式 API 搭配控制器模型来进行应用编排,通过 API 资源对象的创建与更新( PATCH )来驱动整个系统的持续运转。
这种设计的最终效果,就是用户只需要将一个“描述”应用的 YAML 文件,放在 etcd 里存起来,然后通过控制器模型驱动整个基础设施的状态不断地向用户声明的状态逼近,就也就是 Kubernetes 的核心工作原理了。这套理论,正是 Google Borg/Omega 进行应用管理和编排的核心与基础,同时也是 K8s 同 Mesos 这种资源管理器项目最大的区别。
这时候,我们也就不难发现。Helm 试图在推进的一些事情,跟 K8s 的设计发生了正面冲突。
理论上来讲,Helm 只需要将应用描述文件提交给 K8s ,剩下的应用启动、发布和回滚等操作,就都交给 K8s 即可。比如在 K8s 的 Deployment 语义中,已经为用户提供了非常详细的滚动更新策略,这些都是应用描述( YAML 文件)里的主要字段:
yaml
strategy:
type: Rolling
rollingParams:
updatePeriodSeconds: 1
intervalSeconds: 1
timeoutSeconds: 120
maxSurge: “20%”
maxUnavailable: “10%”
但是现在,Helm 自己也内置了应用的更新和回滚策略,并且它们与 K8s 的策略没有什么关系、都通过 Tiller 帮你完成。
这就让用户陷入了一种非常尴尬的境地:我到底还要不要定义和使用 K8s 的滚动更新参数了?
除此之外,Tiller 事实上还接管了其他一些的 K8s 核心功能,比如 PATCH API 的实现。这些都让用户感觉到困惑,毕竟在绝大多数情况,用户都是先学习了 K8s API 然后再开始使用 Helm 的。当然,Helm 项目当初做出这样的决定其实也是可以理解的。
在 2016~2017 年,应用管理并不是 K8s 主要透出来的核心能力,很少有人能够意识到 K8s 异常复杂的声明式 API 、尤其是 PACTH API 到底意味着什么————哪怕“ K8s 声明式应用配置”的大部分理论实际上一直存在于 K8s 文档库最不显眼的一个角落中。所以,在那个时候,大家在 K8s 之上进行应用管理第一个想到的 idea ,基本都是在 K8s 里安装一个 Controller 来实现。实际上,当时 Google Cloud 团队自己也提出了一个叫做 Deployment Manager的插件,这个插件后来跟 Tiller 部分合并在了一起。
但开源社区魔力就在于用户“用脚投票”的神奇力量。
Helm 项目作为 “ K8s 包管理工具”的人设,让这个项目在云原生社区风生水起;但与此同时, Tiller 这个奇怪的存在,也成为了 Helm 项目进一步向前发展的绊脚石。长久以来,Tiller 组件带来的使用困惑、安全隐患、部署维护的复杂度,几乎占据了 Helm 社区的绝大多数板块。一些厂商甚至干脆自己发布了“去 Tiller 版”的 Helm 发行版来表示“抗议“。
而另一方面, K8s 的声明式应用管理思路也没有走向外置 Controller 的方式去解决,而是选择继续在 K8s 本身去丰富和完善应用管理与发布能力,这很快也成为了整个 K8s 社区投入的重中之重(这个故事,我们在后续的《云原生应用管理系列文章》中会为你进行进一步的介绍)。这也就使得 Helm 本身内置的应用管理体系开始与上游社区渐行渐远。
当生态和社区都开始与项目的发展背道而驰的时候,“自我革命”就自然成为了一个势在必行的选择。
Helm v3,云原生应用管理的重要里程碑
除了移除 Tiller、让 Helm 变成纯客户端工具之外,Helm v3 相对于 Helm v2 ,还有如下一些重要变化:
- Release 名字可缩小至 Namespace 范围,需要显示启用选项 —generate-name :这进一步规范和完善了 Helm 应用的名称问题;
- 合并描述应用依赖的 requirements.yaml 到 Chart.yaml:进一步减小用户的学习负担
- 支持 helm push 到远端 Helm Hub ,支持登陆认证;
- 支持在容器镜像 Registry 中存储 Charts:消除 Helm Hub 和 DockerHub 的重合定位
- 支持 LUA 语法:现有的模板变量,实际上问题很大,我们在后续文章中会详细介绍;
- 对 values.yaml 里的内容进行验证;
- …
关于 Helm v3 的详细解读和实例,你可以继续阅读这篇《深度解读Helm 3:犹抱琵琶半遮面》来一探究竟。
经历了这样的重构之后,Helm v3 已经开始调整自己的发展方向,淡化了做一个“微型 PaaS”的思路,更多的关注于应用打包和基础管理功能,将更多的自由度和发挥空间交换给了 K8s 社区。
这个变化,无论是对于 Helm 社区还是云原生应用开发者来说,都是喜闻乐见的。不难预料,Helm v3 很大概率会成为未来云原生应用管理体系中的一个重要工具,而与之相对应的 App Hub ,也会成为云应用分发与托管过程中的重要环节。
Helm3命令变化
Helm 3: 不再存在的Helm 2的命令
在前面的文章示例中,我们发现helm init已经在Helm 3中不存在了。类似的共有如下7条命令,在Helm 3中或删除或改名或则功能增强,比如因为Tiller的去除,所以导致了reset命令没有存在的意义,同时init存在仅剩客户端需要设定的功能,所以被去除了。另外诸如fetch命令,而在Helm 3中提供了pull命令予以替代。本来home命令用于显示HELM_HOME环境变量,而在Helm 3中提供env命令可以显示所有的环境变量信息,用增强的功能予以了替换。但是无论如何,总之已经无法在Helm 3中直接使用如下7条命令。
Helm 3: 相较与Helm 2新增的命令
稍作分析,会发现如下事实: