GitOps 工作流

这个仓库是整个集群的唯一事实来源(source of truth)。ArgoCD 持续监视 yldm-tech/k8s-configmain 分支,把仓库目录里的 YAML 变成集群里运行的 Application,再由 Application 把各自的 manifest 同步进集群。合并到 main 几分钟后改动就会被自动同步,没有手动 kubectl apply 这一步。

两层编排概览

ArgoCD 用两层结构把仓库变成运行的应用:第一层是 App-of-apps 根应用,负责自动发现 bootstrap/applications/ 下所有的 Application / ApplicationSet;第二层是其中一个特殊的 微服务 ApplicationSetyldm-services),它用一个静态列表批量生成所有业务微服务的 Application。基础设施、数据库、监控、网络策略这类单例由第一层直接覆盖;业务微服务则交给第二层统一生成。

  • Name
    ① App-of-apps 根应用
    Description
    bootstrap/applications/root-app.yaml,用 directory.recurse: true 递归扫描 bootstrap/applications/ 目录(排除自身),任何放进去的 Application / ApplicationSet YAML 都会被自动发现,无需手动注册。
  • Name
    ② 微服务 ApplicationSet
    Description
    bootstrap/applications/orchestration/production-services.yaml,ApplicationSet 名为 yldm-services,用 List generator + goTemplate 由静态列表批量生成业务服务的 Application。

App-of-apps 根应用

根应用 root-app(namespace argocd,project default)的 source 指向仓库 bootstrap/applications 路径,开启 directory.recurse: trueexclude: 'root-app.yaml'(避免自引用)。它本身就是一个 Application,作用是把 bootstrap/applications/ 目录下的每一份 Application / ApplicationSet 清单都同步进集群。

这意味着新增一个 ArgoCD Application 或 ApplicationSet 时,只要把 YAML 放进 bootstrap/applications/ 下任意位置,根应用就会在下次 reconcile 时自动发现并接管 —— 不需要在任何地方手工登记。这条路径覆盖的是各类单例:infrastructure、databases、monitoring、network policies,以及 cluster/ 下的集群级配置。

# bootstrap/applications/root-app.yaml (节选)
spec:
  source:
    repoURL: git@github.com:yldm-tech/k8s-config.git
    targetRevision: main
    path: bootstrap/applications
    directory:
      recurse: true
      exclude: 'root-app.yaml'
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

微服务 ApplicationSet

业务微服务不是一个个手写 Application,而是由 ApplicationSet yldm-services 统一生成。它用 List generator 配合 goTemplate: true(并设 goTemplateOptions: ["missingkey=error"]),列表里每个元素是一组字段:service / serviceType / namespace / replicas(还有 category,少数元素带 sourceRepo 覆盖)。

template 把每个列表元素渲染成一个名为 <serviceType>-<service> 的 Application(例如 platform-fluxaapp-aidictgame-dnf-server),source 指向仓库的 applications/<serviceType>/<service> 路径,destination namespace 取该元素的 namespace,project 取 serviceType

每个生成的 Application 同样开 automated: {prune, selfHeal}(并 allowEmpty: false),带 PrunePropagationPolicy=foreground / PruneLast=true 等 syncOptions 和重试退避,且 ignoreDifferences 忽略 Deployment/spec/replicas(让 HPA 调整副本数时不被判为 drift)。游戏服务器一类的具体部署可参见 游戏服务

# production-services.yaml template (节选)
template:
  metadata:
    name: '{{.serviceType}}-{{.service}}'
  spec:
    project: '{{.serviceType}}'
    source:
      path: 'applications/{{.serviceType}}/{{.service}}'
    destination:
      namespace: '{{.namespace}}'

AppProject 隔离

bootstrap/projects/*.yaml 定义了 6 个 AppProject,用来限定每个 Application 能创建哪些资源、落到哪个 namespace。ApplicationSet 生成的业务 Application 的 project 字段就取自列表元素的 serviceType,正好对应到这里的 app / platform / game。

AppProject用途资源范围
appYLDM Application Servicesnamespace 限定 app
platformYLDM Platform Servicesnamespace 限定 platform
gameYLDM Game Servicesnamespace 限定 game
infrastructure基础设施组件(Ingress、存储、证书管理等)允许集群级资源(显式 whitelist)
ci-cdCI/CD 系统(Tekton Pipelines、Triggers 等)允许集群级资源
monitoring监控和日志系统(Prometheus、Grafana、Loki 等)允许集群级资源

app / platform / game 是 namespace-scoped 的(clusterResourceWhitelist 不开放或受限,destinations 锁到单一 namespace);infrastructure / ci-cd / monitoring 则通过显式的 clusterResourceWhitelist 放行 ClusterRole、CRD、Webhook、StorageClass、ClusterIssuer 等集群级资源。

自动同步与镜像回写

两层结构下的 Application 普遍开启 automated.pruneautomated.selfHealprune 会删掉已从 git 移除的资源,selfHeal 会把集群里被手动改动的资源拉回 git 声明的状态。所以改集群的正确方式是改仓库再合并,手动 kubectl edit 会被 selfHeal 覆盖回去

镜像 tag 不靠手工维护,而是由 argocd-image-updater 反向回写。每个应用在 applications/infrastructure/argocd-image-updater/imageupdaters/<app>.yaml 有一份 ImageUpdater CR,采用 semver 策略并用严格正则 ^[0-9]+\.[0-9]+\.[0-9]+$ 过滤 tag(跳过 latest / sha / 任意 tag)。检测到新版本时,它通过 SSH 把新 tag 写回该应用 kustomization 的 images: 块,提交到 main(就是仓库里那些 build: automatic update of … 的提交),随后 ArgoCD 再把新镜像同步进集群。

评论