一、怎样在 Kubernetes 提供软件服务
在 Kubernetes 环境中运行工作负载看似简单——编写一个 Deployment YAML,提交给 apiserver,Pod 就能跑起来。然而,当团队规模扩大、应用复杂度提升时,简单的 YAML 复制已经无法满足需求。开发者关心的是「我的应用需要哪些资源」、「如何配置才能连接数据库」、「版本如何滚动更新」,而不是 Kubernetes 的 API 对象细节。
这正是应用模型(Application Model)要解决的问题——在 Kubernetes 之上抽象出一层应用级的概念,让开发者以应用的视角而非资源对象的视角来管理服务。
常见的应用抽象模型包括:
| 方案 | 设计目标 | 适用场景 |
|---|---|---|
| Helm | Chart 包管理,通过模板化实现 YAML 的复用与版本化 | 通用服务的模板化发布 |
| Kustomize | 声明式配置叠加,通过 patch 机制实现环境差异化 | 多环境(dev/staging/prod)配置管理 |
| OAM | 标准化应用定义,分离开发角色与运维角色 | 平台构建,应用开发者聚焦业务逻辑 |
| Operator | 将运维知识编码为 CRD,实现复杂有状态应用的管理 | 数据库、消息队列等有状态中间件 |
这些方案并非互斥,实际上可以组合使用。例如,使用 OAM 定义应用架构,用 Helm 作为 OAM 应用的交付载体。
二、Kubernetes 核心工作负载
在深入应用管理方案之前,需要先理解 Kubernetes 内置的核心工作负载类型,它们是一切应用模型的基础。
2.1 Deployment:无状态应用管理
Deployment 是 Kubernetes 中最常用的工作负载控制器,用于管理无状态应用。它通过 ReplicaSet 控制 Pod 的副本数,并提供声明式的滚动更新和回滚能力。
一个典型的 Deployment 定义如下:
apiVersion: apps/v1kind: Deploymentmetadata: name: web-app labels: app: web-appspec: replicas: 3 selector: matchLabels: app: web-app strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 # 滚动更新时允许超出副本数的最大 Pod 数 maxUnavailable: 0 # 滚动更新时允许不可用的最大 Pod 数 template: metadata: labels: app: web-app spec: containers: - name: web-app image: myapp:v2.0.0 ports: - containerPort: 8080 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 512Mi readinessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 15 periodSeconds: 20Deployment 更新策略
Deployment 支持两种更新策略:
- RollingUpdate(默认):渐进式地用新 Pod 替换旧 Pod。通过
maxSurge和maxUnavailable两个参数控制更新速率。maxSurge=1, maxUnavailable=0表示先创建 1 个新 Pod,等其就绪后再删除 1 个旧 Pod,始终保证总可用副本数不低于期望值。这是最安全的策略,适合生产环境。 - Recreate:先删除所有旧 Pod,再创建新 Pod。更新期间服务会中断,适合开发/测试环境或可以接受短暂中断的场景。
Deployment 回滚
当新版本出现问题时,可以快速回滚到之前的版本:
# 查看部署历史kubectl rollout history deployment/web-app
# 查看特定版本的详情kubectl rollout history deployment/web-app --revision=2
# 回滚到上一版本kubectl rollout undo deployment/web-app
# 回滚到指定版本kubectl rollout undo deployment/web-app --to-revision=2
# 暂停滚动更新(用于金丝雀发布)kubectl rollout pause deployment/web-app
# 恢复滚动更新kubectl rollout resume deployment/web-app2.2 StatefulSet:有状态应用管理
StatefulSet 是管理有状态应用的工作负载控制器。与 Deployment 不同,StatefulSet 为每个 Pod 提供稳定的网络标识、稳定的持久化存储和有序的部署/删除/滚动更新。
StatefulSet 的核心特性:
- 稳定的网络标识:每个 Pod 的主机名格式为
$(statefulset-name)-$(ordinal),例如mysql-0、mysql-1、mysql-2。配合 Headless Service,每个 Pod 都有稳定的 DNS 名称:mysql-0.mysql.default.svc.cluster.local。 - 稳定的持久化存储:每个 Pod 可以绑定独立的 PVC,即使 Pod 被重新调度,PVC 也会保留并重新挂载到同一个 Pod。
- 有序的部署和扩展:Pod 按序号顺序创建(0 → 1 → 2),删除时逆序进行(2 → 1 → 0)。
一个 MySQL 主从复制的 StatefulSet 示例:
apiVersion: apps/v1kind: StatefulSetmetadata: name: mysqlspec: serviceName: mysql # 必须指定 Headless Service replicas: 3 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:8.0 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: root-password ports: - containerPort: 3306 volumeMounts: - name: data mountPath: /var/lib/mysql volumeClaimTemplates: # 为每个 Pod 自动创建独立的 PVC - metadata: name: data spec: accessModes: ["ReadWriteOnce"] storageClassName: ssd resources: requests: storage: 50GiStatefulSet 更新策略
StatefulSet 支持两种更新策略:
- RollingUpdate(默认):按序号逆序更新 Pod(2 → 1 → 0),每更新一个 Pod 等待其就绪后再更新下一个。可以通过
partition参数实现灰度发布——只有序号 ≥ partition 的 Pod 会被更新。 - OnDelete:不自动更新 Pod,需要手动删除 Pod 触发重建。适合需要精确控制更新时机的场景。
spec: updateStrategy: type: RollingUpdate rollingUpdate: partition: 2 # 只更新序号 >= 2 的 Pod(灰度发布)2.3 DaemonSet:节点级守护进程
DaemonSet 确保每个(或特定)节点上运行一个 Pod 副本。当节点加入集群时,DaemonSet 自动在该节点上调度 Pod;当节点移除时,DaemonSet 自动回收 Pod。
DaemonSet 的典型用例包括:
- 日志采集:Fluentd、Filebeat 等在每个节点采集容器日志并输出到集中式存储。
- 监控 Agent:Prometheus Node Exporter、Datadog Agent 等在每个节点采集主机指标。
- 网络插件:Calico、Flannel、Cilium 等在每个节点配置网络规则。
- 存储插件:CSI Node Driver 在每个节点挂载存储卷。
apiVersion: apps/v1kind: DaemonSetmetadata: name: fluentd labels: app: fluentdspec: selector: matchLabels: app: fluentd template: metadata: labels: app: fluentd spec: tolerations: - key: node-role.kubernetes.io/control-plane effect: NoSchedule # 允许在控制平面节点运行 containers: - name: fluentd image: fluent/fluentd:v1.16 resources: limits: cpu: 200m memory: 256Mi volumeMounts: - name: varlog mountPath: /var/log - name: containers mountPath: /var/lib/docker/containers volumes: - name: varlog hostPath: path: /var/log - name: containers hostPath: path: /var/lib/docker/containersDaemonSet 可以通过 nodeSelector 或 affinity 限制只在特定节点上运行:
spec: template: spec: nodeSelector: node-type: worker # 只在带有 node-type=worker 标签的节点运行 # 或者使用更灵活的 affinity affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: node-type operator: In values: ["worker", "infra"]2.4 Job 和 CronJob:批处理任务
Job 用于运行一次性任务,确保指定数量的 Pod 成功完成。CronJob 则按照 Cron 表达式定期创建 Job。
# 一次性数据迁移任务apiVersion: batch/v1kind: Jobmetadata: name: data-migrationspec: completions: 1 # 需要 1 个 Pod 成功完成 parallelism: 1 # 同时运行 1 个 Pod backoffLimit: 3 # 失败重试次数上限 activeDeadlineSeconds: 300 # 任务最长运行时间 template: spec: restartPolicy: Never # Job 不使用 OnFailure 以外的重启策略 containers: - name: migrate image: myapp:migrate-v1 command: ["python", "migrate.py"]# 定期数据库备份apiVersion: batch/v1kind: CronJobmetadata: name: db-backupspec: schedule: "0 2 * * *" # 每天凌晨 2 点 concurrencyPolicy: Forbid # 禁止并发执行 successfulJobsHistoryLimit: 3 failedJobsHistoryLimit: 1 jobTemplate: spec: template: spec: restartPolicy: OnFailure containers: - name: backup image: myapp:backup-v1 command: ["bash", "-c", "pg_dump ... | aws s3 cp - s3://backup/"]三、怎样在 Kubernetes 上发布应用
3.1 Helm:Chart 包管理
Helm 是 Kubernetes 生态中最成熟的包管理工具,类似于 Ubuntu 的 apt 或 Homebrew。它将一组 Kubernetes 资源打包为 Chart,通过模板化参数实现跨环境复用,并通过 release 概念实现版本跟踪和回滚。
Helm 经历了两个大版本的重大演进:
- Helm v2(2016 年):采用 Client-Server 架构,Server 端 Tiller 拥有集群管理员权限,存在安全风险。Tiller 是 Helm v2 的核心组件,负责在集群内执行模板渲染和资源部署。
- Helm v3(2019 年 11 月):移除了 Tiller,改为纯客户端架构。模板渲染在本地执行,通过调用 kubeconfig 中的用户凭证与 API Server 交互,安全性大幅提升。同时引入了 JSON Schema 验证、Lua 自定义 Hook 等新特性。
一个典型的 Helm Chart 结构如下:
myapp/├── Chart.yaml # Chart 元数据├── values.yaml # 默认配置参数├── values-prod.yaml # 生产环境覆盖├── templates/ # Kubernetes 资源模板│ ├── deployment.yaml│ ├── service.yaml│ ├── ingress.yaml│ ├── _helpers.tpl # 命名模板(可复用的模板片段)│ └── NOTES.txt # 安装后的提示信息└── charts/ # 依赖的子 Chartvalues.yaml 定义了可配置的参数,模板中通过 {{ .Values.image.repository }} 引用:
replicaCount: 2image: repository: myapp tag: latest pullPolicy: IfNotPresentservice: type: ClusterIP port: 80ingress: enabled: false className: nginx hosts: - host: myapp.local paths: - path: / pathType: Prefixresources: limits: cpu: 500m memory: 512Mi requests: cpu: 100m memory: 128Miautoscaling: enabled: false minReplicas: 2 maxReplicas: 10 targetCPUUtilizationPercentage: 80使用 helm install 部署应用时,可以通过 -f values-prod.yaml 加载生产环境配置,或通过 --set 直接覆盖单个参数:
# 从 Chart 目录安装helm install myapp ./myapp
# 从压缩包安装helm install myapp ./myapp-1.0.0.tgz
# 从远程仓库安装helm install myapp oci://registry.example.com/charts/myapp
# 指定生产环境配置helm install myapp ./myapp -f values-prod.yaml
# 运行时覆盖参数helm install myapp ./myapp --set replicaCount=5
# 预渲染模板(调试用)helm template myapp ./myapp > rendered.yaml
# 升级已部署的 releasehelm upgrade myapp ./myapp -f values-prod.yaml
# 安装或升级(推荐用法)helm upgrade --install myapp ./myapp -f values-prod.yaml
# 回滚到上一版本helm rollback myapp
# 回滚到指定版本helm rollback myapp 2
# 查看已部署的 releasehelm list
# 查看 release 的值helm get values myappHelm 高级特性
条件渲染:根据 values 中的布尔值决定是否渲染某个资源:
{{- if .Values.ingress.enabled }}apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: {{ include "myapp.fullname" . }}spec: ingressClassName: {{ .Values.ingress.className }} rules: {{- range .Values.ingress.hosts }} - host: {{ .host }} http: paths: {{- range .paths }} - path: {{ .path }} pathType: {{ .pathType }} backend: service: name: {{ include "myapp.fullname" $ }} port: number: {{ $.Values.service.port }} {{- end }} {{- end }}{{- end }}命名模板(Named Templates):在 _helpers.tpl 中定义可复用的模板片段,减少重复代码:
{{- define "myapp.labels" -}}app.kubernetes.io/name: {{ .Chart.Name }}app.kubernetes.io/instance: {{ .Release.Name }}app.kubernetes.io/version: {{ .Chart.AppVersion }}app.kubernetes.io/managed-by: {{ .Release.Service }}{{- end }}Chart 依赖管理:通过 Chart.yaml 的 dependencies 字段声明子 Chart:
apiVersion: v2name: myappversion: 1.0.0appVersion: "2.0"dependencies: - name: redis version: "18.0.0" repository: "https://charts.bitnami.com/bitnami" condition: redis.enabled # 可通过 values 控制是否安装 - name: postgresql version: "14.0.0" repository: "https://charts.bitnami.com/bitnami" condition: postgresql.enabled alias: db # 在 values 中通过 db 而非 postgresql 引用Helm 的模板机制非常强大,支持条件渲染、函数调用、命名模板等高级特性。但这也带来调试困难的问题——本地建议使用 helm template 预渲染查看展开后的 YAML,确认无误后再执行 helm install。
3.2 Kustomize:声明式配置叠加
Kustomize 是 Kubernetes 原生的配置管理工具,从 kubectl v1.14 开始内置支持(kubectl apply -k)。与 Helm 的模板化方式不同,Kustomize 通过声明式的 Patch 机制实现配置差异化,不引入模板语法,更贴近 Kubernetes 原生风格。
Kustomize 的核心概念:
- Base:基础配置,包含共享的 Kubernetes 资源定义。
- Overlay:叠加层,在 Base 之上通过 Patch 实现环境差异化。
- Kustomization:描述 Base 和 Overlay 关系的配置文件。
一个典型的 Kustomize 项目结构:
myapp/├── base/│ ├── kustomization.yaml│ ├── deployment.yaml│ ├── service.yaml│ └── configmap.yaml└── overlays/ ├── dev/ │ ├── kustomization.yaml │ └── patch-replicas.yaml ├── staging/ │ ├── kustomization.yaml │ └── patch-replicas.yaml └── prod/ ├── kustomization.yaml ├── patch-replicas.yaml └── patch-resources.yamlBase 的 kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationresources: - deployment.yaml - service.yaml - configmap.yamlnamespace: myappcommonLabels: app: myapp开发环境的 Overlay:
apiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationbases: - ../../basepatchesStrategicMerge: - patch-replicas.yamlapiVersion: apps/v1kind: Deploymentmetadata: name: web-appspec: replicas: 1# 预览开发环境配置kubectl kustomize overlays/dev
# 直接部署kubectl apply -k overlays/dev
# 对比不同环境的差异diff <(kubectl kustomize overlays/dev) <(kubectl kustomize overlays/prod)3.3 OAM:标准化应用定义
OAM(Open Application Model)是由阿里云和微软共同提出的应用模型规范,旨在分离应用开发者与平台运维者的职责。开发者只需要声明「我的应用包含哪些组件、需要什么运维特征」,而具体的 Kubernetes 资源实现则由平台根据这些声明自动生成。
OAM 的核心概念包括:
- Component:应用组件,定义 workloads(如 Web 服务、后台任务)和其配置参数
- Trait:运维特征,附加到 Component 上的运维能力(如副本数、环境变量、入口规则)
- Application Scope:应用作用域,定义组件之间的分组关系(如共享配置)
- Application Configuration:应用配置,将 Component、Trait 和 Scope 组合在一起形成完整的应用定义
一个 OAM Application 示例:
apiVersion: core.oam.dev/v1alpha2kind: Applicationmetadata: name: myappspec: components: - name: web type: webservice settings: image: myapp:v1.0.0 port: 8080 cpu: 1 memory: 1Gi traits: - name: scaler properties: replica: 3 - name: ingress properties: domain: myapp.example.com path: / entrypoint: web - name: db type: webservice settings: image: postgres:15 port: 5432 cpu: 2 memory: 4Gi traits: - name: scaler properties: replica: 1可以看到,开发者的关注点是「这个服务需要多少 CPU 和内存」、「需要 3 个副本」这样的业务语言,而不是 Deployment、Service、Ingress 这些 Kubernetes 实现细节。
当前 OAM 的落地实现主要有 KubeVela 平台。KubeVela 作为基于 OAM 的现代化应用交付平台,可以将 OAM 应用直接部署到 Kubernetes 集群,并支持通过插件扩展 Trait 能力。KubeVela 还支持多集群分发、工作流编排等高级特性。
3.4 Operator:运维知识的代码化
对于无状态的 Web 服务,Deployment + ConfigMap 的组合已经足够。但对于有状态的中间件(如 MySQL、Redis、Kafka),事情变得复杂——这些应用有自己的运维理念:如何扩缩容而不丢数据、如何进行版本升级而不中断服务、如何处理故障自愈。
Operator 模式的核心思想是用代码封装运维知识。开发者编写一个 Custom Resource Definition(CRD)和对应的 Controller,Controller 监听 CR 资源的变化,自动完成运维操作。
Operator 的核心组成
一个 Operator 由以下部分组成:
- CRD(Custom Resource Definition):定义自定义资源的 Schema,扩展 Kubernetes API。用户通过创建 CR 实例来声明期望状态。
- Controller:监听 CR 资源的变化,执行 Reconcile 循环,将实际状态驱动到期望状态。
- RBAC 权限:Controller 需要 ServiceAccount 和 RBAC 权限来操作 Kubernetes 资源。
以 Prometheus Operator 为例:
# CRD 定义了 Prometheus 自定义资源apiVersion: monitoring.coreos.com/v1kind: Prometheusmetadata: name: examplespec: replicas: 2 retention: 30d serviceAccountName: prometheus resources: requests: cpu: 500m memory: 1Gi storage: volumeClaimTemplate: spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 50Gi只需要声明期望的副本数和保留周期,Operator 会自动创建 ConfigMap、Service、StatefulSet 等关联资源,并持续监控状态确保实际部署符合声明。
Operator 的成熟度模型
CNCF Operator Framework 定义了 Operator 的五个成熟度等级:
| 等级 | 名称 | 能力描述 | 示例 |
|---|---|---|---|
| Level 1 | Basic Install | 自动化安装和卸载 | Helm Operator |
| Level 2 | Seamless Upgrades | 无缝升级和回滚 | 支持版本升级的 Operator |
| Level 3 | Full Lifecycle | 完整生命周期管理(备份、恢复、扩缩容) | Percona MySQL Operator |
| Level 4 | Deep Insights | 深度可观测性(指标、告警、日志分析) | Prometheus Operator |
| Level 5 | Auto Pilot | 自动驾驶(自调优、异常检测、自愈) | Crossplane |
成熟的 Operator 生态
社区提供了大量成熟的 Operator,涵盖数据库、消息队列、存储、安全等各个领域:
| 类别 | 代表 Operator | 功能 |
|---|---|---|
| 数据库 | Percona Operator for MySQL | MySQL 半同步复制、自动备份 |
| Vitess Operator | 分片扩展、在线 Schema 变更 | |
| PostgreSQL Operator (Zalando) | Patroni 高可用、自动故障转移 | |
| 消息队列 | Strimzi Operator | Kafka 集群管理、TLS 加密 |
| RabbitMQ Operator | 集群创建、用户管理 | |
| 存储 | Rook Operator | Ceph/EdgeFS 存储编排 |
| 服务网格 | Istio Operator | 网格配置、流量管理 |
| 可观测性 | Prometheus Operator | Prometheus/Alertmanager 管理 |
编写 Operator 的框架
编写一个 Operator 通常需要借助框架,主流框架包括:
- Kubebuilder:SIG CLI 维护的官方框架,基于 controller-runtime 库,提供 CRD 生成、Controller 脚手架、Makefile 和集成测试模板。适合对 Kubernetes API 有深入了解的开发者。
- Operator SDK:Red Hat 维护的框架,支持 Go、Ansible、Helm 三种方式编写 Operator。Ansible 和 Helm 方式降低了入门门槛,无需编写 Go 代码即可创建 Level 1~2 的 Operator。
- KubeVela:基于 OAM 的应用交付平台,通过 CUE 模板定义 Workload 和 Trait,自动生成 CRD 和 Controller,适合平台构建者。
以 Kubebuilder 为例,创建一个 Operator 的基本流程:
# 初始化项目kubebuilder init --domain my.domain --repo my.domain/guestbook
# 创建 API(CRD + Controller)kubebuilder create api --group webapp --version v1 --kind Guestbook
# 生成 CRD 清单make manifests
# 安装 CRD 到集群make install
# 本地运行 Controller(开发调试)make run
# 构建 Operator 镜像make docker-build docker-push IMG=myrepo/guestbook-operator:v0.1.0生成的 CRD 定义和 Reconcile 循环框架:
type GuestbookSpec struct { // +kubebuilder:validation:Minimum=1 Replicas *int32 `json:"replicas"` Image string `json:"image"`}
type GuestbookStatus struct { AvailableReplicas int32 `json:"availableReplicas"`}
// internal/controller/guestbook_controller.gofunc (r *GuestbookReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { var guestbook webappv1.Guestbook if err := r.Get(ctx, req.NamespacedName, &guestbook); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) }
// 期望状态:guestbook.Spec.Replicas // 实际状态:查询当前运行的 Deployment // 执行动作:创建/更新/删除 Deployment 以收敛到期望状态
return ctrl.Result{}, nil}四、参考资料
- Helm 官方文档
- Kustomize 官方文档
- OAM 规范
- KubeVela 官方文档
- Operator SDK 官方文档
- Operator Pattern - Kubernetes 官方文档
- Kubebuilder 官方文档
- Kubernetes Workloads 文档
- Deployment 策略详解
- StatefulSet 最佳实践
- Operator 成熟度模型
- CNCF Operator 白皮书
参考
- Percona Operator for MySQL
- Vitess Operator
- PostgreSQL Operator (Zalando)
- Strimzi Operator
- RabbitMQ Operator
- Rook Operator
- Istio Operator
- Prometheus Operator
- Helm 官方文档
- Kustomize 官方文档
- OAM 规范
- KubeVela 官方文档
- Operator SDK 官方文档
- Operator Pattern - Kubernetes 官方文档
- Kubebuilder 官方文档
- Kubernetes Workloads 文档
- Deployment 策略详解
- StatefulSet 最佳实践
- Operator 成熟度模型
- CNCF Operator 白皮书
支持与分享
如果这篇文章对你有帮助,欢迎支持作者或分享给更多人
部分信息可能已经过时






