Kubernetes 应用部署的挑战

Kubernetes 是一个提供了基于容器的应用集群管理解决方案,Kubernetes 为容器化应用提供了部署运行、资源调度、服务发现和动态伸缩等一系列完整功能。
Kubernetes 的核心设计理念是: 用户定义要部署的应用程序的规则,而 Kubernetes 则负责按照定义的规则部署并运行应用程序。如果应用程序出现问题导致偏离了定义的规格,Kubernetes 负责对其进行自动修正。例如:定义的应用规则要求部署两个实例(Pod),其中一个实例异常终止了,Kubernetes 会检查到并重新启动一个新的实例。
用户通过使用 Kubernetes API 对象来描述应用程序规则,包括 Pod、Service、Volume、Namespace、ReplicaSet、Deployment、Job等等。一般这些资源对象的定义需要写入一系列的 YAML 文件中,然后通过 Kubernetes 命令行工具 Kubectl 调 Kubernetes API 进行部署。
以一个典型的三层应用 Wordpress 为例,该应用程序就涉及到多个 Kubernetes API 对象,而要描述这些 Kubernetes API 对象就可能要同时维护多个 YAML 文件。
Helm快速入门 - 图1
从上图可以看到,在进行 Kubernetes 软件部署时,我们面临下述几个问题:

  • 如何管理、编辑和更新这些这些分散的 Kubernetes 应用配置文件。
  • 如何把一套相关的配置文件作为一个应用进行管理。
  • 如何分发和重用 Kubernetes 的应用配置。

Helm 的出现就是为了很好地解决上面这些问题。

Helm 组件及相关术语

helm

Helm 是一个命令行下的客户端工具。主要用于 Kubernetes 应用程序 Chart 的创建、打包、发布以及创建和管理本地和远程的 Chart 仓库。

Chart

Chart 是用来封装 Kubernetes 原生应用程序的一系列 YAML 文件。可以在你部署应用的时候自定义应用程序的一些 Metadata,以便于应用程序的分发。

  • 对于应用发布者而言,可以通过 Helm 打包应用、管理应用依赖关系、管理应用版本并发布应用到软件仓库。
  • 对于使用者而言,使用 Helm 后不用需要编写复杂的应用部署文件,可以以简单的方式在 Kubernetes 上查找、安装、升级、回滚、卸载应用程序。

一个Chart就是一个Helm包,包含运行一个应用必要的资源文件(其表现形式就是 .tgz 格式的压缩包),通过Chart将资源(PV、PVC、Pod、Service、Ingress等)整合在一起

Repository

Helm 的软件仓库,Repository 本质上是一个 Web 服务器,该服务器保存了一系列的 Chart 软件包以供用户下载,并且提供了一个该 Repository 的 Chart 包的清单文件以供查询。Helm 可以同时管理多个不同的 Repository。

Release

使用 helm install 命令在 Kubernetes 集群中部署的 Chart 称为 Release。可以理解为 Helm 使用 Chart 包部署的一个应用实例。一个Chart可以被多次安装,每次安装都会有不同的Release 产生,用来标识在 k8s 中运行的一组资源。
有了 release,helm 在操作 k8s 时,就再也不用逐个管理资源,而可以将一组相关的资源当做一个整体来操作,比如删除或升级

Helm3 与 Helm2 区别

Helm2&Helm3对比
Helm 3.0.0 于 2019.11.13 宣告发布,Helm3 与 Helm2 相比发生了很大变更。

  • Helm2
    • 使用C/S架构,由Helm Client、Tiller Server组成。
    • Helm Client 是一个命令行工具,负责和Tiller 交互
    • Tiller Server 内置在K8s集群中,通过K8s API Server与K8s交互
  • Helm3
    • 最重大的变更:移除了Tiller,Helm client直接通过 K8s API Server 交互
    • 移除了用于托管本地Chart Repository 的 helm serve 命令
    • Release 不再是全局资源,直接存储在namespace中
    • Helm3 发布6个月后Helm2不再修复Bug,只处理安全问题
    • 降低了安装、运维复杂性,提高安全性
    • 需要 k8s v1.6+ 支持,k8s以前版本不支持RBAC(基于角色的访问控制)
    • 部分命令更名
      1. helm delete => helm uninstall
      2. helm inspect => helm show
      3. helm fetch => helm pull

      Helm命令

      ```shell root@xxx-dev1:~$ helm -h The Kubernetes package manager

Common actions for Helm:

  • helm search: search for charts
  • helm pull: download a chart to your local directory to view
  • helm install: upload the chart to Kubernetes
  • helm list: list releases of charts

Environment variables:

Name Description
$HELM_CACHE_HOME set an alternative location for storing cached files.
$HELM_CONFIG_HOME set an alternative location for storing Helm configuration.
$HELM_DATA_HOME set an alternative location for storing Helm data.
$HELM_DEBUG indicate whether or not Helm is running in Debug mode
$HELM_DRIVER set the backend storage driver. Values are: configmap, secret, memory, postgres
$HELM_DRIVER_SQL_CONNECTION_STRING set the connection string the SQL storage driver should use.
$HELM_MAX_HISTORY set the maximum number of helm release history.
$HELM_NAMESPACE set the namespace used for the helm operations.
$HELM_NO_PLUGINS disable plugins. Set HELM_NO_PLUGINS=1 to disable plugins.
$HELM_PLUGINS set the path to the plugins directory
$HELM_REGISTRY_CONFIG set the path to the registry config file.
$HELM_REPOSITORY_CACHE set the path to the repository cache directory
$HELM_REPOSITORY_CONFIG set the path to the repositories file.
$KUBECONFIG set an alternative Kubernetes configuration file (default “~/.kube/config”)
$HELM_KUBEAPISERVER set the Kubernetes API Server Endpoint for authentication
$HELM_KUBECAFILE set the Kubernetes certificate authority file.
$HELM_KUBEASGROUPS set the Groups to use for impersonation using a comma-separated list.
$HELM_KUBEASUSER set the Username to impersonate for the operation.
$HELM_KUBECONTEXT set the name of the kubeconfig context.
$HELM_KUBETOKEN set the Bearer KubeToken used for authentication.

Helm stores cache, configuration, and data based on the following configuration order:

  • If a HELM_*_HOME environment variable is set, it will be used
  • Otherwise, on systems supporting the XDG base directory specification, the XDG variables will be used
  • When no other location is set a default location will be used based on the operating system

By default, the default directories depend on the Operating System. The defaults are listed below:

Operating System Cache Path Configuration Path Data Path
Linux $HOME/.cache/helm $HOME/.config/helm $HOME/.local/share/helm
macOS $HOME/Library/Caches/helm $HOME/Library/Preferences/helm $HOME/Library/helm
Windows %TEMP%\helm %APPDATA%\helm %APPDATA%\helm

Usage: helm [command]

Available Commands: completion generate autocompletion scripts for the specified shell create create a new chart with the given name dependency manage a chart’s dependencies env helm client environment information get download extended information of a named release help Help about any command history fetch release history install install a chart lint examine a chart for possible issues list list releases package package a chart directory into a chart archive plugin install, list, or uninstall Helm plugins pull download a chart from a repository and (optionally) unpack it in local directory repo add, list, remove, update, and index chart repositories rollback roll back a release to a previous revision search search for a keyword in charts show show information of a chart status display the status of the named release template locally render templates test run tests for a release uninstall uninstall a release upgrade upgrade a release verify verify that a chart at the given path has been signed and is valid version print the client version information

Flags: —debug enable verbose output -h, —help help for helm —kube-apiserver string the address and the port for the Kubernetes API server —kube-as-group stringArray group to impersonate for the operation, this flag can be repeated to specify multiple groups. —kube-as-user string username to impersonate for the operation —kube-ca-file string the certificate authority file for the Kubernetes API server connection —kube-context string name of the kubeconfig context to use —kube-token string bearer token used for authentication —kubeconfig string path to the kubeconfig file -n, —namespace string namespace scope for this request —registry-config string path to the registry config file (default “/home/ngdn/.config/helm/registry.json”) —repository-cache string path to the file containing cached repository indexes (default “/home/ngdn/.cache/helm/repository”) —repository-config string path to the file containing repository names and URLs (default “/home/ngdn/.config/helm/repositories.yaml”)

  1. <a name="fKQNG"></a>
  2. ### Repository 相关操作
  3. <a name="jxvrg"></a>
  4. #### 添加常用仓库
  5. ```shell
  6. $ helm repo add stable https://kubernetes-charts.storage.googleapis.com/
  7. $ helm repo add bitnami https://charts.bitnami.com/bitnami
  8. $ helm repo add incubator https://kubernetes-charts-incubator.storage.googleapis.com/
  9. $ helm repo update # Make sure we get the latest list of charts

列出仓库可安装的charts

helm search repo stable
NAME                                    CHART VERSION   APP VERSION                     DESCRIPTION
stable/acs-engine-autoscaler            2.2.2           2.1.1                           DEPRECATED Scales worker nodes within agent pools
stable/aerospike                        0.2.8           v4.5.0.5                        A Helm chart for Aerospike in Kubernetes
stable/airflow                          4.1.0           1.10.4                          Airflow is a platform to programmatically autho...
stable/ambassador                       4.1.0           0.81.0                          A Helm chart for Datawire Ambassador
# ... and many more

Chart 相关操作

# 创建chart目录结构, 仅保留deployment, service, 删除其他对象
helm create nginx

# 打成chart包
helm package nginx
Successfully packaged chart and saved it to:/root/nginx-0.1.0.tgz

# 检索chart
helm search repo stable/mysql

# 查看chart信息
helm show chart stable/mysql

# 查看chart values.yaml
helm show values stable/mysql

# 拉取mysql chart
helm pull stable/mysql
# 将chart目录打成chart压缩包

helm package dirName
# 模拟安装
helm install --dry-run --debug demo1 --generate-name

Release相关操作

Release 查看

$ helm ls

Release 安装

在线安装指定的 chart,比如 nginx-ingress。

$ helm repo add nginx-stable https://helm.nginx.com/stable
$ helm repo update

$ helm search repo nginx-ingress
NAME                            CHART VERSION   APP VERSION     DESCRIPTION
apphub/nginx-ingress            1.30.3          0.28.0          An nginx Ingress controller that uses ConfigMap...
apphub/nginx-ingress-controller 5.3.4           0.29.0          Chart for the nginx Ingress controller
nginx-stable/nginx-ingress      0.15.1          2.4.1           NGINX Ingress Controller
apphub/nginx-lego               0.3.1                           Chart for nginx-ingress-controller and kube-lego

$ helm install mynginx-ingress nginx-stable/nginx-ingress

Release 更新

如果想修改运行时 Release 的配置,可以使用 —set 或者 -f 选项进行修改。
1. 基于命令行更新 Release

# mynginx-ingress 是上面创建的 release 名;nginx-stable/nginx-ingress 是在线 chart 名

$ helm upgrade --set controller.hostNetwork=true mynginx-ingress nginx-stable/nginx-ingress
Release "mynginx-ingress" has been upgraded. Happy Helming!
NAME: mynginx-ingress
LAST DEPLOYED: Sat Jun 12 16:20:05 2021
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None
NOTES:
The NGINX Ingress Controller has been installed.

2. 基于文件更新 Release
如果想基于文件来更新 release,则首先需要将 chart 下载到本地,然后手动修改 chart 的 values.yaml 文件。

$ helm pull nginx-stable/nginx-ingress
# 下载 chart

$ tar zxf nginx-ingress-0.9.3.tgz
# 解压缩 chart

$ sed -i 's/hostNetwork: false/hostNetwork: true/g' nginx-ingress/values.yaml
# 修改 values.yaml 内容。比如修改 hostNetwork 的值为 true

$ helm upgrade mynginx-ingress nginx-ingress -f nginx-ingress/values.yaml
Release "mynginx-ingress" has been upgraded. Happy Helming!
NAME: mynginx-ingress
LAST DEPLOYED: Sat Jun 12 16:23:50 2021
NAMESPACE: default
STATUS: deployed
REVISION: 3
TEST SUITE: None
NOTES:
The NGINX Ingress Controller has been installed.

4.3 查看 Release 更新后的新值

$ helm get values mynginx-ingress

Release 版本历史

$ helm history mynginx-ingress
# mynginx-ingress 这个 release 各个历史版本。其中 REVISION 3 是最新的版本。
REVISION        UPDATED                         STATUS          CHART                   APP VERSION     DESCRIPTION
1               Sat Jun 12 16:17:57 2021        superseded      nginx-ingress-0.9.3     1.11.3          Install complete
2               Sat Jun 12 16:20:05 2021        superseded      nginx-ingress-0.9.3     1.11.3          Upgrade complete
3               Sat Jun 12 16:23:50 2021        deployed        nginx-ingress-0.9.3     1.11.3          Upgrade complete

Release 回滚

# 回滚到指定版本, 1 是上面的 revision
$ helm rollback mynginx-ingress 1
Rollback was a success! Happy Helming!

#回滚后状态
$ helm history mynginx-ingress
REVISION        UPDATED                         STATUS          CHART                   APP VERSION     DESCRIPTION
1               Sat Jun 12 16:17:57 2021        superseded      nginx-ingress-0.9.3     1.11.3          Install complete
2               Sat Jun 12 16:20:05 2021        superseded      nginx-ingress-0.9.3     1.11.3          Upgrade complete
3               Sat Jun 12 16:23:50 2021        superseded      nginx-ingress-0.9.3     1.11.3          Upgrade complete
4               Sat Jun 12 16:29:59 2021        deployed        nginx-ingress-0.9.3     1.11.3          Rollback to 1

Release 卸载

$ helm uninstall mynginx-ingress
release "mynginx-ingress" uninstalled

Helm Chart创建

Helm应用的创建/发布/部署/升级/回退

# 创建chart目录结构, 仅保留deployment, service, 删除其他对象
helm create nginx

# 打成chart包
helm package nginx
Successfully packaged chart and saved it to: /root/nginx-0.1.0.tgz

# 基于chart包安装
helm install nginx-0.1.0.tgz --generate-name
# 查看部署好的 release
helm list

# 调整chart版本并重新打包, 如将 Chart.yaml 中 version 调整为0.1.1
$ helm package nginx
Successfully packaged chart and saved it to: /root/nginx-0.1.1.tgz

# 升级 release
helm upgrade nginx-0-1582344693 nginx-0.1.1.tgz 

# 查看 releae 历史记录
helm history nginx-0-1582344693

# 回滚到指定版本, 1 是上面的 revision
$ helm rollback nginx-0-1582344693 1
Rollback was a success! Happy Helming!

$ helm uninstall nginx-0-1582344693
release "nginx-0-1582344693" uninstalled

Values.yaml 和模板

apiVersion: (必需)Chart API 版本。 
name: (必需)Chart 名称。
version: (必需)版本,遵循 SemVer 2 标准。 
kubeVersion: (可选)兼容的 Kubernetes 版本,遵循 SemVer 2 标准。
description: (可选)对应用的一句话说明。
type: (可选)Chart 的类型。
keywords:
- (可选)关于应用的关键字列表。
home: (可选)应用的 URL。
sources:
- (可选)应用源代码的 URL 列表。
dependencies: (可选)Chart 必要条件的列表。
- name: Chart 的名称,例如 nginx。
version: Chart 的版本,例如 "1.2.3"。
repository: 仓库 URL ("https://example.com/charts") 或别名 ("@repo-name")。
condition: (可选)解析为布尔值的 YAML 路径,用于启用/禁用 Chart (例如 subchart1.enabled)。
tags: (可选)
- 用于将 Chart 分组,一同启用/禁用。
import-values: (可选)
- ImportValues 保存源值到待导入父键的映射。每一项可以是字符串或者一对子/父子列表项。
alias: (可选)Chart 要使用的别名。当您要多次添加同一个 Chart 时,它会很有用。
maintainers: (可选)
- name: (必需)维护者姓名。
email: (可选)维护者电子邮件。
url: (可选)维护者 URL。
icon: (可选)要用作图标的 SVG 或 PNG 图片的 URL。
appVersion: (可选)应用版本。不需要是 SemVer。
deprecated: (可选,布尔值)该 Chart 是否已被弃用。
annotations:
example: (可选)按名称输入的注解列表。

Helm Chart 模板采用 Go 模板语言编写并存储在 Chart 的 templates 文件夹。有两种方式可以为模板提供值:

  1. 在 Chart 中创建一个包含可供引用的默认值的 values.yaml 文件。
  2. 创建一个包含必要值的 YAML 文件,通过在命令行使用 helm install 命令来使用该文件。

下面是 templates 文件夹中模板的示例。

apiVersion: v1
kind: ReplicationController
metadata:
  name: deis-database
  namespace: deis
  labels:
    app.kubernetes.io/managed-by: deis
spec:
  replicas: 1
  selector:
    app.kubernetes.io/name: deis-database
  template:
    metadata:
      labels:
        app.kubernetes.io/name: deis-database
    spec:
      serviceAccount: deis-database
      containers:
        - name: deis-database
          image: {{.Values.imageRegistry}}/postgres:{{.Values.dockerTag}}
          imagePullPolicy: {{.Values.pullPolicy}}
          ports:
            - containerPort: 5432
          env:
            - name: DATABASE_STORAGE
              value: {{default "minio" .Values.storage}}

上述示例在 Kubernetes 中定义 ReplicationController 模板,其中引用的一些值已在 values.yaml 文件中进行定义。

  • imageRegistry:Docker 镜像仓库。
  • dockerTag:Docker 镜像标签 (tag)。
  • pullPolicy:镜像拉取策略。
  • storage:存储后端,默认为 minio。

下面是 values.yaml 文件的示例:

imageRegistry: "quay.io/deis"
dockerTag: "latest"
pullPolicy: "Always"
storage: "s3"

Helm最佳实践