- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
在开始前需要先对 kubernetes Operator 有个简单的认识.
以为我们在编写部署一些简单 Deployment 的时候只需要自己编写一个 yaml 文件然后 kubectl apply 即可.
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: k8s-combat
name: k8s-combat
spec:
replicas: 1
selector:
matchLabels:
app: k8s-combat
template:
metadata:
labels:
app: k8s-combat
spec:
containers:
- name: k8s-combat
image: crossoverjie/k8s-combat:v1
imagePullPolicy: Always
resources:
limits:
cpu: "1"
memory: 300Mi
requests:
cpu: "0.1"
memory: 30Mi
kubectl apply -f deployment.yaml
这对于一些并不复杂的项目来说完全够用了,但组件一多就比较麻烦了.
这里以 Apache Pulsar 为例:它的核心组件有
必须需要等 Zookeeper 和 Bookkeeper 启动之后才能将流量放进来.
此时如何还继续使用 yaml 文件一个个部署就会非常繁琐,好在社区有提供 Helm 一键安装程序,使用它我们只需要在一个同意的 yaml 里简单的配置一些组件,配置就可以由 helm 来部署整个复杂的 Pulsar 系统.
components:
# zookeeper
zookeeper: true
# bookkeeper
bookkeeper: true
# bookkeeper - autorecovery
autorecovery: true
# broker
broker: true
# functions
functions: false
# proxy
proxy: true
# toolset
toolset: true
# pulsar manager
pulsar_manager: false
monitoring:
# monitoring - prometheus
prometheus: true
# monitoring - grafana
grafana: true
# monitoring - node_exporter
node_exporter: true
# alerting - alert-manager
alert_manager: false
比如在 helm 的 yaml 中我们可以选择使用哪些 components,以及是否启用监控组件.
最后直接使用这个文件进行安装:
helm install pulsar apache/pulsar \
--values charts/pulsar/values.yaml \
--set namespace=pulsar \
--set initialize=true
它就会自动生成各个组件的 yaml 文件,然后统一执行.
所以 helm 的本质上和 kubectl apply yaml 一样的,只是我们在定义 value.yaml 时帮我们处理了许多不需要用户低频修改的参数.
我们可以使用 helm 将要执行的 yaml 输出后人工审核 。
helm install pulsar apache/pulsar --dry-run --debug > debug.yaml
Helm 虽然可以帮我们部署或者升级一个大型应用,但他却没法帮我们运维这个应用.
举个例子:比如我希望当 Pulsar Broker 的流量或者内存达到某个阈值后就指定扩容 Broker,闲时再自动回收.
或者某个 Bookkeeper 的磁盘使用率达到阈值后可以自动扩容磁盘,这些仅仅使用 Helm 时都是无法实现的.
以上这些需求我们目前也是通过监控系统发出报警,然后再由人工处理.
其中最大的痛点就是进行升级:
因为每次升级是有先后顺序的,需要依次观察每个组件运行是否正常才能往后操作.
如果有 Operator 理性情况下下我们只需要更新一下镜像版本,它就可以自动执行以上的所有步骤最后将集群升级完毕.
所以相对于 Helm 来说 Operator 是可以站在一个更高的视角俯视整个应用系统,它能发现系统哪个地方需要它从而直接修复.
而提到 Operator 那就不得不提到 CRD(Custom Resource Definitions)翻译过来就是自定义资源.
这是 kubernetes 提供的一个 API 扩展机制,类似于内置的 Deployment/StatefulSet/Services 资源,CRD 是一种自定义的资源.
这里以我们常用的 prometheus-operator 和 VictoriaMetrics-operator 为例:
Prometheus:
Prometheus
:用于定义 Prometheus 的 DeploymentAlertmanager
:用于定义 Alertmanager
ScrapeConfig
:用于定会抓取规则apiVersion: monitoring.coreos.com/v1alpha1
kind: ScrapeConfig
metadata:
name: static-config
namespace: my-namespace
labels:
prometheus: system-monitoring-prometheus
spec:
staticConfigs:
- labels:
job: prometheus
targets:
- prometheus.demo.do.prometheus.io:9090
使用时的一个很大区别就是资源的 kind: ScrapeConfig 为自定义的类型.
VictoriaMetrics 的 CRD:
# vmcluster.yaml
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMCluster
metadata:
name: demo
spec:
retentionPeriod: "1"
replicationFactor: 2
vmstorage:
replicaCount: 2
storageDataPath: "/vm-data"
storage:
volumeClaimTemplate:
spec:
resources:
requests:
storage: "10Gi"
resources:
limits:
cpu: "1"
memory: "1Gi"
vmselect:
replicaCount: 2
cacheMountPath: "/select-cache"
storage:
volumeClaimTemplate:
spec:
resources:
requests:
storage: "1Gi"
resources:
limits:
cpu: "1"
memory: "1Gi"
requests:
cpu: "0.5"
memory: "500Mi"
vminsert:
replicaCount: 2
以上是用于创建一个 VM 集群的 CRD 资源,应用之后就会自动创建一个集群.
Operator 通常是运行在 kubernetes API server 的 webhook 之上,简单来说就是在一些内置资源的关键节点 API-server 会调用我们注册的一个 webhook,在这个 webhook 中我们根据我们的 CRD 做一些自定义的操作.
理论上我们可以使用任何语言都可以写 Operator,只需要能处理 api-server 的回调即可.
只是 Go 语言有很多成熟的工具,比如常用的 kubebuilder 和 operator-sdk. 。
他们内置了许多命令行工具,可以帮我们节省需要工作量.
这里以 operator-sdk 为例:
$ operator-sdk create webhook --group cache --version v1alpha1 --kind Memcached --defaulting --programmatic-validation
会直接帮我们创建好一个标准的 operator 项目
├── Dockerfile
├── Makefile
├── PROJECT
├── api
│ └── v1alpha1
│ ├── memcached_webhook.go
│ ├── webhook_suite_test.go
├── config
│ ├── certmanager
│ │ ├── certificate.yaml
│ │ ├── kustomization.yaml
│ │ └── kustomizeconfig.yaml
│ ├── default
│ │ ├── manager_webhook_patch.yaml
│ │ └── webhookcainjection_patch.yaml
│ └── webhook
│ ├── kustomization.yaml
│ ├── kustomizeconfig.yaml
│ └── service.yaml
├── go.mod
├── go.sum
└── main.go
其中 Makefile 中包含了开发过程中常用的工具链(包括根据声明的结构体自动生成 CRD 资源、部署k8s 环境测试等等)、Dockerfile 等等.
这样我们就只需要专注于开发业务逻辑即可.
因为我前段时间给 https://github.com/open-telemetry/opentelemetry-operator 贡献过两个 feature,所以就以这个 Operator 为例:
它有一个 CRD: kind: Instrumentation,在这个 CRD 中可以将 OpenTelemetry 的 agent 注入到应用中.
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: instrumentation-test-order
namespace: test
spec:
env:
- name: OTEL_SERVICE_NAME
value: order
selector:
matchLabels:
app: order
java:
image: autoinstrumentation-java:2.4.0-release
extensions:
- image: autoinstrumentation-java:2.4.0-release
dir: /extensions
env:
- name: OTEL_RESOURCE_ATTRIBUTES
value: service.name=order
- name: OTEL_INSTRUMENTATION_MESSAGING_EXPERIMENTAL_RECEIVE_TELEMETRY_ENABLED
value: "true"
- name: OTEL_TRACES_EXPORTER
value: otlp
- name: OTEL_METRICS_EXPORTER
value: otlp
- name: OTEL_LOGS_EXPORTER
value: none
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: http://open-telemetry-opentelemetry-collector.otel.svc.cluster.local:4317
- name: OTEL_EXPORTER_OTLP_COMPRESSION
value: gzip
- name: OTEL_EXPERIMENTAL_EXPORTER_OTLP_RETRY_ENABLED
value: "true"
它的运行规则是当我们的 Pod 在启动过程中会判断 Pod 的注解中是否开启了注入 OpenTelemetry 的配置.
如果开启则会将我们在 CRD 中自定义的镜像里的 javaagent 复制到业务容器中,同时会将下面的那些环境变量也一起加入的业务容器中.
要达到这样的效果就需要我们注册一个回调 endpoint.
mgr.GetWebhookServer().Register("/mutate-v1-pod", &webhook.Admission{
Handler: podmutation.NewWebhookHandler(cfg, ctrl.Log.WithName("pod-webhook"), decoder, mgr.GetClient(),
[]podmutation.PodMutator{
sidecar.NewMutator(logger, cfg, mgr.GetClient()),
instrumentation.NewMutator(logger, mgr.GetClient(), mgr.GetEventRecorderFor("opentelemetry-operator"), cfg),
}),})
当 Pod 创建或有新的变更请求时就会回调我们的接口.
func (pm *instPodMutator) Mutate(ctx context.Context, ns corev1.Namespace, pod corev1.Pod) (corev1.Pod, error) {
logger := pm.Logger.WithValues("namespace", pod.Namespace, "name", pod.Name)
}
在这个接口中我们就可以拿到 Pod 的信息,然后再获取 CRD Instrumentation 做我们的业务逻辑.
var otelInsts v1alpha1.InstrumentationList
if err := pm.Client.List(ctx, &otelInsts, client.InNamespace(ns.Name)); err != nil {
return nil, err
}
// 从 CRD 中将数据复制到业务容器中。
pod.Spec.InitContainers = append(pod.Spec.InitContainers, corev1.Container{
Name: javaInitContainerName,
Image: javaSpec.Image,
Command: []string{"cp", "/javaagent.jar", javaInstrMountPath + "/javaagent.jar"},
Resources: javaSpec.Resources,
VolumeMounts: []corev1.VolumeMount{{
Name: javaVolumeName,
MountPath: javaInstrMountPath,
}},
})
for i, extension := range javaSpec.Extensions {
pod.Spec.InitContainers = append(pod.Spec.InitContainers, corev1.Container{
Name: initContainerName + fmt.Sprintf("-extension-%d", i),
Image: extension.Image,
Command: []string{"cp", "-r", extension.Dir + "/.", javaInstrMountPath + "/extensions"},
Resources: javaSpec.Resources,
VolumeMounts: []corev1.VolumeMount{{
Name: javaVolumeName,
MountPath: javaInstrMountPath,
}},
})
}
不过需要注意的是想要在测试环境中测试 operator 是需要安装一个 cert-manage,这样 webhook 才能正常的回调.
要使得 CRD 生效,我们还得先将 CRD 安装进 kubernetes 集群中,不过这些 operator-sdk 这类根据已经考虑周到了.
我们只需要定义好 CRD 的结构体:
然后使用 Makefile 中的工具 make bundle 就会自动将结构体转换为 CRD.
参考链接:
最后此篇关于从Helm到Operator:Kubernetes应用管理的进化的文章就讲到这里了,如果你想了解更多关于从Helm到Operator:Kubernetes应用管理的进化的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
有没有办法根据全局 values.yaml 有条件地安装 helm 子图?我将所有内部服务和组件都作为子图表,其中之一是消息队列图表。在我的开发和测试环境(本地 k8s)中,我使用 RabbitMQ,
我是 Helm 新手。 我在父图表中有一个默认值。我想默认在每个子图中使用这个值,但也有可能覆盖特定子图的值。 例子: # Parent-chart values.yaml global: sch
我正在使用 Helm chart 来部署大约 15 个微服务。有一个带有 requirements.yaml 的父 Helm chart 其中所有必需的微服务都列为依赖项。 sample requir
我正在为我的应用程序创建一个 Helm chart 。在模板目录中,我有一个包含这个的 config-map.yaml {{- with Values.xyz }} xyz.abc-def: {{ .
我已将图表发布到Chartmuseum。是的,我已经运行了“helm repo更新”。 $ helm search chartmuseum/ NAME C
我正在尝试找到一种方法来删除 Helm 中所有已部署的版本。 看来 Helm does not support删除所有版本,使用 --all否则。 是否有另一种方法可以在一个命令中删除所有 Helm
我想知道helm template --debug之间哪个最好 和 helm install --dry-run --debug 谢谢 最佳答案 两个命令的区别在于helm install --dry
我已经使用 helm 在我的 GKE 集群上部署了 jupyterhub。但是,当我运行 helm list --all(或 helm list --failed 等)时,我看不到任何输出。 我可以确
我正在尝试使用 OCI 注册表 (ACR) 来存储我的 helm 图表。我找到了推送和拉取图表的方法,但我无法以 OCI native 方式登录注册表。 目前我可以通过以下方式登录: az acr l
我正在使用 helm 图表(带有子图表)来部署我的应用程序。我正在使用值文件来设置值。 我正在寻找一种在我的值文件(或任何其他地方)中设置对我的值文件有效的变量的方法。 我的值文件中有一些部分(服务)
我有一个包含以下键/值对的值文件: domains: - name: "one.dev.beta.com" - name: "two.dev.beta.com" - name: "thre
我正在尝试在我的 helm 模板中提供一个条件,以使用 regexMatch 函数检查有效(或相当无效)的主机名。 这是我正在使用的代码行: {{- if regexMatch "(?:[0-9]{1
我有一个带有可选组件的 Helm chart 。似乎支持可选组件的首选方法是将它们分成单独的图表并用标签切换它们。 我试过了,但我的可选组件需要知道图表其余部分的变量(特定服务的地址)。这会导致事情破
我目前正在为多容器应用程序编写 Helm 图表。我们有一堆微服务容器(我们称它们为“应用程序”),它们在通过 K8s 处理的方式上非常相似,并且可以(因此应该)由相同的 Helm 模板处理以避免重复。
我正在安装 prometheus-redis-exporter Helm chart .其Deployment对象有一种注入(inject)注解的方法: # deployment.yaml ...
我无法摆脱这种状态:PENDING_INSTALL .这导致 terraform 无法部署。有没有办法不删除? # helm status core-api LAST DEPLOYED: Mon Ju
我正在寻找一种解决方案,将我的 values.yaml 中的列表转换为逗号分隔的列表。 值.yaml app: logfiletoexclude: - "/var/log/containe
我有一个 k8s 资源的通用模板,我想将其扩展 n 次(如果您好奇,这样我就可以创建 mongo 集群的 n 个成员,并且他们使用 statefulset 资源,以便每个成员都有一个稳定的网络姓名)。
我正在为 Web 服务开发一组 Helm 模板,该模板将整数 ID 作为其配置的一部分。该 Id 成为服务端点的一部分,编码为网络安全的 base64 字符集: 0=A 1=B 2=C ... 26=
我正在尝试将字典从一个 helm 模板传递到另一个 helm 模板,但它在被调用模板中解析为 null。 调用模板 - deployment.yaml 调用模板 - storageNodeAffini
我是一名优秀的程序员,十分优秀!