第一章:孔令飞与云原生Go开发方法论
孔令飞作为云原生领域资深实践者,其Go开发方法论强调“可观察性先行、声明式设计、渐进式演进”三大原则。该方法论并非抽象理论,而是深度植根于Kubernetes Operator、eBPF可观测工具链及高并发微服务场景的真实工程反馈。
核心开发范式
- 接口契约驱动:在项目初期即定义清晰的
interface{}边界,例如type ResourceManager interface { Apply(*v1alpha1.Config) error; Status() v1alpha1.Status },强制实现层解耦; - 错误处理标准化:统一使用
errors.Join()聚合多错误,并通过xerrors.WithStack()保留调用栈,避免if err != nil { return err }的简单透传; - 配置即代码(CoC):将环境差异封装为结构体标签,如
type Config struct { Port intenv:”PORT” default:”8080″},配合github.com/mitchellh/mapstructure动态绑定。
可观测性嵌入实践
在HTTP服务启动时自动注入OpenTelemetry SDK,关键代码片段如下:
// 初始化全局TracerProvider(仅执行一次)
func initTracer() {
exporter, _ := otlptracegrpc.New(context.Background(),
otlptracegrpc.WithEndpoint("otel-collector:4317"),
otlptracegrpc.WithInsecure(),
)
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(resource.MustNewSchemaVersion(resource.SchemaURL)),
)
otel.SetTracerProvider(tp)
}
// 在HTTP handler中创建span
func handleRequest(w http.ResponseWriter, r *http.Request) {
ctx, span := otel.Tracer("api").Start(r.Context(), "handle-request")
defer span.End()
// 业务逻辑...
}
工程效能保障机制
| 实践项 | 工具链 | 触发时机 |
|---|---|---|
| 接口兼容性检查 | gofumpt -l + go vet |
Git pre-commit |
| CRD变更验证 | controller-gen + kubebuilder |
CI阶段生成YAML并diff |
| 性能基线监控 | pprof + Prometheus Exporter |
每次发布前压测 |
该方法论要求开发者在main.go中显式声明依赖注入容器,禁用全局变量隐式状态,所有组件初始化必须通过func NewXxx(...Option) (*Xxx, error)构造函数完成。
第二章:Go语言高可用系统核心设计原则
2.1 并发模型与goroutine生命周期管理实践
Go 的并发模型以 goroutine + channel 为核心,轻量级协程由 runtime 自动调度,但生命周期需开发者显式管控。
goroutine 启动与隐式泄漏风险
func loadData() {
go func() { // 无超时、无取消、无错误处理 → 潜在泄漏
time.Sleep(10 * time.Second)
fmt.Println("loaded")
}()
}
该匿名 goroutine 启动后脱离控制流,若外部无上下文约束,将长期驻留直至程序退出。
基于 context 的生命周期收敛
func loadDataWithContext(ctx context.Context) {
go func() {
select {
case <-time.After(10 * time.Second):
fmt.Println("loaded")
case <-ctx.Done(): // 可被 cancel/timeout 主动终止
return
}
}()
}
ctx.Done() 提供统一退出信号,配合 context.WithTimeout 或 WithCancel 实现可预测的生命周期收口。
关键生命周期状态对照表
| 状态 | 触发条件 | 是否可恢复 |
|---|---|---|
| 启动(New) | go f() 执行 |
否 |
| 运行(Running) | 被 M 抢占并执行 | 是(暂停) |
| 阻塞(Blocked) | 等待 channel、锁、系统调用 | 是(唤醒) |
| 终止(Dead) | 函数返回或 panic 且无 recover | 否 |
graph TD
A[New] --> B[Running]
B --> C{I/O or Channel?}
C -->|Yes| D[Blocked]
C -->|No| E[Dead]
D -->|Ready| B
D -->|Cancel| E
2.2 错误处理与可观测性嵌入式设计
在资源受限的嵌入式系统中,错误处理不能依赖通用框架,而需轻量、确定性、可追溯。
错误分类与响应策略
- 瞬态错误(如SPI超时):重试 + 指数退避
- 持久错误(如Flash校验失败):降级运行 + 上报
- 致命错误(如堆栈溢出):安全停机 + 环形日志快照
嵌入式可观测性三要素
| 维度 | 实现方式 | 资源开销示例 |
|---|---|---|
| 日志 | 二进制编码 + UART环形缓冲 | |
| 指标 | 固定周期采样计数器 | 32-bit寄存器 |
| 追踪 | 事件ID + 时间戳压缩编码 | 8字节/事件 |
// 错误上报轻量协议(含上下文压缩)
typedef struct __attribute__((packed)) {
uint16_t err_code; // 预定义枚举,非字符串
uint8_t module_id; // 模块索引(0~31)
uint8_t severity; // 0=debug, 3=fatal
uint32_t timestamp; // 低16位为tick差分编码
} err_report_t;
该结构体通过 __attribute__((packed)) 消除填充字节;err_code 使用紧凑枚举替代字符串节省ROM;timestamp 采用差分编码(相对于上次上报),避免32位绝对时间带来的带宽压力。
graph TD
A[传感器中断] --> B{校验通过?}
B -->|否| C[记录err_code=0x0A]
B -->|是| D[更新指标计数器]
C --> E[写入环形日志缓冲区]
E --> F[UART异步发送压缩包]
2.3 接口抽象与依赖注入在K8s控制器中的落地
Kubernetes控制器通过接口抽象解耦核心逻辑与具体实现,client.Client 和 cache.Cache 接口统一了数据访问方式,使测试与替换(如 mock client)成为可能。
依赖注入的典型模式
控制器构造函数接收预配置的依赖项,而非自行创建:
type Reconciler struct {
client client.Client // 抽象接口,非具体 rest.Client
scheme *runtime.Scheme
logger logr.Logger
}
→ client.Client 封装了 CRUD + List/Watch,屏蔽底层 HTTP 细节;scheme 负责对象序列化;logger 支持结构化日志注入。
核心依赖关系
| 依赖项 | 作用 | 可替换性 |
|---|---|---|
client.Client |
集群资源操作统一入口 | ✅ 高(可注入 fake.NewClientBuilder) |
cache.Cache |
本地索引缓存层 | ✅ 中(需兼容 Indexer 接口) |
eventRecorder |
事件上报 | ✅ 高 |
graph TD
A[Reconciler] --> B[client.Client]
A --> C[cache.Cache]
A --> D[eventRecorder]
B --> E[REST client / Fake client]
C --> F[Informers + SharedIndexInformer]
2.4 零信任安全模型下的Go服务认证与授权实现
零信任要求“永不信任,始终验证”,在Go微服务中需将认证(Who are you?)与授权(What may you do?)深度耦合于每次请求。
JWT解析与上下文注入
func AuthMiddleware(jwtKey []byte) gin.HandlerFunc {
return func(c *gin.Context) {
tokenStr := c.GetHeader("Authorization")
if tokenStr == "" {
c.AbortWithStatusJSON(401, gin.H{"error": "missing token"})
return
}
token, err := jwt.Parse(tokenStr, func(t *jwt.Token) (interface{}, error) {
return jwtKey, nil // 使用对称密钥验证签名
})
if err != nil || !token.Valid {
c.AbortWithStatusJSON(401, gin.H{"error": "invalid token"})
return
}
c.Set("claims", token.Claims) // 注入至上下文供后续中间件使用
c.Next()
}
}
该中间件解析并校验JWT签名,仅当令牌有效时才放行;c.Set("claims")为下游授权逻辑提供结构化身份凭证,避免重复解析。
基于策略的RBAC授权
| 资源 | 动作 | 角色 |
|---|---|---|
/api/v1/users |
GET | viewer, admin |
/api/v1/users |
POST | admin |
/api/v1/config |
PUT | admin |
请求决策流程
graph TD
A[HTTP Request] --> B{Has valid JWT?}
B -->|No| C[401 Unauthorized]
B -->|Yes| D[Extract Claims]
D --> E{Policy Engine Match?}
E -->|No| F[403 Forbidden]
E -->|Yes| G[Forward to Handler]
2.5 内存安全与GC调优在长周期微服务中的实证分析
长周期微服务(运行>30天)面临对象泄漏累积与G1 GC退化风险。实证表明:未清理的ThreadLocal<ByteBuffer>引用导致老年代每72小时增长1.2GB。
关键泄漏模式识别
// ❌ 危险:ThreadLocal未remove,线程复用下持续持有堆外内存引用
private static final ThreadLocal<ByteBuffer> BUFFER_HOLDER =
ThreadLocal.withInitial(() -> ByteBuffer.allocateDirect(1024 * 1024));
// ✅ 修复:在请求结束钩子中显式清理
filterChain.doFilter(request, response);
BUFFER_HOLDER.remove(); // 防止弱引用被GC绕过
ThreadLocal.remove()是唯一可靠清除方式;仅依赖WeakReference无法阻止DirectBuffer元数据泄漏。
G1调优核心参数对照
| 参数 | 推荐值 | 作用 |
|---|---|---|
-XX:MaxGCPauseMillis |
200 | 控制停顿上限,避免长周期服务抖动 |
-XX:G1HeapRegionSize |
4M | 匹配大对象分配频率,减少Humongous区碎片 |
GC行为演化路径
graph TD
A[启动期:年轻代GC频繁] --> B[稳定期:混合GC主导]
B --> C[老化期:并发标记延迟上升]
C --> D[退化:Full GC触发→服务卡顿]
第三章:Kubernetes原生Go开发深度实践
3.1 Operator模式开发:从CRD定义到Reconcile循环优化
Operator的核心在于将运维逻辑编码为 Kubernetes 原生控制循环。首先通过 CRD 定义领域资源:
# crd.yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: databases.example.com
spec:
group: example.com
versions:
- name: v1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
replicas: {type: integer, minimum: 1, maximum: 5}
names:
plural: databases
singular: database
kind: Database
listKind: DatabaseList
该 CRD 声明了 Database 资源的结构约束,其中 replicas 字段被严格限制在 1–5 之间,确保语义合法性。
Reconcile 循环优化策略
- ✅ 使用缓存索引加速关联资源查找(如按
ownerReference索引) - ✅ 实现条件性 Requeue:仅当
status.observedGeneration != metadata.generation时跳过同步 - ❌ 避免在 Reconcile 中直接调用阻塞式 HTTP 客户端
| 优化手段 | QPS 提升 | 内存开销 |
|---|---|---|
| Informer 缓存 | +320% | +12% |
| 指数退避重试 | +85% | +3% |
| 并发队列分片 | +210% | +9% |
func (r *DatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
var db examplev1.Database
if err := r.Get(ctx, req.NamespacedName, &db); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err) // 忽略删除事件错误
}
// 核心逻辑:比对 spec 与实际状态,生成最小差异操作
return ctrl.Result{RequeueAfter: time.Second * 30}, nil
}
此 Reconcile 函数采用幂等设计,返回 RequeueAfter 实现节流,避免高频轮询;client.IgnoreNotFound 确保资源已删时不报错中断循环。
graph TD
A[Watch Event] --> B{CR in Cluster?}
B -->|Yes| C[Fetch from Cache]
B -->|No| D[Skip]
C --> E[Run Reconcile]
E --> F[Update Status]
F --> G[Conditional Requeue]
3.2 Client-go高级用法:动态资源操作与缓存一致性保障
动态资源操作:DynamicClient 实战
使用 dynamic.Interface 可泛化操作任意 CRD 或内置资源,无需预生成类型定义:
dynClient := dynamic.NewForConfigOrDie(config)
unstr, err := dynClient.Resource(schema.GroupVersionResource{
Group: "apps",
Version: "v1",
Resource: "deployments",
}).Namespace("default").Get(context.TODO(), "nginx", metav1.GetOptions{})
// 参数说明:GroupVersionResource 定义资源坐标;GetOptions 控制服务端行为(如 resourceVersion)
// 逻辑分析:DynamicClient 底层通过 RESTClient 发起 HTTP 请求,返回 *unstructured.Unstructured,规避类型强绑定
缓存一致性保障机制
Informer 通过 Reflector + DeltaFIFO + Indexer 构建事件驱动缓存:
| 组件 | 职责 |
|---|---|
| Reflector | 监听 API Server 变更流 |
| DeltaFIFO | 存储增删改事件队列 |
| Indexer | 提供内存索引加速查询 |
数据同步机制
graph TD
A[API Server] -->|Watch Stream| B(Reflector)
B --> C[DeltaFIFO]
C --> D[Controller Loop]
D --> E[Indexer Cache]
E --> F[SharedInformer Handler]
3.3 K8s API Server扩展机制与Webhook定制开发
Kubernetes API Server 通过 Aggregated API 和 Dynamic Admission Control 提供两类核心扩展能力:前者用于注册自定义资源端点(如 metrics.k8s.io),后者通过 ValidatingAdmissionWebhook 与 MutatingAdmissionWebhook 实现策略注入。
Webhook 请求生命周期
# admissionregistration.k8s.io/v1 MutatingWebhookConfiguration 示例
webhooks:
- name: tenant-mutator.example.com
rules:
- operations: ["CREATE"]
apiGroups: ["*"]
apiVersions: ["*"]
resources: ["pods"]
clientConfig:
service:
namespace: webhook-system
name: tenant-mutator-svc
▶️ 此配置声明:所有 Pod 创建请求将同步转发至 tenant-mutator-svc。clientConfig.service 指定集群内服务地址,rules 定义匹配粒度;API Server 会等待其返回 AdmissionReview 响应并应用变更。
扩展能力对比
| 机制 | 时序 | 可修改对象 | 典型用途 |
|---|---|---|---|
| Mutating Webhook | 请求入栈后、持久化前 | ✅(字段注入、标签添加) | 自动注入 sidecar、设置默认容忍度 |
| Validating Webhook | Mutating 后、写入 etcd 前 | ❌(仅校验) | 阻断违反命名规范或配额的资源 |
graph TD
A[API Request] --> B{Aggregated API?}
B -->|Yes| C[Route to APIService]
B -->|No| D[Admission Phase]
D --> E[Mutating Webhooks]
E --> F[Validating Webhooks]
F --> G[Storage]
第四章:云原生Go系统高可用工程体系构建
4.1 多集群联邦调度框架与Go控制平面实现
多集群联邦调度需统一纳管异构K8s集群,核心在于解耦调度决策与执行,并保障跨集群资源视图一致性。
架构设计原则
- 控制平面无状态化,便于水平扩展
- 各集群Agent仅上报摘要指标(CPU/内存/自定义CRD状态)
- 调度器基于声明式策略(如
topology-aware、cost-optimized)生成Placement决策
数据同步机制
采用Delta Watch机制降低带宽消耗:
// DeltaStore维护增量变更队列,避免全量List开销
type DeltaStore struct {
queue workqueue.RateLimitingInterface // 带限速的变更队列
indexer cache.Indexer // 本地索引缓存
}
// 每次Sync仅处理diff,非全量Reconcile
该结构使千节点级联邦下同步延迟稳定在
调度策略路由表
| 策略名 | 触发条件 | 目标集群筛选逻辑 |
|---|---|---|
zone-preferred |
label: topology.kubernetes.io/zone=us-east-1a | 优先匹配zone标签一致集群 |
cost-aware |
annotation: cluster-cost-tier=low | 排序按预设成本权重 |
graph TD
A[联邦API Server] --> B[Policy Engine]
B --> C{策略匹配}
C -->|zone-preferred| D[Topology Resolver]
C -->|cost-aware| E[Price Estimator]
D & E --> F[Placement Decision]
4.2 自愈型服务网格Sidecar的Go轻量级替代方案
传统Envoy Sidecar内存占用高、启动慢,难以适配边缘与Serverless场景。轻量级替代方案聚焦于最小化依赖与事件驱动自愈。
核心设计原则
- 零CGO依赖,纯Go实现
- 基于
net/http/httputil构建反向代理内核 - 利用
k8s.io/client-go监听Pod/Endpoint变更事件
自愈机制流程
graph TD
A[Watch API Server] --> B{Pod Ready?}
B -- 否 --> C[触发健康检查]
C --> D[调用 /healthz 接口]
D -- 失败 --> E[自动重启代理实例]
D -- 成功 --> F[更新路由表]
路由热更新示例
// 动态加载路由配置,支持原子替换
func (p *Proxy) UpdateRoutes(cfg *RouteConfig) error {
p.mu.Lock()
defer p.mu.Unlock()
p.routes = cfg.Rules // 非阻塞赋值,零停机切换
return nil
}
cfg.Rules为[]*RouteRule结构,含Host, PathPrefix, Upstream字段;锁保护仅作用于指针交换,避免路由请求阻塞。
| 方案 | 内存占用 | 启动耗时 | 自愈延迟 |
|---|---|---|---|
| Envoy | ~120MB | ~800ms | ~3s |
| Go-Proxy | ~12MB | ~12ms | ~300ms |
4.3 基于eBPF+Go的内核级流量治理与故障注入实践
现代云原生系统需在不重启、不侵入业务的前提下实现细粒度网络控制。eBPF 提供安全、可编程的内核钩子,而 Go 以其高生产力和 cgo 集成能力成为理想的用户态协作者。
核心架构分层
- eBPF 层:在
TC(Traffic Control)或XDP端挂载程序,拦截并标记数据包 - Go 控制面:通过
libbpf-go加载 BPF 对象,动态更新 map 中的策略与故障规则 - 策略驱动:基于五元组 + 自定义标签(如
service=auth,env=staging)匹配流量
故障注入示例(BPF 代码片段)
// bpf_program.c:在 tc clsact egress 处注入延迟
SEC("classifier")
int inject_fault(struct __sk_buff *skb) {
__u32 key = get_flow_key(skb); // 提取 src/dst ip/port + proto
struct fault_rule *rule = bpf_map_lookup_elem(&fault_rules, &key);
if (rule && rule->enabled && bpf_ktime_get_ns() % 100 == 0) {
bpf_skb_event_output(skb, &events, BPF_F_CURRENT_CPU, &rule, sizeof(*rule));
return TC_ACT_SHOT; // 主动丢包模拟故障
}
return TC_ACT_OK;
}
逻辑分析:该程序在 egress 路径对匹配
fault_rulesmap 的流执行概率性丢包(% 100实现 ~1% 注入率)。bpf_skb_event_output将事件推至 perf ring buffer,供 Go 程序实时消费与审计。TC_ACT_SHOT表示终止处理并丢弃包,实现零延迟故障注入。
支持的故障类型对比
| 类型 | 延迟范围 | 可控维度 | 是否需重编译 |
|---|---|---|---|
| 随机丢包 | — | 流量标签、端口 | 否 |
| 固定延迟 | 10ms–5s | 源服务名、路径 | 否 |
| TCP RST 注入 | 即时 | 连接状态、方向 | 是(需 map 更新) |
graph TD
A[Go 应用启动] --> B[加载 eBPF 字节码]
B --> C[初始化 fault_rules map]
C --> D[监听 Prometheus /inject API]
D --> E[写入故障规则到 BPF map]
E --> F[eBPF 程序实时生效]
4.4 混沌工程平台Go SDK设计与K8s原生混沌实验编排
为实现Kubernetes原生混沌实验的声明式编排与可编程控制,平台提供轻量、类型安全的Go SDK,封装CRD操作、实验生命周期管理及事件回调机制。
核心能力抽象
- 支持
ChaosExperiment资源的创建、状态轮询与终止 - 内置重试策略与上下文超时控制
- 提供
OnStart/OnComplete钩子函数注册接口
SDK初始化示例
// 初始化客户端,自动发现集群内ChaosOperator服务
client, err := chaos.NewClient(chaos.WithKubeConfig("/etc/kube/config"))
if err != nil {
log.Fatal("failed to init chaos client: ", err)
}
WithKubeConfig指定K8s认证配置路径;若运行于集群内,SDK默认使用ServiceAccount令牌自动加载。
实验编排流程(Mermaid)
graph TD
A[定义ChaosSpec] --> B[调用CreateExperiment]
B --> C{CRD已注册?}
C -->|是| D[Operator监听并调度]
C -->|否| E[返回ValidationError]
D --> F[Pod注入故障/网络延迟等]
常见实验类型支持表
| 类型 | 动作粒度 | 超时默认值 | 是否支持回滚 |
|---|---|---|---|
| PodKill | 单Pod | 30s | 是 |
| NetworkDelay | Service级别 | 60s | 是 |
| CPUStress | Node级别 | 120s | 否 |
第五章:走向生产级云原生Go生态
高可用服务网格集成实践
在某金融级支付平台升级中,团队将自研Go微服务(基于Gin+gRPC)接入Istio 1.21,通过Envoy Sidecar实现零代码改造的mTLS双向认证与细粒度流量镜像。关键配置片段如下:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: payment-service
spec:
hosts:
- "payment.internal"
http:
- route:
- destination:
host: payment-service.default.svc.cluster.local
subset: v2
weight: 90
- destination:
host: payment-service-canary.default.svc.cluster.local
subset: v1
weight: 10
生产级可观测性堆栈构建
| 采用OpenTelemetry Go SDK统一采集指标、日志与链路追踪数据,经OTLP exporter直连Prometheus+Loki+Tempo三件套。定制化仪表盘监控核心SLI: | 指标类型 | 采集方式 | 告警阈值 | 数据源 |
|---|---|---|---|---|
| gRPC成功率 | otelgrpc.Interceptor | Prometheus | ||
| 日志错误率 | Loki日志解析 | >0.1%/min | Loki | |
| P99延迟 | Jaeger span duration | >300ms | Tempo |
安全合规加固方案
针对GDPR与等保2.0要求,在Kubernetes集群中部署以下策略:
- 使用Kyverno策略引擎强制所有Go容器镜像签名验证(cosign verify)
- 通过OPA Gatekeeper限制Pod必须启用seccompProfile: runtime/default
- Go应用内嵌入
go.opentelemetry.io/otel/sdk/trace并启用采样率动态调整(基于请求头X-Trace-Mode)
CI/CD流水线深度优化
GitHub Actions流水线集成Snyk扫描与Trivy镜像扫描,关键阶段耗时对比:
flowchart LR
A[Go代码编译] --> B[静态分析-gosec]
B --> C[单元测试覆盖率≥85%]
C --> D[多架构镜像构建-arm64/amd64]
D --> E[安全扫描-阻断CVE≥7.0]
E --> F[金丝雀发布-自动回滚]
混沌工程常态化实施
在预发环境每日执行Chaos Mesh故障注入:
- 网络延迟:对etcd客户端注入200ms±50ms抖动
- 内存泄漏:使用pumba工具对Go进程施加15%内存压力
- 模拟GC停顿:通过
GODEBUG=gctrace=1日志分析STW时间分布
多集群联邦治理
基于Karmada 1.7实现跨AZ集群调度,Go服务通过karmada.io/v1alpha1 API声明:
// service-placement.go
placement := &workv1alpha2.ClusterPropagationPolicy{
Spec: workv1alpha2.PropagationPolicySpec{
ResourceSelectors: []workv1alpha2.ResourceSelector{{
ResourceType: "Deployment",
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"app": "payment-go"},
},
}},
Placement: workv1alpha2.Placement{
ClusterAffinity: []string{"az-shanghai", "az-beijing"},
SpreadConstraints: []workv1alpha2.SpreadConstraint{{
MaxSkew: 1,
TopologyKey: "topology.kubernetes.io/zone",
}},
},
},
}
实时配置热更新机制
放弃传统ConfigMap挂载,采用Nacos Go SDK实现配置变更事件驱动:
- 监听
/payment/rate-limit路径变更 - 触发goroutine重建限流器(基于golang.org/x/time/rate)
- 全链路生效延迟控制在200ms内(实测P99=187ms)
资源效率深度调优
通过pprof火焰图定位到JSON序列化瓶颈,将默认encoding/json替换为github.com/json-iterator/go后:
- 内存分配减少63%(从12.4MB→4.6MB per req)
- GC pause时间下降至1.2ms(原8.7ms)
- CPU使用率降低22%(AWS m5.2xlarge实例)
服务韧性设计模式
在订单服务中实现熔断-降级-重试三级防护:
- 使用
sony/gobreaker配置熔断器(连续5次超时触发) - 降级逻辑返回缓存中的最近成功订单状态(Redis TTL=30s)
- 重试策略采用指数退避(base=100ms, max=1.6s, jitter=0.2)
多租户隔离架构
基于Open Policy Agent定义租户策略:
package kubernetes.admission
import data.kubernetes.namespaces
default allow = false
allow {
input.request.kind.kind == "Pod"
input.request.object.spec.containers[_].image == "payment-go:v3.2"
namespaces[input.request.namespace].labels["tenant-id"] == input.request.object.metadata.labels["tenant-id"]
} 