39、Kubernetes 定制与 Helm 包管理全解析

Kubernetes 定制与 Helm 包管理全解析

1. 定制 Kubernetes 调度器

在 Kubernetes 中,自定义调度器有着重要的作用。自定义调度器的名称(例如这里的 custom-scheduler )非常关键,必须保证唯一,后续会用它来将 Pod 与调度器关联,从而实现调度。并且,自定义调度器属于 kube-system 命名空间。

  • 运行另一个自定义调度器 :在集群中运行另一个自定义调度器很简单,就像创建一个部署一样。使用如下命令创建自定义调度器:
$ kubectl create -f custom-scheduler.yaml

使用以下命令验证调度器 Pod 是否正在运行:

$ kubectl get pods --namespace=kube-system

示例输出如下:

NAME                              READY    STATUS  RESTARTS   AGE
....
custom-scheduler-7cfc49d749-lwzxj  1/1     Running     0        2m
...

这表明自定义调度器已成功运行。

  • 将 Pod 分配给自定义调度器 :当自定义调度器与默认调度器同时运行时,Kubernetes 如何选择使用哪个调度器来调度 Pod 呢?实际上是由 Pod 自身决定的。Pod 规范中有一个可选的 schedulerName 字段,如果该字段缺失,将使用默认调度器;否则,将使用指定的调度器。这就是自定义调度器名称必须唯一的原因,默认调度器的名称是 default-scheduler

以下是一个使用默认调度器调度的 Pod 定义:

apiVersion: v1
kind: Pod
metadata:
  name: some-pod
  labels:
    name: some-pod
spec:
  containers:
  - name: some-container
    image: gcr.io/google_containers/pause:2.0

若要使用自定义调度器调度该 Pod,需将 Pod 规范修改为:

apiVersion: v1
kind: Pod
metadata:
  name: some-pod
  labels:
    name: some-pod
spec:
  schedulerName: custom-scheduler
  containers:
  - name: some-container
    image: gcr.io/google_containers/pause:2.0
  • 验证 Pod 是否由自定义调度器调度 :有两种主要方法可以验证 Pod 是否由正确的调度器调度。
    • 方法一:在部署自定义调度器之前创建需要由该调度器调度的 Pod,这些 Pod 将处于待处理状态。部署自定义调度器后,待处理的 Pod 将被调度并开始运行。
    • 方法二:检查事件日志,使用以下命令查找调度事件:
$ kubectl get events
2. 使用访问控制 Webhook

Kubernetes 提供了多种自定义访问控制的方式,访问控制可以表示为 AAA,即认证(Authentication)、授权(Authorization)和准入控制(Admission control)。早期是通过需要 Go 编程、安装到集群、注册等侵入性过程的插件来实现,现在可以自定义认证、授权和准入控制 Webhook。

  • 使用认证 Webhook :Kubernetes 允许通过注入用于承载令牌的 Webhook 来扩展认证过程。这需要两部分信息:如何访问远程认证服务以及认证决策的持续时间(默认为两分钟)。
    要提供这些信息并启用认证 Webhook,使用以下命令行参数启动 API 服务器:
--runtime-config=authentication.k8s.io/v1beta1=true
--authentication-token-webhook-config-file
--authentication-token-webhook-cache-ttl

配置文件使用 kubeconfig 文件格式,示例如下:

clusters:
  - name: remote-authentication-service
    cluster:
      certificate-authority: /path/to/ca.pem
      server: https://example.com/authenticate
users:
  - name: k8s-api-server
    user:
      client-certificate: /path/to/cert.pem
      client-key: /path/to/key.pem
current-context: webhook
contexts:
- context:
    cluster: remote-authentication-service
    user: k8s-api-sever
  name: webhook

当收到 API HTTP 请求时,Kubernetes 会从请求头中提取承载令牌,并通过 Webhook 向远程认证服务发送 TokenReview JSON 请求:

{
  "apiVersion": "authentication.k8s.io/v1beta1",
  "kind": "TokenReview",
  "spec": {
    "token": "<bearer token from original request headers>"
  }
}

远程认证服务将返回决策结果,认证状态为 true false 。以下是一个成功认证的示例:

{
  "apiVersion": "authentication.k8s.io/v1beta1",
  "kind": "TokenReview",
  "status": {
    "authenticated": true,
    "user": {
      "username": "gigi@gg.com",
      "uid": "42",
      "groups": [
        "developers"
      ],
      "extra": {
        "extrafield1": [
          "extravalue1",
          "extravalue2"
        ]
      }
    }
  }
}

拒绝响应则更为简洁:

{
  "apiVersion": "authentication.k8s.io/v1beta1",
  "kind": "TokenReview",
  "status": {
    "authenticated": false
  }
}
  • 使用授权 Webhook :授权 Webhook 与认证 Webhook 非常相似,它只需要一个与认证 Webhook 配置文件格式相同的配置文件。由于与认证不同,同一用户可能会向不同的 API 端点发送带有不同参数的大量请求,授权决策可能不同,因此不适合进行授权缓存。
    通过向 API 服务器传递以下命令行参数来配置 Webhook:
--runtime-config=authorization.k8s.io/v1beta1=true
--authorization-webhook-config-file=<configuration filename>

当请求通过认证后,Kubernetes 会向远程授权服务发送一个 SubjectAccessReview JSON 对象,其中包含请求用户、请求的资源和其他请求属性:

{
  "apiVersion": "authorization.k8s.io/v1beta1",
  "kind": "SubjectAccessReview",
  "spec": {
    "resourceAttributes": {
      "namespace": "awesome-namespace",
      "verb": "get",
      "group": "awesome.example.org",
      "resource": "pods"
    },
    "user": "gigi@gg.com",
    "group": [
      "group1",
      "group2"
    ]
  }
}

请求可能被允许:

{
  "apiVersion": "authorization.k8s.io/v1beta1",
  "kind": "SubjectAccessReview",
  "status": {
    "allowed": true
  }
}

也可能被拒绝(并给出原因):

{
  "apiVersion": "authorization.k8s.io/v1beta1",
  "kind": "SubjectAccessReview",
  "status": {
    "allowed": false,
    "reason": "user does not have read access to the namespace"
  }
}

用户可能被授权访问某个资源,但不一定能访问非资源属性,如 /api /apis 等。以下是请求访问日志的示例:

{
  "apiVersion": "authorization.k8s.io/v1beta1",
  "kind": "SubjectAccessReview",
  "spec": {
    "nonResourceAttributes": {
      "path": "/logs",
      "verb": "get"
    },
    "user": "gigi@gg.com",
    "group": [
      "group1",
      "group2"
    ]
  }
}
  • 使用准入控制 Webhook :动态准入控制也支持 Webhook,目前仍处于 Alpha 阶段。需要向 API 服务器传递以下命令行参数来启用通用准入 Webhook:
--admission-control=GenericAdmissionWebhook
--runtime-config=admissionregistration.k8s.io/v1alpha1

准入控制 Webhook 可以通过创建 externaladmissionhookconfiguration 对象进行动态配置:

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ExternalAdmissionHookConfiguration
metadata:
  name: example-config
externalAdmissionHooks:
- name: pod-image.k8s.io
  rules:
  - apiGroups:
    - ""
    apiVersions:
    - v1
    operations:
    - CREATE
    resources:
    - pods
  failurePolicy: Ignore
  clientConfig:
    caBundle: <pem encoded ca cert that signs the server cert used by the webhook>
    service:
      name: <name of the front-end service>
      namespace: <namespace of the front-end service>
3. 为水平 Pod 自动扩缩提供自定义指标

在 Kubernetes 1.6 之前,自定义指标是通过 Heapster 模型实现的。从 Kubernetes 1.6 开始,新的自定义指标 API 出现并逐渐成熟,到 Kubernetes 1.9 版本,这些指标默认启用。自定义指标依赖于 API 聚合,推荐从以下链接提供的自定义指标 API 服务器样板代码开始:

https://github.com/kubernetes-incubator/custom-metrics-apiserver

然后,实现 CustomMetricsProvider 接口:

type CustomMetricsProvider interface {
    GetRootScopedMetricByName(groupResource schema.GroupResource,
                              name string,
                              metricName string)
(*custom_metrics.MetricValue, error)
    GetRootScopedMetricBySelector(groupResource schema.GroupResource,
                                  selector labels.Selector,
                                  metricName string)
(*custom_metrics.MetricValueList, error)
    GetNamespacedMetricByName(groupResource schema.GroupResource,
                              namespace string,
                              name string,
                              metricName string)
(*custom_metrics.MetricValue, error)
    GetNamespacedMetricBySelector(groupResource schema.GroupResource,
                                  namespace string,
                                  selector labels.Selector,
                                  metricName string)
(*MetricValueList, error)
    ListAllMetrics() []MetricInfo
}
4. 使用自定义存储扩展 Kubernetes

卷插件是另一种类型的插件。在 Kubernetes 1.8 之前,需要编写一个 Kublet 插件,这涉及实现、向 Kubernetes 注册以及与 Kublet 链接等操作。Kubernetes 1.8 引入了更通用的 FlexVolume,Kubernetes 1.9 则通过容器存储接口(CSI)将其提升到了新的水平。

  • 利用 FlexVolume :Kubernetes 卷插件旨在支持特定类型的存储或存储提供商。对于大多数用户来说,现有的卷插件已经足够,但如果需要集成不支持的存储解决方案,则必须实现自己的卷插件,这并非易事。而 FlexVolume 提供了另一种途径,它是一个通用插件,允许在不与 Kubernetes 进行深度集成的情况下连接不支持的存储后端。
    FlexVolume 允许向规范中添加任意属性,并通过包含以下操作的调用接口与后端进行通信:

    • Attach :将卷附加到 Kubernetes Kubelet 节点。
    • Detach :从 Kubernetes Kubelet 节点分离卷。
    • Mount :挂载已附加的卷。
    • Unmount :卸载已挂载的卷。
      每个操作由后端驱动程序作为二进制文件实现,FlexVolume 会在适当的时候调用这些二进制文件。驱动程序必须安装在 /usr/libexec/kubernetes/kubelet-plugins/volume/exec/<vendor>~<driver>/<driver> 路径下。
  • 受益于 CSI :FlexVolume 提供了树外插件功能,但仍然需要 FlexVolume 插件本身以及相对繁琐的安装和调用模型。CSI 通过让供应商直接实现,显著改进了这一点。对于开发者来说,无需创建和维护这些插件,存储解决方案提供商有责任实现和维护 CSI,并确保其尽可能健壮,以避免用户选择其他能在 Kubernetes(以及其他集成了 CSI 的平台)上开箱即用的存储解决方案。

5. 理解 Helm

Kubernetes 在运行时提供了多种组织和编排容器的方式,但缺乏将一组镜像进行更高级别分组的功能,Helm 则弥补了这一不足。

  • Helm 的动机 :Helm 支持以下几个重要的用例:

    • 管理复杂性:图表可以描述最复杂的应用程序,提供可重复的应用程序安装,并作为单一的权威点。
    • 轻松升级:原地升级和自定义钩子允许轻松更新。
    • 简单共享:可以轻松共享可版本化的图表,并将其托管在公共或私有服务器上。
    • 安全回滚:当需要回滚最近的升级时,Helm 提供了一个单一的命令来回滚对基础设施的一系列连贯更改。
  • Helm 的架构 :Helm 旨在执行以下操作:

    • 从头创建新图表。
    • 将图表打包成图表存档(tgz)文件。
    • 与存储图表的图表仓库进行交互。
    • 在现有的 Kubernetes 集群中安装和卸载图表。
    • 管理使用 Helm 安装的图表的发布周期。
      Helm 使用客户端 - 服务器架构来实现这些目标。
  • Helm 的组件 :Helm 有一个运行在 Kubernetes 集群上的服务器组件和一个运行在本地机器上的客户端组件。

    • Tiller 服务器 :负责管理发布,与 Helm 客户端以及 Kubernetes API 服务器进行交互。其主要功能包括:
      • 监听来自 Helm 客户端的传入请求。
      • 结合图表和配置来构建发布。
      • 将图表安装到 Kubernetes 中。
      • 跟踪后续的发布。
      • 通过与 Kubernetes 交互来升级和卸载图表。
    • Helm 客户端 :安装在本地机器上,负责以下操作:
      • 本地图表开发。
      • 管理仓库。
      • 与 Tiller 服务器进行交互。
      • 发送要安装的图表。
      • 请求有关发布的信息。
      • 请求升级或卸载现有发布。

以下是 Helm 组件及其功能的表格总结:
| 组件 | 位置 | 功能 |
| ---- | ---- | ---- |
| Tiller 服务器 | Kubernetes 集群 | 管理发布,与客户端和 API 服务器交互 |
| Helm 客户端 | 本地机器 | 本地开发、管理仓库、与服务器交互等 |

mermaid 流程图展示 Helm 客户端与服务器的交互:

graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;

    A(Helm 客户端):::process -->|请求| B(Tiller 服务器):::process
    B -->|响应| A
    B -->|安装/升级/卸载| C(Kubernetes 集群):::process
    C -->|状态反馈| B
6. 使用 Helm

Helm 是一个功能丰富的包管理系统,可用于管理集群上安装的应用程序。以下是使用 Helm 的具体步骤:

  • 安装 Helm :安装 Helm 涉及安装客户端和服务器,Helm 用 Go 语言实现,同一个二进制可执行文件既可以作为客户端,也可以作为服务器。
    • 安装 Helm 客户端 :必须正确配置 Kubectl 以与 Kubernetes 集群通信,因为 Helm 客户端使用 Kubectl 配置与 Helm 服务器(Tiller)进行通信。
      • 对于所有平台,可以从以下链接获取二进制发行版: https://github.com/kubernetes/helm/releases/latest
      • 对于 Windows,也可以使用 chocolatey 包管理器,但版本可能稍落后于官方版本: https://chocolatey.org/packages/kubernetes-helm/<version>
      • 对于 macOS 和 Linux,可以通过脚本安装客户端:
$ curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get > get_helm.sh
$ chmod 700 get_helm.sh
$ ./get_helm.sh
    - 在 macOS X 上,也可以使用 Homebrew 安装:
brew install kubernetes-helm
- **安装 Tiller 服务器**:Tiller 通常在集群内运行,但在开发时,有时在本地运行会更方便。
    - **在集群内安装 Tiller**:从安装了 Helm 客户端的机器上运行以下命令来初始化 Tiller 服务器:
helm init

安装完成后,使用以下命令检查集群的 kube-system 命名空间中是否有正在运行的 Tiller Pod:

> kubectl get po --namespace=kube-system -l name=tiller

示例输出如下:

NAME                            READY  STATUS   RESTARTS   AGE
tiller-deploy-3210613906-2j5sh  1/1    Running  0          1m

还可以使用 helm version 命令检查客户端和服务器的版本:

> helm version

示例输出如下:

Client: &version.Version{SemVer:"v2.2.3",
GitCommit:"1402a4d6ec9fb349e17b912e32fe259ca21181e3", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.2.3",
GitCommit:"1402a4d6ec9fb349e17b912e32fe259ca21181e3", GitTreeState:"clean"}
    - **在本地安装 Tiller**:如果要在本地运行 Tiller,需要先进行构建,此操作在 Linux 和 macOS 上支持:
> cd $GOPATH
> mkdir -p src/k8s.io
> cd src/k8s.io
> git clone https://github.com/kubernetes/helm.git
> cd helm
> make bootstrap build

bootstrap 目标会尝试安装依赖项、重建 vendor/ 树并验证配置, build 目标会编译 Helm 并将其放置在 bin/helm 路径下,Tiller 也会被编译并放置在 bin/tiller 路径下。
运行 bin/tiller 启动 Tiller,它将通过 Kubectl 配置连接到 Kubernetes 集群。需要告诉 Helm 客户端连接到本地 Tiller 服务器,可以通过设置环境变量:

> export HELM_HOST=localhost:44134

或者作为命令行参数传递: --host localhost:44134

  • 使用替代存储后端 :Helm 2.7.0 增加了将发布信息存储为机密的选项,早期版本总是将发布信息存储在 ConfigMaps 中。机密后端提高了图表的安全性,是 Kubernetes 静态加密的补充。要使用机密后端,需要使用以下命令行运行 Helm:
> helm init --override 'spec.template.spec.containers[0].command'='{/tiller,--storage=secret}'

通过以上步骤,你可以深入了解 Kubernetes 的定制和 Helm 包管理的相关知识,并在实际应用中灵活运用。

Kubernetes 定制与 Helm 包管理全解析

7. 创建自己的 Helm 图表

创建自己的 Helm 图表可以帮助我们更好地管理和部署复杂的应用程序。以下是创建 Helm 图表的详细步骤:

7.1 初始化图表

首先,使用 helm create 命令来初始化一个新的图表。例如,创建一个名为 mychart 的图表:

helm create mychart

这个命令会生成一个包含基本结构的图表目录,目录结构如下:

mychart/
├── charts/
├── templates/
│   ├── deployment.yaml
│   ├── service.yaml
│   └── _helpers.tpl
├── Chart.yaml
└── values.yaml
  • charts/ :用于存放子图表。
  • templates/ :包含 Kubernetes 资源的模板文件。
  • Chart.yaml :定义图表的元数据,如名称、版本等。
  • values.yaml :包含模板文件中使用的默认值。
7.2 编辑 Chart.yaml

打开 Chart.yaml 文件,修改图表的元数据。例如:

apiVersion: v2
name: mychart
description: A Helm chart for my application
type: application
version: 0.1.0
appVersion: "1.16.0"

这里可以根据实际情况修改 name description version 等信息。

7.3 编辑 values.yaml

values.yaml 文件包含了模板文件中使用的默认值。例如,修改应用程序的镜像信息:

image:
  repository: myapp
  tag: 1.0.0
  pullPolicy: IfNotPresent
7.4 编辑模板文件

templates/ 目录下,可以编辑各种 Kubernetes 资源的模板文件。例如,编辑 deployment.yaml 文件:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "mychart.fullname" . }}
  labels:
    {{- include "mychart.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "mychart.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "mychart.selectorLabels" . | nindent 8 }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: 80
              protocol: TCP

这里使用了 Helm 的模板语法,如 {{ }} 来引用 values.yaml 中的值。

7.5 测试模板

在部署之前,可以使用 helm template 命令来测试模板是否正确渲染:

helm template mychart

这个命令会输出渲染后的 Kubernetes 资源清单。

7.6 打包和发布图表

当图表开发完成后,可以使用 helm package 命令将图表打包成一个 .tgz 文件:

helm package mychart

然后可以将打包好的图表发布到图表仓库,供其他用户使用。

8. 管理 Helm 图表的版本、依赖和模板

在使用 Helm 图表时,管理版本、依赖和模板是非常重要的。

8.1 版本管理

Helm 图表使用语义化版本号(SemVer)来管理版本。在 Chart.yaml 文件中,可以指定图表的版本号。例如:

version: 0.1.0

当对图表进行更新时,需要相应地更新版本号。可以使用 helm upgrade 命令来升级已安装的图表到新版本。

8.2 依赖管理

Helm 图表可以依赖其他图表。在 Chart.yaml 文件中,可以使用 dependencies 字段来指定依赖的图表:

dependencies:
  - name: mysql
    version: "8.8.0"
    repository: "https://charts.bitnami.com/bitnami"

使用 helm dependency update 命令来下载和更新依赖的图表:

helm dependency update mychart
8.3 模板管理

Helm 模板使用 Go 模板语言,可以通过定义变量、函数和条件语句来实现复杂的逻辑。例如,在 _helpers.tpl 文件中定义一个函数:

{{- define "mychart.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}

然后在其他模板文件中可以使用这个函数:

metadata:
  name: {{ include "mychart.fullname" . }}
9. 总结

通过前面的介绍,我们了解了 Kubernetes 的多种定制方式以及 Helm 包管理的相关知识。下面是对这些内容的总结:

定制类型 主要内容
调度器定制 创建自定义调度器,将 Pod 分配给自定义调度器,并验证调度结果
访问控制 Webhook 使用认证、授权和准入控制 Webhook 来扩展 Kubernetes 的访问控制
自定义指标 为水平 Pod 自动扩缩提供自定义指标,依赖 API 聚合
自定义存储 使用 FlexVolume 和 CSI 来扩展 Kubernetes 的存储功能
Helm 包管理 理解 Helm 的动机、架构和组件,学会使用 Helm 进行安装、升级、卸载等操作,创建和管理自己的 Helm 图表

mermaid 流程图展示整个 Kubernetes 定制和 Helm 包管理的流程:

graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;

    A(Kubernetes 定制):::process --> B(调度器定制):::process
    A --> C(访问控制 Webhook):::process
    A --> D(自定义指标):::process
    A --> E(自定义存储):::process
    F(Helm 包管理):::process --> G(理解 Helm):::process
    F --> H(使用 Helm):::process
    F --> I(创建自己的图表):::process
    F --> J(管理版本、依赖和模板):::process

通过掌握这些机制,我们可以根据实际需求灵活地扩展、定制和控制 Kubernetes,利用 Helm 更好地管理和部署复杂的应用程序,从而提高开发和运维的效率。在未来的实践中,我们可以进一步探索这些技术的更多应用场景,为企业的数字化转型提供有力支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值