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 服务器进行交互。
- 发送要安装的图表。
- 请求有关发布的信息。
- 请求升级或卸载现有发布。
-
Tiller 服务器
:负责管理发布,与 Helm 客户端以及 Kubernetes API 服务器进行交互。其主要功能包括:
以下是 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,可以通过脚本安装客户端:
-
对于所有平台,可以从以下链接获取二进制发行版:
-
安装 Helm 客户端
:必须正确配置 Kubectl 以与 Kubernetes 集群通信,因为 Helm 客户端使用 Kubectl 配置与 Helm 服务器(Tiller)进行通信。
$ 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 更好地管理和部署复杂的应用程序,从而提高开发和运维的效率。在未来的实践中,我们可以进一步探索这些技术的更多应用场景,为企业的数字化转型提供有力支持。
超级会员免费看
1102

被折叠的 条评论
为什么被折叠?



