【Kubernetes从入门到精通】第12篇:Annotation——K8s的“便利贴“文化
2026/8/3 13:50:24 网站建设 项目流程

上一篇【第11篇】Namespace——给你的K8s集群划地盘
下一篇【第13篇】Deployment——无状态应用的"自动档"


摘要

上一篇文章聊了Label——K8s里的"分类标签",专门用来做选择、过滤、分组。但有些信息你不想用来筛东西,只是想在资源上"贴个便条"备忘——比如"这个Deployment是张三建的"、“上次部署的版本号是123”、“Prometheus你过来抓一下指标”……这些就是Annotation的活。

Annotation不参与选择器匹配,不影响调度,不影响路由——它就是个自说自话的便利贴。但别小看它:K8s里很多高级功能(Ingress路由配置、Prometheus自动发现、Helm部署追踪)全靠Annotation驱动。本文从Annotation和Label的本质区别讲起,梳理最常用的系统Annotation,然后重点演示Ingress Nginx注解配置和Prometheus自动发现两个实战场景。


一、Annotation vs Label——到底有什么区别

很多新人搞不清楚Label和Annotation的区别,觉得"不都是KV对吗"。来,一句话讲清楚:

用Label做"选择"和"过滤",用Annotation存"附加信息"和"元数据"。

【Label vs Annotation —— 直观对比】 Label(分类标签): Annotation(便利贴): ┌────────────────────┐ ┌────────────────────┐ │ 用于:选择/过滤/分组 │ │ 用于:存附加信息 │ │ │ │ │ │ app: nginx │ │ 构建时间: 2026-07-28│ │ version: v1.25 │ │ Git commit: abc123 │ │ tier: frontend │ │ 创建人: 张三 │ │ environment: prod │ │ 联系方式: ext-8888 │ │ │ │ │ │ 被Selector使用 │ │ 不被Selector使用 │ │ Service靠它找Pod │ │ 工具/控制器读取它 │ │ kubectl -l 用它筛 │ │ 人类和程序参考它 │ └────────────────────┘ └────────────────────┘
维度LabelAnnotation
用途选择、过滤、分组存储附加元数据
被Selector匹配?✅ 是❌ 否
被kubectl -l筛选?✅ 是❌ 否
影响调度?✅ 是(nodeSelector)❌ 否
影响路由?✅ 是(Service)❌ 否(除非控制器读取)
键命名规范前缀+名称前缀+名称(一样)
值大小限制最大63字符无限制(但别太大,影响API性能)
速度快(用于频繁查找)不参与索引,但值可更大

要点:关键区别就一句话——Label是给K8s"看"的(用来做决策),Annotation是给"人"和"工具"看的(用来存信息)。如果你不确定用哪个,就问自己:"我以后会按这个字段筛选资源吗?"会的就用Label,不会的就用Annotation。

规则:什么时候用Annotation

【决策树:Label 还是 Annotation?】 "我需要用这个字段来筛选或分组资源吗?" │ ┌──┴──┐ │ 是 │──► 用 Label ✅ └─────┘ │ ┌──┴──┐ │ 否 │ └─────┘ │ "这个信息是用来驱动K8s行为的吗?" (比如Ingress规则、监控抓取配置) │ ┌──┴──┐ ┌──────────┐ │ 是 │──► 用 Annotation │ 否 │──► 可能不需要存K8s里 └─────┘ └──────────┘
# 正确示例:Label和Annotation各司其职apiVersion:v1kind:Podmetadata:name:my-nginx# Label —— 用于选择和分组labels:app:nginxversion:v1.25environment:production# Annotation —— 存附加信息annotations:build-version:"v1.25.3"build-time:"2026-07-28T10:30:00Z"git-commit:"a1b2c3d4"git-branch:"main"created-by:"zhangsan"team-contact:"ext-8888"description:"Main production nginx instance"spec:containers:-name:nginximage:nginx:1.25.3

二、常用系统Annotation——K8s自己也在贴便利贴

K8s内部很多控制器和组件通过Annotation传递信息。这些Annotation是K8s自动添加的,你看一眼就知道Pod的"前世今生"。

2.1 Deployment自动添加的Annotation

# 每个由Deployment创建的ReplicaSet自动带这些Annotationmetadata:annotations:deployment.kubernetes.io/desired-replicas:"3"# 期望副本数deployment.kubernetes.io/max-replicas:"4"# 最大副本数deployment.kubernetes.io/revision:"5"# 部署版本号(回滚就靠它)deployment.kubernetes.io/revision-history:"1,2,3,4"# 历史版本号

要点deployment.kubernetes.io/revision是Deployment回滚的关键——每个Deployment升级,这个数字就加1,K8s保留历史ReplicaSet,你就可以通过kubectl rollout undo回到任意历史版本。

2.2 kubectl自动添加的Annotation

# kubectl apply 时自动添加,记录是谁用什么命令创建/修改的kubectl apply-fnginx-deployment.yaml
# kubectl 自动加上的metadata:annotations:kubectl.kubernetes.io/last-applied-configuration:|{"apiVersion":"apps/v1","kind":"Deployment",...}

这个Annotation存的是你上次kubectl apply时提交的完整配置。kubectl apply用它来做"三向合并"——比较上次提交的配置、当前实际状态、这次提交的新配置——算出该做什么变更。

# 查看 last-applied-configurationkubectl get deployment nginx-ojsonpath='{.metadata.annotations.kubectl\.kubernetes\.io/last-applied-configuration}'|jq.

2.3 常见的系统Annotation速查

Annotation来源用途
kubectl.kubernetes.io/last-applied-configurationkubectl三向合并,追踪上次提交的配置
deployment.kubernetes.io/revisionDeployment Controller部署版本号,回滚时使用
kubernetes.io/change-cause用户/CI记录变更原因(配合--record
kubernetes.io/config.hashkubelet配置哈希,配置变更时触发滚动更新
kubernetes.io/config.seenkubelet上次看到配置的时间戳
kubernetes.io/config.sourcekubelet配置来源(file/apiserver)
# 手动加变更原因(kubectl --record)apiVersion:apps/v1kind:Deploymentmetadata:name:nginxannotations:kubernetes.io/change-cause:"升级到1.25.3,修复CVE-2026-XXXX"

三、实战场景一:Ingress Nginx的注解配置——“一个注解一个功能”

Ingress Nginx Controller是通过Annotation驱动的经典案例——你想要什么功能,加个Annotation就行。这比修改配置文件方便多了。

【Ingress Nginx 通过 Annotation 开启各种功能】 ┌─────────────────────────────────────────────────────┐ │ Ingress 资源 │ │ │ │ annotations: │ │ # 基础功能 │ │ rewrite-target: / ← URL重写 │ │ ssl-redirect: "true" ← HTTP自动跳HTTPS │ │ │ │ # 安全 │ │ whitelist-source-range: ← IP白名单 │ │ "10.0.0.0/8" │ │ enable-cors: "true" ← 跨域 │ │ │ │ # 性能 │ │ proxy-body-size: "10m" ← 请求体大小限制 │ │ proxy-connect-timeout: "30"← 连接超时 │ │ │ │ # 高级 │ │ canary: "true" ← 灰度发布 │ │ canary-weight: "20" ← 20%流量 │ └─────────────────────────────────────────────────────┘
# Ingress Nginx 注解实战apiVersion:networking.k8s.io/v1kind:Ingressmetadata:name:myapp-ingressannotations:# URL 重写:/api/users → /usersnginx.ingress.kubernetes.io/rewrite-target:/$2# 请求体大小限制(防止恶意大文件上传)nginx.ingress.kubernetes.io/proxy-body-size:"20m"# 强制 HTTPSnginx.ingress.kubernetes.io/ssl-redirect:"true"# 连接超时nginx.ingress.kubernetes.io/proxy-connect-timeout:"30"nginx.ingress.kubernetes.io/proxy-read-timeout:"60"# 速率限制(每秒5个请求 + 突发10个)nginx.ingress.kubernetes.io/limit-rps:"5"nginx.ingress.kubernetes.io/limit-burst-multiplier:"2"# IP白名单nginx.ingress.kubernetes.io/whitelist-source-range:"10.0.0.0/8,172.16.0.0/12"# CORS 跨域nginx.ingress.kubernetes.io/enable-cors:"true"nginx.ingress.kubernetes.io/cors-allow-origin:"https://example.com"# 会话亲和性(同一用户始终路由到同一Pod)nginx.ingress.kubernetes.io/affinity:"cookie"nginx.ingress.kubernetes.io/session-cookie-name:"INGRESS-COOKIE"nginx.ingress.kubernetes.io/session-cookie-path:"/"spec:ingressClassName:nginxrules:-host:myapp.example.comhttp:paths:-path:/api(/|$)(.*)pathType:ImplementationSpecificbackend:service:name:api-serviceport:number:8080

要点:Ingress Nginx有超过100个Annotation可用——速率限制、认证、重写、缓存、跨域……几乎你能想到的HTTP网关功能,全有对应的Annotation。这就是Annotation驱动架构的魅力:不改代码、不改配置中心,贴个标签就完事。

灰度发布——又见Annotation

# Canary Ingress(灰度版)apiVersion:networking.k8s.io/v1kind:Ingressmetadata:name:myapp-canaryannotations:nginx.ingress.kubernetes.io/canary:"true"nginx.ingress.kubernetes.io/canary-weight:"20"# 20%流量# 或者按Header匹配# nginx.ingress.kubernetes.io/canary-by-header: "x-canary"# nginx.ingress.kubernetes.io/canary-by-header-value: "true"spec:rules:-host:myapp.example.comhttp:paths:-path:/pathType:Prefixbackend:service:name:myapp-canary-serviceport:number:8080

四、实战场景二:Prometheus自动发现——贴个便利贴就完成监控接入

Prometheus Operator通过Annotation实现"零配置"监控接入——你只需要在Service或Pod上贴几个Annotation,Prometheus就自动开始抓取指标。

【Prometheus 自动发现——Annotation驱动】 不加 Annotation: 加了 Annotation: ┌──────────────┐ ┌──────────────────────────────┐ │ Service │ │ Service │ │ │ │ │ │ name: myapp │ │ annotations: │ │ port: 8080 │ │ prometheus.io/scrape: │ │ │ │ "true" ← 抓! │ │ │ │ prometheus.io/port: │ │ │ │ "9113" ← 端口 │ │ │ │ prometheus.io/path: │ │ │ │ "/metrics" ← 路径 │ └──────────────┘ └──────────────┬───────────────┘ │ │ ▼ ▼ Prometheus: "这啥? Prometheus: "扫到标签了! 我不认识它,跳过" 开始抓 http://10.96.x.x:9113/metrics"
# Pod 上贴 Prometheus 注解(自动发现模式)apiVersion:v1kind:Podmetadata:name:myapp-with-metricsannotations:prometheus.io/scrape:"true"# 告诉Prometheus来抓指标prometheus.io/port:"9113"# 指标暴露的端口prometheus.io/path:"/metrics"# 指标路径(默认就是/metrics,可选)prometheus.io/scheme:"http"# http或https(可选,默认http)spec:containers:-name:myappimage:myapp:latestports:-containerPort:8080-name:metrics-exporterimage:prom/statsd-exporterports:-containerPort:9113# 就是这个端口暴露Prometheus指标
# Service 上贴 Prometheus 注解(更常见的做法)apiVersion:v1kind:Servicemetadata:name:myapp-serviceannotations:prometheus.io/scrape:"true"prometheus.io/port:"9113"prometheus.io/path:"/metrics"# 额外的Prometheus配置prometheus.io/scrape_interval:"30s"# 抓取间隔prometheus.io/scrape_timeout:"10s"# 抓取超时spec:selector:app:myappports:-name:httpport:8080targetPort:8080-name:metricsport:9113targetPort:9113
# Prometheus Operator 的 ServiceMonitor 配置# (Prometheus Operator 会基于Service标签自动生成这个)apiVersion:monitoring.coreos.com/v1kind:ServiceMonitormetadata:name:myapp-monitorspec:selector:matchLabels:app:myappendpoints:-port:metricsinterval:30spath:/metrics

要点:Prometheus自动发现的核心在于——你不改Prometheus配置文件,不给运维发工单,只要在Pod/Service上贴对Annotation,Prometheus就自动发现并开始监控。这就是K8s声明式哲学在监控领域的优雅实践。


五、Annotation的实用技巧

5.1 常用操作命令

# 给资源加Annotationkubectl annotate pod my-nginx created-by=zhangsan kubectl annotate deployment nginx kubernetes.io/change-cause="v1.25 to v1.26"# 覆盖已有Annotationkubectl annotate pod my-nginx created-by=lisi--overwrite# 删除Annotation(加个减号后缀)kubectl annotate pod my-nginx created-by-# 查看某个资源的Annotationkubectl describe pod my-nginx|grepAnnotations-A10# 用 jsonpath 提取特定Annotationkubectl get pod my-nginx-ojsonpath='{.metadata.annotations.created-by}'# 按Annotation筛选(不能直接用 -l,因为-l只查Label)# 得用 jsonpath 或者 jqkubectl get pods-ojson|jq'.items[] | select(.metadata.annotations."created-by"=="zhangsan") | .metadata.name'

5.2 自定义Annotation命名规范

# 建议:自定义Annotation加上你的组织前缀metadata:annotations:# 系统自带(前缀是 kubernetes.io/)kubernetes.io/change-cause:"upgrade to v1.26"# 组织自定义(用你的域名做前缀)example.com/team-owner:"platform"example.com/cost-center:"cc-12345"example.com/expires-at:"2026-12-31"example.com/security-tier:"pci"# 工具相关prometheus.io/scrape:"true"nginx.ingress.kubernetes.io/rewrite-target:/# 不要用无前缀的Annotation——容易跟别人的冲突!# ❌ 不要这样:description: "my important pod"# ✅ 用前缀:example.com/description: "my important pod"

要点:自定义Annotation强烈建议加上组织域名前缀example.com/),避免跟其他工具的Annotation冲突。无前缀的Annotation就像全局变量——你永远不知道谁会跟你撞名。


六、Label和Annotation的协作分工——一个完整示例

最后看一个完整的Deployment配置,展示Label和Annotation如何各司其职:

apiVersion:apps/v1kind:Deploymentmetadata:name:payment-servicenamespace:team-backend# Label —— 被Selector使用,用于管理分组labels:app:paymentversion:v2.3.1tier:backendteam:payments-team# Annotation —— 存元数据,不参与选择annotations:# 构建信息example.com/git-commit:"a1b2c3d4e5f6"example.com/git-branch:"release/v2.3"example.com/build-time:"2026-07-28T14:30:00Z"example.com/ci-pipeline:"https://jenkins.example.com/job/payment/123"# 运维信息example.com/team-owner:"payments-team"example.com/oncall:"ext-8888"example.com/deployed-by:"zhangsan"# Prometheus 监控prometheus.io/scrape:"true"prometheus.io/port:"9113"prometheus.io/path:"/metrics"# 变更追踪kubernetes.io/change-cause:"升级到v2.3.1,修复订单超时问题 #BUG-5678"spec:replicas:3selector:matchLabels:# ← 用Label做选择app:paymenttemplate:metadata:labels:# ← Pod的Labelapp:paymentversion:v2.3.1spec:containers:-name:paymentimage:payment-service:v2.3.1ports:-containerPort:8080
# Label的意义——快速筛选kubectl get pods-lapp=payment,tier=backend kubectl get pods-lapp=payment,version=v2.3.1# Annotation的意义——查看详细信息kubectl describe deployment payment-service|grepAnnotations-A20# 快速定位问题版本kubectl get deploy payment-service-ojsonpath='{.metadata.annotations.kubernetes\.io/change-cause}'

本篇小结

Annotation看着"不务正业"(不影响调度、不影响路由),但它实际上是K8s生态的"胶水语言":

  1. Label vs Annotation:Label用于选择和过滤(K8s在决策时"看"它),Annotation用于存附加信息(人和工具"看"它)
  2. Ingress Nginx全靠Annotation驱动:上百个Annotation控制路由、限流、认证、灰度等能力,不改Nginx配置也能灵活控制
  3. Prometheus自动发现:贴几个Annotation就完成监控接入,零配置、零工单,是声明式管理的典范
  4. 命名规范:自定义Annotation建议加组织域名前缀,避免冲突

从下一篇开始,咱们进入K8s工作负载管理的大门——Deployment、StatefulSet、DaemonSet三兄弟,帮你管好Pod的"生老病死"。首先登场的是一哥Deployment。


上一篇【第11篇】Namespace——给你的K8s集群划地盘
下一篇【第13篇】Deployment——无状态应用的"自动档"


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询