基于 ArgoCD 优雅落地 K8s Gateway API 与 Kong 控制器(KIC)

]

在现代云原生微服务架构中,Kubernetes Gateway API 正在逐步取代传统的 Ingress 成为新一代的标准流量入口。如何通过 GitOps(ArgoCD)优雅、解耦地安装和管理 Gateway API 的底层资源、Kong 控制器以及网关基础设施?本文将以真实的工程实践为例,详细拆解整个配置过程。

一、 架构设计思路:控制面与数据面配置解耦

在我们的配置仓库中,采用了纯正的 App of Apps 模式,并将配置文件严格划分为两个不同的目录,实现了调度层与基建实体的解耦:

  1. argocd-apps/(调度指挥部) :存放所有的 kind: Application 文件。这些文件相当于"快递单",它们负责告诉 ArgoCD 去哪里拉取配置(比如远端 Helm 仓库或其他 Git 目录),并空投到哪个目标集群。
  2. infrastructure/kong-gateway/(基建实体) :存放目标集群真正需要落地的纯 K8s 资源清单(比如 GatewayClassGateway)。

1.1 全景架构图

#mermaid-svg-zYIHEDIz9ZQPKZSA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zYIHEDIz9ZQPKZSA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zYIHEDIz9ZQPKZSA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zYIHEDIz9ZQPKZSA .error-icon{fill:#552222;}#mermaid-svg-zYIHEDIz9ZQPKZSA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zYIHEDIz9ZQPKZSA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zYIHEDIz9ZQPKZSA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zYIHEDIz9ZQPKZSA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zYIHEDIz9ZQPKZSA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zYIHEDIz9ZQPKZSA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zYIHEDIz9ZQPKZSA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zYIHEDIz9ZQPKZSA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zYIHEDIz9ZQPKZSA .marker.cross{stroke:#333333;}#mermaid-svg-zYIHEDIz9ZQPKZSA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zYIHEDIz9ZQPKZSA p{margin:0;}#mermaid-svg-zYIHEDIz9ZQPKZSA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zYIHEDIz9ZQPKZSA .cluster-label text{fill:#333;}#mermaid-svg-zYIHEDIz9ZQPKZSA .cluster-label span{color:#333;}#mermaid-svg-zYIHEDIz9ZQPKZSA .cluster-label span p{background-color:transparent;}#mermaid-svg-zYIHEDIz9ZQPKZSA .label text,#mermaid-svg-zYIHEDIz9ZQPKZSA span{fill:#333;color:#333;}#mermaid-svg-zYIHEDIz9ZQPKZSA .node rect,#mermaid-svg-zYIHEDIz9ZQPKZSA .node circle,#mermaid-svg-zYIHEDIz9ZQPKZSA .node ellipse,#mermaid-svg-zYIHEDIz9ZQPKZSA .node polygon,#mermaid-svg-zYIHEDIz9ZQPKZSA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zYIHEDIz9ZQPKZSA .rough-node .label text,#mermaid-svg-zYIHEDIz9ZQPKZSA .node .label text,#mermaid-svg-zYIHEDIz9ZQPKZSA .image-shape .label,#mermaid-svg-zYIHEDIz9ZQPKZSA .icon-shape .label{text-anchor:middle;}#mermaid-svg-zYIHEDIz9ZQPKZSA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zYIHEDIz9ZQPKZSA .rough-node .label,#mermaid-svg-zYIHEDIz9ZQPKZSA .node .label,#mermaid-svg-zYIHEDIz9ZQPKZSA .image-shape .label,#mermaid-svg-zYIHEDIz9ZQPKZSA .icon-shape .label{text-align:center;}#mermaid-svg-zYIHEDIz9ZQPKZSA .node.clickable{cursor:pointer;}#mermaid-svg-zYIHEDIz9ZQPKZSA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zYIHEDIz9ZQPKZSA .arrowheadPath{fill:#333333;}#mermaid-svg-zYIHEDIz9ZQPKZSA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zYIHEDIz9ZQPKZSA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zYIHEDIz9ZQPKZSA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zYIHEDIz9ZQPKZSA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zYIHEDIz9ZQPKZSA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zYIHEDIz9ZQPKZSA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zYIHEDIz9ZQPKZSA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zYIHEDIz9ZQPKZSA .cluster text{fill:#333;}#mermaid-svg-zYIHEDIz9ZQPKZSA .cluster span{color:#333;}#mermaid-svg-zYIHEDIz9ZQPKZSA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zYIHEDIz9ZQPKZSA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zYIHEDIz9ZQPKZSA rect.text{fill:none;stroke-width:0;}#mermaid-svg-zYIHEDIz9ZQPKZSA .icon-shape,#mermaid-svg-zYIHEDIz9ZQPKZSA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zYIHEDIz9ZQPKZSA .icon-shape p,#mermaid-svg-zYIHEDIz9ZQPKZSA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zYIHEDIz9ZQPKZSA .icon-shape .label rect,#mermaid-svg-zYIHEDIz9ZQPKZSA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zYIHEDIz9ZQPKZSA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zYIHEDIz9ZQPKZSA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zYIHEDIz9ZQPKZSA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 数据面: 腾讯云集群
控制面: 阿里云集群
Git 仓库 (my-argocd-manifests)
读取并同步
读取并同步
Git 同步
派送: Helm 安装
派送: 投递 YAML
落地为
落地为
认领大门
关联类别
argocd-apps/

(ArgoCD 快递单)
infrastructure/kong-gateway/

(K8s 基建实体)
ArgoCD 控制器
kong-controller-app
kong-infra-app
Kong 控制器程序

(konghq.com/kic-gateway-controller)
GatewayClass

(name: kong)
Gateway

(name: kong-main-gateway)

二、 核心部署流程解析

部署整个网关体系存在严格的先后依赖关系:必须先有 CRD(字典),才能启动控制器(解析程序),最后才能创建网关实体。我们通过 ArgoCD 的 Sync Waves(同步波次) 完美解决了这个问题。

步骤 1:安装 Gateway API CRD (Wave 1)

首先,我们需要在集群中注册 Gateway API 的官方 CRD(如 GatewayClass, Gateway, HTTPRoute 等)。

创建 argocd-apps/gateway-api-crds-app.yaml

yaml 复制代码
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: gateway-api-crds
  namespace: argocd
  annotations:
    argocd.argoproj.io/sync-wave: "1" # 🎯 波次 1:最底层的基础设施字典
spec:
  project: default
  source:
    repoURL: 'https://github.com/kubernetes-sigs/gateway-api.git'
    targetRevision: v1.1.0
    path: config/crd/standard
  destination:
    name: 'tencent-dp1-cluster'
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - ServerSideApply=true # CRD 往往很大,必须使用 ServerSideApply 避免报错

步骤 2:安装 Kong Ingress Controller (KIC) (Wave 2)

CRD 就绪后,接下来安装 Kong 的控制器程序(KIC)。我们直接引用 Kong 官方的 Helm Chart。

创建 argocd-apps/kong-controller-app.yaml

yaml 复制代码
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: kong-ingress-controller
  namespace: argocd
  annotations:
    argocd.argoproj.io/sync-wave: "2" # 🎯 波次 2:等 CRD 装好后再安装控制器
spec:
  project: default
  source:
    repoURL: 'https://charts.konghq.com'
    chart: kong
    targetRevision: 2.38.0
    helm:
      values: |
        ingressController:
          installCRDs: false # 防止模板重复安装 CRD,产生冲突
        env:
          database: "off"
        gateway:
          enabled: true      # 核心:开启 Kong 对 Gateway API 的监听能力
  destination:
    name: 'tencent-dp1-cluster'
    namespace: kong-system
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - ServerSideApply=true

避坑指南 :我们在这里设置了 ingressController.installCRDs: false,目的是阻止 Helm 在模板渲染阶段重复处理 CRD(容易导致 ArgoCD sync 失败)。至于 Kong 自身的 CRD(如 KongPlugin),由于 Helm 自身的机制,会在第一次部署时通过 chart 内的 crds/ 目录自动安装。

步骤 3:定义网关基础设施 (GatewayClass & Gateway)

有了控制器后,我们需要在集群中真正开辟一扇"大门"。这些属于基础设施层的实体资源,存放在 infrastructure/kong-gateway/ 目录下。

1. 定义 GatewayClass (infrastructure/kong-gateway/GatewayClass.yaml):

这相当于在集群中注册一个网关类别,并与刚才安装的 KIC 进行"暗号配对"。

yaml 复制代码
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: kong
  annotations:
    konghq.com/gatewayclass-unmanaged: "true" # 告诉 Kong 这是一个 Unmanaged 模式
spec:
  # 这是一句关键的配对声明:所有 kong 类别的大门,都交给这个名字的控制器处理。
  # Kong KIC 程序内部硬编码了自己就叫这个名字。
  controllerName: konghq.com/kic-gateway-controller 

2. 定义 Gateway (infrastructure/kong-gateway/Gateway.yaml):

真正承接流量的入口。

yaml 复制代码
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: kong-main-gateway
  namespace: default
spec:
  gatewayClassName: kong # 引用上方的 GatewayClass
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: Same # 允许同命名空间下的业务应用创建 HTTPRoute 来绑定

3. 基础设施的 ArgoCD 调度器 (argocd-apps/kong-infra-app.yaml):

最后,通过一个 Application 将上述基础设施资源空投到目标集群。

yaml 复制代码
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: kong-gateway-infra
  namespace: argocd
spec:
  project: default
  source:
    repoURL: 'https://github.com/nvd11/my-argocd-manifests.git'
    targetRevision: HEAD
    path: infrastructure/kong-gateway
  destination:
    name: 'tencent-dp1-cluster'
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

三、 总结

通过以上配置,我们实现了一个极度优雅的 GitOps 闭环:

  1. 职责单一argocd-apps 只负责派发指令,infrastructure 只负责落地实体。
  2. 时序可控 :Sync Waves 确保了 CRD -> 控制器 -> 自定义资源 的正确启动顺序。
  3. 架构解耦 :利用标准的 Gateway API 和 GatewayClass 机制,业务应用(创建 HTTPRoute 时)只需认准 kong-main-gateway,完全不需要关心底层跑的是 Kong、Envoy 还是 Nginx。

四、 常见问题 (Q&A)

Q: 为什么 kong-controller-app 会执行 Helm 安装,而 kong-infra-app 只是单纯地投递 YAML?ArgoCD 是如何区分这两者的?

A: 其实这两个应用最终的目的地都是一致的 (都会部署到目标 Kubernetes 集群),区别在于 ArgoCD 的**"加工方式"**不同。ArgoCD 极其智能,它会根据 Applicationsource 块的定义来自动选择渲染引擎:

  • 触发 Helm 渲染模式 (如 kong-controller-app.yaml):

    当 ArgoCD 看到配置中包含了 chart: konghelm: 关键字,并且 repoURL 指向的是一个 Helm 仓库(如 https://charts.konghq.com)时,它会意识到这是一个 Helm 包。ArgoCD 会先在控制面调用 Helm 引擎,将 values 里的参数注入并渲染出完整的 K8s YAML 清单,然后再应用到目标集群。

  • 纯 YAML 直投模式 (如 kong-infra-app.yaml):

    当配置中的 repoURL 是一个普通的 Git 仓库,且仅指定了 path 目录,而没有 看到 chart 等关键字时。ArgoCD 会直接去拉取该 Git 目录下的纯文本 YAML 文件,不经过任何二次渲染,原封不动地 kubectl apply 到目标集群。

通过这种"看菜下饭"的机制,我们在同一个 ArgoCD 实例下,既能管理复杂的第三方 Helm 控制器,也能精细化控制纯手工编写的基建 YAML,实现了极大的灵活性。

Q: 所谓的 CRD(字典)在这个架构中究竟包含了哪些具体的资源?

A: 在这个部署架构中,实际上引入了两套截然不同的 CRD(Custom Resource Definition),它们让 K8s 能够识别不同类型的自定义资源:

  1. Gateway API 官方 CRD (由 gateway-api-crds-app.yaml 在波次 1 显式安装):

    这套字典属于 K8s 官方标准规范,包含了所有网关接口类型的定义。核心包含:

    • gatewayclasses.gateway.networking.k8s.io (让 K8s 认识 kind: GatewayClass)
    • gateways.gateway.networking.k8s.io (让 K8s 认识 kind: Gateway)
    • httproutes.gateway.networking.k8s.io (让 K8s 认识 kind: HTTPRoute)
    • 其他如 grpcroutes, referencegrants
  2. Kong 私有 CRD (由 Kong Helm Chart 自动隐式安装):

    当我们通过 kong-controller-app.yaml 安装 KIC 时,即便我们设置了 installCRDs: false(这是为了防止 Helm 模板渲染阶段产生冗余),Helm 的底层机制依然会在首次安装时,读取 Chart 包里的特权目录 crds/,将 Kong 专属的字典一并装入集群。它们包含:

    • kongplugins.configuration.konghq.com (让 K8s 认识 kind: KongPlugin,可用于添加限流、安全、请求重写等插件)
    • kongconsumers.configuration.konghq.com (让 K8s 认识 kind: KongConsumer)
    • kongingresses.configuration.konghq.com (让 K8s 认识 kind: KongIngress)
    • 其他诸如 tcpingresses, udpingresses

总结 :您能够在集群中编写解耦的 kind: Gateway 实体,是因为装了第一套官方的 CRD;而如果未来要利用 Kong 的生态(比如定义 kind: KongPlugin),底气则来源于第二套随控制器一起附带的私有 CRD。

相关推荐
沉迷学习 日益消瘦2 小时前
01-Kubernetes 入门:概念与安装
云原生·容器·kubernetes
沉迷学习 日益消瘦4 小时前
04-配置与扩缩
kubernetes
糟糕喔6 小时前
k8s-云原生cicd
云原生·容器·kubernetes
小二·6 小时前
云原生2026:Kubernetes + Wasm + Serverless 深度实战
云原生·kubernetes·wasm
海兰7 小时前
基于 ES|QL 的 Kubernetes 监控工具箱:使用 ES|QL 进行 Kubernetes 监控,从内存压力到错误日志
大数据·elasticsearch·kubernetes
沉迷学习 日益消瘦8 小时前
09-Helm 包管理
kubernetes
爱吃龙利鱼11 小时前
K8s 运维体系搭建:全组件监控与日志收集实战(victoria-metrics-k8s-stack 0.87.0)
运维·容器·kubernetes
欢醉11 小时前
踩了个大坑!K8s 挂载目录的日志,居然也在吃容器内存?
kubernetes·springcloud
沉迷学习 日益消瘦11 小时前
10-可观测性与排错
kubernetes