简介
在上一篇文章中,咱们介绍了如何应用 KCL 编写并治理 Kubernetes 配置并将配置下发到集群,这一节咱们通过与其余 Kubernetes 配置管理工具的对比方 Helm 介绍 KCL 在 Kubernetes 配置管理场景更丰盛的内容。
Helm 是一个为 Kubernetes 对象生成可部署清单的工具,它承当了以两种不同模式生成最终清单的工作。Helm 是一个治理 Kubernetes 包(称为 charts)的必备模板工具。图表是 YAML 清单的模板化版本,其中混合了 Go template 的子集,它也是 Kubernetes 的包管理器,能够打包、配置和部署 / 利用 Helm 图表到 Kubernetes 集群。
在 KCL 中,用户能够应用更多的工具和 IDE 插件反对间接编写配置代码文件,而不是模板文件,这些工具和插件反对须要在相应地位的代码中进行批改,从而打消了读取 YAML 的老本。同时,用户能够通过代码重用配置片段,防止了 YAML 配置的大量复制和粘贴。信息密度更高,更不容易出错。
上面以一个经典的 Helm Chart 配置管理的例子具体阐明 Kustomize 和 KCL 在 Kubernetes 资源配置管理上的区别。
Helm
Helm 具备 values.yaml
和 template
的概念, 通常一个 Helm Chart 由一个蕴含 Chart.yaml
的门路组成。咱们能够执行如下命令取得一个典型的 Helm Chart 工程
- 创立
workload-helm
目录来保留 chart 工程
# Create a directory to hold the chart project
mkdir workload-helm
# Create a workload-helm/Chart.yaml
cat <<EOF > workload-helm/Chart.yaml
apiVersion: v2
appVersion: 0.3.0
description: A helm chart to provision standard workloads.
name: workload
type: application
version: 0.3.0
EOF
# Create a workload-helm/values.yaml
cat <<EOF > workload-helm/values.yaml
service:
type: ClusterIP
ports:
- name: www
protocol: TCP
port: 80
targetPort: 80
containers:
my-container:
image:
name: busybox:latest
command: ["/bin/echo"]
args:
- "-c"
- "Hello World!"
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
EOF
- 创立模版文件夹
# Create a directory to hold templates
mkdir workload-helm/templates
# Create a workload-helm/templates/helpers.tpl
cat <<EOF > workload-helm/templates/helpers.tpl
{{/*
Expand the name of the chart.
*/}}
{{- define "workload.name" -}}
{{- default .Release.Name .Values.nameOverride | trunc 63 | trimSuffix "-"}}
{{- end}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "workload.fullname" -}}
{{- \$name := default .Chart.Name .Values.nameOverride}}
{{- if contains \$name .Release.Name}}
{{- .Release.Name | trunc 63 | trimSuffix "-"}}
{{- else}}
{{- printf "%s-%s" .Release.Name \$name | trunc 63 | trimSuffix "-"}}
{{- end}}
{{- end}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "workload.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-"}}
{{- end}}
{{/*
Common labels
*/}}
{{- define "workload.labels" -}}
helm.sh/chart: {{include "workload.chart" .}}
{{include "workload.selectorLabels" .}}
{{- if .Chart.AppVersion}}
app.kubernetes.io/version: {{.Chart.AppVersion | quote}}
{{- end}}
app.kubernetes.io/managed-by: {{.Release.Service}}
{{- end}}
{{/*
Selector labels
*/}}
{{- define "workload.selectorLabels" -}}
app.kubernetes.io/name: {{include "workload.name" .}}
app.kubernetes.io/instance: {{.Release.Name}}
{{- end}}
EOF
cat <<EOF > workload-helm/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{include "workload.name" .}}
labels:
{{- include "workload.labels" . | nindent 4}}
spec:
selector:
matchLabels:
{{- include "workload.selectorLabels" . | nindent 6}}
template:
metadata:
labels:
{{- include "workload.selectorLabels" . | nindent 8}}
spec:
containers:
{{- range \$name, \$container := .Values.containers}}
- name: {{\$name}}
image: "{{$container.image.name}}"
{{- with \$container.command}}
command:
{{- toYaml \$container.command | nindent 12}}
{{- end}}
{{- with \$container.args}}
args:
{{- toYaml \$container.args | nindent 12}}
{{- end}}
{{- with \$container.env}}
env:
{{- toYaml \$container.env | nindent 12}}
{{- end}}
{{- with \$container.volumeMounts}}
volumeMounts:
{{- toYaml \$container.volumeMounts | nindent 12}}
{{- end}}
{{- with \$container.livenessProbe}}
livenessProbe:
{{- toYaml \$container.livenessProbe | nindent 12}}
{{- end}}
{{- with \$container.readinessProbe}}
readinessProbe:
{{- toYaml \$container.readinessProbe | nindent 12}}
{{- end}}
{{- with \$container.resources}}
resources:
{{- toYaml \$container.resources | nindent 12}}
{{- end}}
{{- end}}
EOF
cat <<EOF > workload-helm/templates/service.yaml
{{if .Values.service}}
apiVersion: v1
kind: Service
metadata:
name: {{include "workload.name" .}}
labels:
{{- include "workload.labels" . | nindent 4}}
spec:
type: {{.Values.service.type}}
selector:
{{- include "workload.selectorLabels" . | nindent 4}}
{{- with .Values.service.ports}}
ports:
{{- toYaml . | nindent 4}}
{{- end}}
{{- end}}
EOF
能够失去如下的 Helm chart 工程
.
├── Chart.yaml
├── templates
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ └── service.yaml
└── values.yaml
咱们能够通过如下的命令渲染实在的部署配置
helm template workload-helm
能够失去如下 YAML 输入
---
# Source: workload-helm/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: release-name
labels:
helm.sh/chart: workload-0.3.0
app.kubernetes.io/name: release-name
app.kubernetes.io/instance: release-name
app.kubernetes.io/version: "0.3.0"
app.kubernetes.io/managed-by: Helm
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: release-name
app.kubernetes.io/instance: release-name
ports:
- name: www
port: 80
protocol: TCP
targetPort: 80
---
# Source: workload-helm/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: release-name
labels:
helm.sh/chart: workload-0.3.0
app.kubernetes.io/name: release-name
app.kubernetes.io/instance: release-name
app.kubernetes.io/version: "0.3.0"
app.kubernetes.io/managed-by: Helm
spec:
selector:
matchLabels:
app.kubernetes.io/name: release-name
app.kubernetes.io/instance: release-name
template:
metadata:
labels:
app.kubernetes.io/name: release-name
app.kubernetes.io/instance: release-name
spec:
containers:
- name: my-container
image: "busybox:latest"
command:
- /bin/echo
args:
- -c
- Hello World!
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
KCL
在 KCL 中,咱们提供了与 Helm values.yaml
类似的动静配置参数 kcl.yaml
文件,咱们能够执行如下的命令取得一个典型的 KCL 工程。
- 创立
workload-kcl
目录来保留 KCL 工程
# Create a directory to hold the KCL project
mkdir workload-kcl
# Create a workload-kcl/kcl.yaml
cat <<EOF > workload-kcl/kcl.yaml
kcl_options:
- key: containers
value:
my-container:
image:
name: busybox:latest
command: ["/bin/echo"]
args:
- "-c"
- "Hello World!"
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
- key: service
value:
type: ClusterIP
ports:
- name: www
protocol: TCP
port: 80
targetPort: 80
EOF
- 创立如下 KCL 文件来保留 kubernetes 资源
# Create a workload-kcl/deployment.k
cat <<EOF > workload-kcl/deployment.k
apiVersion = "apps/v1"
kind = "Deployment"
metadata = {
name = "release-name"
labels = {
"app.kubernetes.io/name" = "release-name"
"app.kubernetes.io/instance" = "release-name"
}
}
spec = {
selector.matchLabels = metadata.labels
template.metadata.labels = metadata.labels
template.spec.containers = [
{
name = name
image = container.image.name
command = container.command
command = container.args
env = container.env
resources = container.resources
} for name, container in option("containers") or {}]
}
EOF
cat <<EOF > workload-kcl/service.k
apiVersion = "v1"
kind = "Service"
metadata = {
name = "release-name"
labels = {
"app.kubernetes.io/name" = "release-name"
"app.kubernetes.io/instance" = "release-name"
}
}
spec = {
selector.matchLabels = metadata.labels
type = option("service", default={})?.type
ports = option("service", default={})?.ports
}
EOF
上述 KCL 代码中咱们别离申明了一个 Kubernetes Deployment
和 Service
资源的 apiVersion
、kind
、metadata
和 spec
等变量,并别离赋值了相应的内容,特地地,咱们将 metadata.labels
字段别离重用在 spec.selector.matchLabels
和 spec.template.metadata.labels
字段。能够看出,相比于 Helm 模版 或者 YAML,KCL 定义的数据结构更加紧凑,而且能够通过定义局部变量实现配置重用。
在 KCL 中,咱们能够通过条件语句和 option
内置函数接管动静参数,并设置不同的配置值以生成资源。
能够通过如下的命令失去 Deployment
和 Service
YAML 输入:
Deployment
$ kcl workload-kcl/deployment.k -Y workload-kcl/kcl.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: release-name
labels:
app.kubernetes.io/name: release-name
app.kubernetes.io/instance: release-name
spec:
selector:
matchLabels:
app.kubernetes.io/name: release-name
app.kubernetes.io/instance: release-name
template:
metadata:
labels:
app.kubernetes.io/name: release-name
app.kubernetes.io/instance: release-name
spec:
containers:
- name: my-container
image: busybox:latest
command:
- -c
- Hello World!
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
Service
$ kcl workload-kcl/service.k -Y workload-kcl/kcl.yaml
apiVersion: v1
kind: Service
metadata:
name: release-name
labels:
app.kubernetes.io/name: release-name
app.kubernetes.io/instance: release-name
spec:
selector:
matchLabels:
app.kubernetes.io/name: release-name
app.kubernetes.io/instance: release-name
type: ClusterIP
ports:
- name: www
protocol: TCP
port: 80
targetPort: 80
此外咱们能够通过 -D
标记设置额定的参数并笼罩 kcl.yaml
文件的配置值
$ kcl workload-kcl/service.k -Y workload-kcl/kcl.yaml -D service=None
apiVersion: v1
kind: Service
metadata:
name: release-name
labels:
app.kubernetes.io/name: release-name
app.kubernetes.io/instance: release-name
spec:
selector:
matchLabels:
app.kubernetes.io/name: release-name
app.kubernetes.io/instance: release-name
type: null
ports: null
小结
能够看出,与 Helm 相比,KCL 通过在配置重用和笼罩的根底上生成代码,缩小了配置文件和代码行的数量。与 Helm 一样,它是一个纯客户端解决方案,能够将配置和策略验证尽可能地左移,而不会对集群造成额定的依赖或累赘,或者甚至没有 Kubernetes 集群时也能够通过 KCL Schema 等个性对 YAML 进行充沛验证和测试。
Helm 能够在 .tpl
文件中定义可重用模板,并反对其余模板援用它。然而,只有模板定义能力重用。在一个简单的 Helm 图表我的项目中,咱们须要定义许多附加的根本模板。与 Helm 繁琐的写作方法相比,KCL 中的所有内容都是变量。指定模板不须要其余语法。任何变量都能够互相援用。
此外,Helm 中还有大量与理论逻辑无关的 {{- include}}
, nindent
和 toYaml
标记字符,咱们须要计算每个 Helm 援用处的空格和缩进。在 KCL 中,无用代码更少,并且不须要很多的 {{*}}
来标记代码块,信息密度更高。
事实上,KCL 和 Helm Chart 并不对抗。咱们甚至能够应用 KCL 编写 Helm 模板或者应用 KCL 来生成 values.yaml
,或者为现有的 Helm 图表提供可编程扩大性能,比方为 Helm 开发可选的 KCL Schema 插件来验证已有的 Helm 图表或者为 Helm Chart 编写额定的 Transformer 来 Patch 已有的 Helm Chart。
将来打算
咱们后续打算 KCL 的模型和束缚能够作为一个包来治理(这个包只有 KCL 文件)。例如,Kubernetes 的模型和束缚能够开箱即用。用户能够通过已有的模型生成配置或验证现有配置,并且能够通过 KCL 继承伎俩简略地扩大用户想要的模型和束缚。
在此阶段,您能够应用 Git 或 OCI Registry as Storage(ORAS) 等工具来治理 KCL 配置版本。
如果您喜爱这篇文章,肯定记得珍藏 + 关注!!更多精彩内容请拜访:
- KCL 仓库地址:https://github.com/KusionStack/KCLVM
- Kusion 仓库地址:https://github.com/KusionStack/kusion
- Konfig 仓库地址:https://github.com/KusionStack/konfig
如果您喜爱这些我的项目,欢送 Github Star 激励一下 🌟🌟🌟,同时欢送拜访上面的链接退出咱们的社区进行交换 👏👏👏
- https://github.com/KusionStack/community