经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » Kubernetes » 查看文章
从 Helm 到 Operator:Kubernetes应用管理的进化
来源:cnblogs  作者:crossoverJie  时间:2024/7/8 9:54:16  对本文有异议

??Helm 的作用

在开始前需要先对 kubernetes Operator 有个简单的认识。

以为我们在编写部署一些简单 Deployment 的时候只需要自己编写一个 yaml 文件然后 kubectl apply 即可。

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. labels:
  5. app: k8s-combat
  6. name: k8s-combat
  7. spec:
  8. replicas: 1
  9. selector:
  10. matchLabels:
  11. app: k8s-combat
  12. template:
  13. metadata:
  14. labels:
  15. app: k8s-combat
  16. spec:
  17. containers:
  18. - name: k8s-combat
  19. image: crossoverjie/k8s-combat:v1
  20. imagePullPolicy: Always
  21. resources:
  22. limits:
  23. cpu: "1"
  24. memory: 300Mi
  25. requests:
  26. cpu: "0.1"
  27. memory: 30Mi
  1. kubectl apply -f deployment.yaml

这对于一些并不复杂的项目来说完全够用了,但组件一多就比较麻烦了。


这里以 Apache Pulsar 为例:它的核心组件有:

  • Broker
  • Proxy
  • Zookeeper
  • Bookkeeper
  • Prometheus(可选)
  • Grafana(可选)
    等组件,每个组件的启动还有这依赖关系。

必须需要等 Zookeeper 和 Bookkeeper 启动之后才能将流量放进来。

此时如何还继续使用 yaml 文件一个个部署就会非常繁琐,好在社区有提供 Helm 一键安装程序,使用它我们只需要在一个同意的 yaml 里简单的配置一些组件,配置就可以由 helm 来部署整个复杂的 Pulsar 系统。

  1. components:
  2. # zookeeper
  3. zookeeper: true
  4. # bookkeeper
  5. bookkeeper: true
  6. # bookkeeper - autorecovery
  7. autorecovery: true
  8. # broker
  9. broker: true
  10. # functions
  11. functions: false
  12. # proxy
  13. proxy: true
  14. # toolset
  15. toolset: true
  16. # pulsar manager
  17. pulsar_manager: false
  18. monitoring:
  19. # monitoring - prometheus
  20. prometheus: true
  21. # monitoring - grafana
  22. grafana: true
  23. # monitoring - node_exporter
  24. node_exporter: true
  25. # alerting - alert-manager
  26. alert_manager: false

比如在 helm 的 yaml 中我们可以选择使用哪些 components,以及是否启用监控组件。

最后直接使用这个文件进行安装:

  1. 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 输出后人工审核

  1. helm install pulsar apache/pulsar --dry-run --debug > debug.yaml

??Operator 是什么

??Helm 的痛点

Helm 虽然可以帮我们部署或者升级一个大型应用,但他却没法帮我们运维这个应用。

举个例子:比如我希望当 Pulsar Broker 的流量或者内存达到某个阈值后就指定扩容 Broker,闲时再自动回收。

或者某个 Bookkeeper 的磁盘使用率达到阈值后可以自动扩容磁盘,这些仅仅使用 Helm 时都是无法实现的。

以上这些需求我们目前也是通过监控系统发出报警,然后再由人工处理。

其中最大的痛点就是进行升级:

  • 升级ZK
  • 关闭auto recovery
  • 升级Bookkeeper
  • 升级Broker
  • 升级Proxy
  • 开启auto recovery

因为每次升级是有先后顺序的,需要依次观察每个组件运行是否正常才能往后操作。

如果有 Operator 理性情况下下我们只需要更新一下镜像版本,它就可以自动执行以上的所有步骤最后将集群升级完毕。

所以相对于 Helm 来说 Operator 是可以站在一个更高的视角俯视整个应用系统,它能发现系统哪个地方需要它从而直接修复。

??CRD(Custom Resource Definitions)

而提到 Operator 那就不得不提到 CRD(Custom Resource Definitions)翻译过来就是自定义资源。

这是 kubernetes 提供的一个 API 扩展机制,类似于内置的 Deployment/StatefulSet/Services 资源,CRD 是一种自定义的资源。

这里以我们常用的 prometheus-operatorVictoriaMetrics-operator 为例:

Prometheus:

  • Prometheus:用于定义 Prometheus 的 Deployment
  • Alertmanager:用于定义 Alertmanager
  • ScrapeConfig:用于定会抓取规则
  1. apiVersion: monitoring.coreos.com/v1alpha1
  2. kind: ScrapeConfig
  3. metadata:
  4. name: static-config
  5. namespace: my-namespace
  6. labels:
  7. prometheus: system-monitoring-prometheus
  8. spec:
  9. staticConfigs:
  10. - labels:
  11. job: prometheus
  12. targets:
  13. - prometheus.demo.do.prometheus.io:9090

使用时的一个很大区别就是资源的 kind: ScrapeConfig 为自定义的类型。

VictoriaMetrics 的 CRD:

  • VMPodScrape:Pod 的抓取规则
  • VMCluster:配置 VM 集群
  • VMAlert:配置 VM 的告警规则
  • 等等
  1. # vmcluster.yaml
  2. apiVersion: operator.victoriametrics.com/v1beta1
  3. kind: VMCluster
  4. metadata:
  5. name: demo
  6. spec:
  7. retentionPeriod: "1"
  8. replicationFactor: 2
  9. vmstorage:
  10. replicaCount: 2
  11. storageDataPath: "/vm-data"
  12. storage:
  13. volumeClaimTemplate:
  14. spec:
  15. resources:
  16. requests:
  17. storage: "10Gi"
  18. resources:
  19. limits:
  20. cpu: "1"
  21. memory: "1Gi"
  22. vmselect:
  23. replicaCount: 2
  24. cacheMountPath: "/select-cache"
  25. storage:
  26. volumeClaimTemplate:
  27. spec:
  28. resources:
  29. requests:
  30. storage: "1Gi"
  31. resources:
  32. limits:
  33. cpu: "1"
  34. memory: "1Gi"
  35. requests:
  36. cpu: "0.5"
  37. memory: "500Mi"
  38. vminsert:
  39. replicaCount: 2

以上是用于创建一个 VM 集群的 CRD 资源,应用之后就会自动创建一个集群。

Operator 原理


Operator 通常是运行在 kubernetes API server 的 webhook 之上,简单来说就是在一些内置资源的关键节点 API-server 会调用我们注册的一个 webhook,在这个 webhook 中我们根据我们的 CRD 做一些自定义的操作。

理论上我们可以使用任何语言都可以写 Operator,只需要能处理 api-server 的回调即可。

只是 Go 语言有很多成熟的工具,比如常用的 kubebuilderoperator-sdk.

他们内置了许多命令行工具,可以帮我们节省需要工作量。

这里以 operator-sdk 为例:

  1. $ operator-sdk create webhook --group cache --version v1alpha1 --kind Memcached --defaulting --programmatic-validation

会直接帮我们创建好一个标准的 operator 项目:

  1. ├── Dockerfile
  2. ├── Makefile
  3. ├── PROJECT
  4. ├── api
  5.    └── v1alpha1
  6.    ├── memcached_webhook.go
  7.    ├── webhook_suite_test.go
  8. ├── config
  9.    ├── certmanager
  10.       ├── certificate.yaml
  11.       ├── kustomization.yaml
  12.       └── kustomizeconfig.yaml
  13.    ├── default
  14.       ├── manager_webhook_patch.yaml
  15.       └── webhookcainjection_patch.yaml
  16.    └── webhook
  17.    ├── kustomization.yaml
  18.    ├── kustomizeconfig.yaml
  19.    └── service.yaml
  20. ├── go.mod
  21. ├── go.sum
  22. └── main.go

其中 Makefile 中包含了开发过程中常用的工具链(包括根据声明的结构体自动生成 CRD 资源、部署k8s 环境测试等等)、Dockerfile 等等。

这样我们就只需要专注于开发业务逻辑即可。

因为我前段时间给 https://github.com/open-telemetry/opentelemetry-operator 贡献过两个 feature,所以就以这个 Operator 为例:

它有一个 CRD: kind: Instrumentation,在这个 CRD 中可以将 OpenTelemetry 的 agent 注入到应用中。

  1. apiVersion: opentelemetry.io/v1alpha1
  2. kind: Instrumentation
  3. metadata:
  4. name: instrumentation-test-order
  5. namespace: test
  6. spec:
  7. env:
  8. - name: OTEL_SERVICE_NAME
  9. value: order
  10. selector:
  11. matchLabels:
  12. app: order
  13. java:
  14. image: autoinstrumentation-java:2.4.0-release
  15. extensions:
  16. - image: autoinstrumentation-java:2.4.0-release
  17. dir: /extensions
  18. env:
  19. - name: OTEL_RESOURCE_ATTRIBUTES
  20. value: service.name=order
  21. - name: OTEL_INSTRUMENTATION_MESSAGING_EXPERIMENTAL_RECEIVE_TELEMETRY_ENABLED
  22. value: "true"
  23. - name: OTEL_TRACES_EXPORTER
  24. value: otlp
  25. - name: OTEL_METRICS_EXPORTER
  26. value: otlp
  27. - name: OTEL_LOGS_EXPORTER
  28. value: none
  29. - name: OTEL_EXPORTER_OTLP_ENDPOINT
  30. value: http://open-telemetry-opentelemetry-collector.otel.svc.cluster.local:4317
  31. - name: OTEL_EXPORTER_OTLP_COMPRESSION
  32. value: gzip
  33. - name: OTEL_EXPERIMENTAL_EXPORTER_OTLP_RETRY_ENABLED
  34. value: "true"

它的运行规则是当我们的 Pod 在启动过程中会判断 Pod 的注解中是否开启了注入 OpenTelemetry 的配置。

如果开启则会将我们在 CRD 中自定义的镜像里的 javaagent 复制到业务容器中,同时会将下面的那些环境变量也一起加入的业务容器中。

要达到这样的效果就需要我们注册一个回调 endpoint。

  1. mgr.GetWebhookServer().Register("/mutate-v1-pod", &webhook.Admission{
  2. Handler: podmutation.NewWebhookHandler(cfg, ctrl.Log.WithName("pod-webhook"), decoder, mgr.GetClient(),
  3. []podmutation.PodMutator{
  4. sidecar.NewMutator(logger, cfg, mgr.GetClient()),
  5. instrumentation.NewMutator(logger, mgr.GetClient(), mgr.GetEventRecorderFor("opentelemetry-operator"), cfg),
  6. }),})

当 Pod 创建或有新的变更请求时就会回调我们的接口。

  1. func (pm *instPodMutator) Mutate(ctx context.Context, ns corev1.Namespace, pod corev1.Pod) (corev1.Pod, error) {
  2. logger := pm.Logger.WithValues("namespace", pod.Namespace, "name", pod.Name)
  3. }

在这个接口中我们就可以拿到 Pod 的信息,然后再获取 CRD Instrumentation 做我们的业务逻辑。

  1. var otelInsts v1alpha1.InstrumentationList
  2. if err := pm.Client.List(ctx, &otelInsts, client.InNamespace(ns.Name)); err != nil {
  3. return nil, err
  4. }
  5. // 从 CRD 中将数据复制到业务容器中。
  6. pod.Spec.InitContainers = append(pod.Spec.InitContainers, corev1.Container{
  7. Name: javaInitContainerName,
  8. Image: javaSpec.Image,
  9. Command: []string{"cp", "/javaagent.jar", javaInstrMountPath + "/javaagent.jar"},
  10. Resources: javaSpec.Resources,
  11. VolumeMounts: []corev1.VolumeMount{{
  12. Name: javaVolumeName,
  13. MountPath: javaInstrMountPath,
  14. }},
  15. })
  16. for i, extension := range javaSpec.Extensions {
  17. pod.Spec.InitContainers = append(pod.Spec.InitContainers, corev1.Container{
  18. Name: initContainerName + fmt.Sprintf("-extension-%d", i),
  19. Image: extension.Image,
  20. Command: []string{"cp", "-r", extension.Dir + "/.", javaInstrMountPath + "/extensions"},
  21. Resources: javaSpec.Resources,
  22. VolumeMounts: []corev1.VolumeMount{{
  23. Name: javaVolumeName,
  24. MountPath: javaInstrMountPath,
  25. }},
  26. })
  27. }

不过需要注意的是想要在测试环境中测试 operator 是需要安装一个 cert-manage,这样 webhook 才能正常的回调。


要使得 CRD 生效,我们还得先将 CRD 安装进 kubernetes 集群中,不过这些 operator-sdk 这类根据已经考虑周到了。

我们只需要定义好 CRD 的结构体:

然后使用 Makefile 中的工具 make bundle 就会自动将结构体转换为 CRD。

参考链接:

原文链接:https://www.cnblogs.com/crossoverJie/p/18289299

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号