勿忘初心做自己 发表于 6 天前

云原生 CI/CD 平台架构筹划

一套运行在公有云上的 GitOps 交付平台,覆盖 500 个线上项目。从网络拓扑、集群规划到主动化链路,完备复盘架构筹划思绪。
一、团体架构概览

先看全局。整套平台摆设在公有云 VPC 内,承载 500 个线上项目的构建和摆设,核心组件分布在三条逻辑链路上:
graph TB    subgraph 代码与成品侧      A[GitLab
代码堆栈 + CI Runner]      B[Harbor
镜像堆栈 + OCI Chart 成品库]    end    subgraph 设置侧      D[GitOps 设置堆栈
应用界说 + 情况 Values]    end    subgraph 集群侧      E[ArgoCD
集群内同步 Agent]      F[Argo Rollouts
渐进式交付]      G[Kubernetes 集群
3 节点池 / 4 定名空间]    end    subgraph 外部      H      I[飞书关照]    end    A -->|推送镜像 + Chart| B    A -->|更新情况设置| D    E -->|轮询 + 同步| D    E -->|摆设 + 康健查抄| F    F -->|管控| G    G -->|对外袒露| H    A -->|摆设变乱| I    E -->|同步状态| I筹划核心:CI 体系不打仗集群。 这条束缚是整个架构的安全基石。CI 只管产出成品(镜像和 Chart)、更新 GitOps 设置堆栈,不持有任何集群根据。集群内的 ArgoCD 自主拉取设置并同步。安全界限清楚——纵然 CI 体系被攻破,攻击者也拿不到集群控制权。
二、网络拓扑:四条隔离界限

网络筹划是云上安全的第一道防线,过后改的资本极高。我们划了四条隔离界限:
graph LR    subgraph 公网      USER[用户流量]      DEV[开辟者]    end    subgraph VPC      subgraph 公网接入层            SLB            NAT      end      subgraph K8s 节点池            direction TB            W_PROD[生产节点池]            W_FAT[测试节点池]      end      subgraph 根本服务            REGISTRY            GIT      end    end    USER --> SLB    SLB --> W_PROD    DEV --> GIT    DEV --> REGISTRY    W_PROD -.->|内网拉镜像| REGISTRY    W_FAT -.->|内网拉镜像| REGISTRY    W_PROD -.->|出公网| NAT    W_FAT -.->|出公网| NAT界限一:Worker 节点不绑公网 IP。 出网走 NAT 同一出口,入网只走 SLB。节点对公网完全不可见。
界限二:镜像堆栈和 GitLab 在同一 VPC。 Runner 也在 VPC 内。构建、推送、拉取全链路走内网,不产生公网流量费用。
界限三:SLB 是唯一的公网入口。 SSL 闭幕在 SLB 层,SLB 做七层转发到 Ingress。不把证书分散到各个应用上管理。
界限四:根据不出集群。 这是个容易被忽略但极其告急的筹划点。Harbor 暗码、GitOps 堆栈 Token、飞书 Webhook Secret,全部通过 GitLab CI 变量注入,CI 运行时以情况变量情势存在于 Runner Pod 内,不写入设置文件、不进入 Git 汗青。ArgoCD 侧的集群根据由 Kubernetes Secret 管理,通过 Sealed Secrets 加密后存入 GitOps 堆栈——Git 里的密文是可版本化的,但只有集群内的 controller 能解密。镜像堆栈的拉取根据同理,通过 imagePullSecrets 注入,应用开辟者不必要知道 Harbor 暗码。
不睁开讲工具细节,核心原则一句话:根据的明文只存在于运行时内存和集群内部 Secret 中,任何恒久化存储(Git、日记、成品)里只答应出现密文或引用。
三、交付链路:为什么拆成两条流水线

这是全文最告急的架构决议,值得单独一节。
sequenceDiagram    participant Dev as 开辟者    participant CI as GitLab CI    participant Registry as Harbor    participant GitOps as GitOps 设置堆栈    participant Argo as ArgoCD    participant K8s as K8s 集群    Dev->>CI: git push    CI->>CI: 编译 + 测试 + 镜像构建    CI->>Registry: 推送镜像 + Helm Chart    CI->>CI: 渲染情况 Values    CI->>GitOps: git commit + push    CI-->>Dev: 关照:构建完成    Note over Argo,GitOps: ArgoCD 每 3 分钟轮询    Argo->>GitOps: git pull    Argo->>Argo: diff 盼望状态 vs 现实状态    Argo->>K8s: 同步差别    Argo-->>Dev: 关照:摆设完成假如把镜像推送和集群摆设写在同一个 pipeline 里(构建完直接 kubectl apply),即是把集群写权限捆绑在 CI 体系上。一旦 CI 被攻破——Runner 镜像有弊端、开辟者脚本注入了恶意下令、某个 CI 变量泄漏——攻击者就能直接操控集群。
拆成两条线之后:
构建线(左侧):CI 只做编译、镜像打包、Values 渲染、Git push。这条线不必要任何集群根据,以致不知道集群所在。
同步线(右侧):ArgoCD 在集群内部,一连对比 Git 堆栈和现实状态,有集群写权限,但完全不袒露给外部体系。
额外收益:摆设和构建解耦后,回滚变得极其简朴。 回滚就是 git revert 推送到 GitOps 堆栈,ArgoCD 主动同步回集群。运维不必要 kubectl 权限,在 GitLab 界面点一下 rollback pipeline 按钮就完成。从"半夜爬起来敲下令"变成了"手机上点个按钮"。
代价:3 分钟的轮询延长。 ArgoCD 默认每 3 分钟拉一次 Git,这意味着从 CI 推送设置到集群现实变更,最多有 3 分钟的空缺期。对于绝大多数业务场景这个延长可以担当。假如对延长敏感,可以紧缩轮询隔断,大概用 webhook 触发——两者都支持,我们守旧地用轮询,先稳再快。
四、平台自举:ArgoCD 自己怎么摆设

GitOps 架构中有一个经典标题:ArgoCD 管理全部业务应用,那 ArgoCD 自己怎么管理?
我们的做法分两层:
集群根本组件(ArgoCD、Traefik、Prometheus、Sealed Secrets Controller 等)不走 GitOps 自举循环——它们由 Helm 手动安装到 kube-system 和专用定名空间,设置通过 values.yaml 生存在 Git 堆栈中,但安装动作是手动的。这不是技能做不到,而是刻意为之:根本组件是平台的"底座",底座不应该依赖平台自己。假如用 ArgoCD 管理 ArgoCD,那就成了一个死结——ArgoCD 挂了,谁去实验 GitOps 同步来规复它?答案是没人,你得手动到场。那还不如一开始就老老实实手动装,别冒充能主动规复。
业务应用和 Addon 由 ArgoCD 通过 ApplicationSet 管理。新增一个项目时,只必要在 GitOps 堆栈中新增一个 Application 界说文件,ArgoCD 主动同步。这部门完全 GitOps 化。
这个"分层自举"的筹划不是一个优雅的方案,但它是一个老实的方案。许多文章会声称"统统皆 GitOps",但底座组件的手动安装是工程现实。我们宁肯在架构文档里认可这一点,而不是冒充 pipeline 里一个 terraform apply 就能办理统统。
五、分支即情况:单集群多定名空间的路由筹划

不做"一个情况一个集群"的奢侈方案。500 个项目跑在集群上,通过定名空间做逻辑隔离:
graph TB    subgraph Git 堆栈      B1      B2      B3      B4    end    subgraph K8s 集群      subgraph fat-ns            F1[项目 A] --- F2[项目 B] --- F3[项目 C]      end      subgraph uat-ns            U1[项目 A] --- U2[项目 B]      end      subgraph prod-ns            P1[项目 A] --- P2[项目 B]      end      subgraph preview-ns            V1            V2      end    end    B1 -->|主动| fat-ns    B2 -->|手动| uat-ns    B3 -->|手动| prod-ns    B4 -->|主动创建| preview-ns为什么照旧单集群? 500 个项目的体量下,这个选择看起来有些反直觉,许多人第一反应是"肯定得拆"。我们的来由不是单集群有多好,而是多集群在这个场景下带来的额外复杂度——多套监控、多套日记、多个 Ingress 入口、跨集群服务发现、多版本的 API 兼容——在当前阶段大于单集群的风险。定名空间级别的隔离加上 RBAC 和资源配额,已经做到了"一个情况的故障不波及其他情况,一个团队的 Pod 不抢占另一个团队的资源"。
什么时间拆? 当出现以下信号之一:某个业务方要求生产情况物理隔离(合规要求而非技能需求)、集群规模靠近单集群的节点上限、大概控制面压力(大量 ArgoCD Application 导致 API Server 负载过高)开始影响调理性能。当前架构的一个告急筹划是:情况设置和集群目的是解耦的——同一个 GitOps 堆栈、同一套 Chart 模板,拆集群时只必要将 prod 定名空间的 ArgoCD Application 指向新集群即可,不必要重新天生任何成品。
生产摆设必须手动触发。 fat 可以主动,但 uat 和 prod 在 pipeline 里必要人点按钮。这不是技能限定,是流程筹划——通往生产的每一步都要有人对它负责。
Feature 预览情况的生命周期管理。 feature 分支在合入或删除后,对应的定名空间、Ingress 域名、ArgoCD Application 一并主动接纳。不留僵尸资源是云资本控制的底线。
六、集群内流量拓扑:南北向和东西向分开看

graph TB    subgraph 集群外部      DNS      CDN    end    subgraph 集群内      SLB_L7[SLB
七层转发 / TLS 闭幕]      INGRESS[Traefik Ingress
限流 / 域名路由]      SVC_A      SVC_B      POD_A1      POD_A2      POD_B1    end    DNS --> CDN    CDN --> SLB_L7    SLB_L7 --> INGRESS    INGRESS -->|域名路由| SVC_A    INGRESS -->|域名路由| SVC_B    SVC_A -->|iptables| POD_A1    SVC_A -->|iptables| POD_A2    SVC_B -->|iptables| POD_B1    POD_A1 -.->|东西向直连| POD_B1南北向:CDN → SLB(七层转发 + TLS 闭幕)→ Ingress → Service → Pod。SSL 闭幕在 SLB 层,证书同一管理。Ingress 层专注于域名路由和限流战略,各司其职。
东西向:集群内服务间直连,不绕 Ingress。镌汰一跳延长,也制止内部流量被限流战略误伤。
为什么选 Traefik 而不是 K8s 原生 Ingress Controller? Traefik 的中心件机制(限流、重定向、路径更换、IP 白名单)可以按 IngressRoute 粒度绑定,不必要在每个应用的 Chart 里重复实现这些横切逻辑。代价是它的 CRD 和原生 Ingress 资源不通用,团队必要额外学习。假如你已经在用原生 Ingress 且没有中心件需求,没须要换。
多租户的网络隔离: 500 个项目跑在一个集群里,差别定名空间之间的 Pod 默认可以互访(K8s 的默认运动)。当前没有上全量 NetworkPolicy——不是不必要,而是 500 个项目的 NetworkPolicy 规则维护资本太高,且大部门项目之间没有调用关系,默认战略就是全通。对于有明确隔离需求的业务(好比涉及付出或用户数据的服务),单独配白名单战略,而不是一刀切。假如后续羁系要求升级,模板层可以主动为每个项目天生默认拒绝 + 显式放行的 NetworkPolicy。这个决议是权衡过的——不被还没发生的合规需求拖着走,但也留好了升级路径。
七、渐进式交付:灰度的真正代价是"反悔权"

标准发布停旧启新,中心有短暂不可用。K8s 滚动更新能办理这个标题(先启新 Pod,康健查抄通过再停旧 Pod),但假如新版本有 bug,滚动更新会把 bug 渐渐扩散到全部 Pod,等你发现已经全量了。
灰度的真正代价不是"平滑切换",而是在错误扩散之前拦住它。
graph LR    subgraph 标准发布      S1 --> S2[新 Pod 启动]      S2 --> S3[康健查抄通过]      S3 --> S4[旧 Pod 克制]    end    subgraph 金丝雀发布      C1[创建 Canary Pod] --> C2[切 10% 流量]      C2 --> C3{主动分析
Prometheus 指标}      C3 -->|通过| C4[渐渐提升至 100%]      C3 -->|失败| C5[主动回滚]    end    subgraph 蓝绿发布      G1[创建完备绿色情况] --> G2[切换 Ingress 权重]      G2 --> G3{观察窗口}      G3 -->|确认| G4[接纳蓝色情况]      G3 -->|非常| G5[切回蓝色]    end三个组件共同支持这套本领:

[*]Argo Rollouts 替换原生 Deployment,担当 Pod 生命周期和流量切换。
[*]Traefik IngressRoute 的加权路由,实现按比例切流量。
[*]Prometheus + AnalysisTemplate 在灰度期间一连查询错误率、延长、重启次数,恣意一项破线主动停止回滚。
发布战略按业务告急度分级:
战略实用场景发布时长标准发布内部工具、管理背景1-2 分钟金丝雀 + 主动分析核心 API、用户面服务5-10 分钟蓝绿大版本升级、数据库迁移10-30 分钟一个踩过的坑:分析窗口要区分预热期和稳态期。 新 Pod 启动时 CPU 和延长天然偏高,假如在这个阶段就开始分析,大概率误判回滚。我们的做法是分析模板先设一段静默期(只查抄 Pod 是否 Ready,不做性能判断),过了静默期再进入正式的指标分析。这个值我们调了好频频才找到一个比力稳的默认值——不是代码标题,是参数标题。
八、可观测性:三层覆盖,逐级缩小排查范围

云上应用出标题时的排查链路比应用自己长得多——哀求颠末了 CDN、SLB、Ingress、Service、Pod 五层,任何一层出标题用户看到的都是 502。
graph TB    subgraph 第一层-根本办法      NODE[节点指标
CPU/内存/磁盘/网络]      KSM[kube-state-metrics
Pod 状态 / 副本数]    end    subgraph 第二层-应用链路      APM[应用指标
QPS / 延长 / 错误率]      TRACE[分布式追踪
OpenTelemetry]    end    subgraph 第三层-变乱      DEPLOY[摆设变乱
谁 / 什么时间 / 发到哪]      ALERT[告警变乱
Prometheus AlertManager]      NOTIFY[关照服务
聚合推送飞书]    end    NODE --> PROM    KSM --> PROM    APM --> PROM    TRACE --> TEMPO    PROM --> GRAFANA    PROM --> ALERTMANAGER    ALERTMANAGER --> NOTIFY    DEPLOY --> NOTIFY    NOTIFY --> FEISHU[飞书群]分层不为分而分,而是为了一个非常现实的目的:出了标题沿层级逐级缩小排查范围。
我们的固定排查路径:先看变乱层有没有近来的摆设记录("是不是刚发版了"——这个标题能表明 50% 的线上非常),再看应用层哪个服务的指标先出现非常(缩小到详细服务),末了看根本办法层有没有资源瓶颈(缩小到详细节点或 Pod)。没有这个分层,排查就是对数百万条日记大海捞针。
关照服务的架构要点只有一句话:关照是旁路,不能壅闭主流程。 关照发失败了不应该影响摆设结果。以是关照服务是独立摆设的 Webhook 中转——CI 发一个 JSON 过来,关照服务负责格式化并推送到飞书,CI 不关心推送结果。摆设日记里看不到关照报错,那是关照服务的事。
九、架构筹划的五个弃取

这是全文最告急的一章。架构本质上是弃取,而不是"最佳实践"的堆砌。下面五个决议是做过的最难的。
1. 单集群 vs 多集群。 500 个项目仍然选了单集群。这个决定不轻松——利益是运维资本受控,一套监控、一套日记、一套 Ingress 扛住全部业务。代价是风险会合,集群故障会同时影响全部情况。拆集群的触发条件不是项目数目,而是合规要求物理隔离、节点数逼近单集群上限、或 API Server 压力影响调理性能。真到那一天,情况设置和集群目的是解耦的——同一个 GitOps 堆栈,改一下 Application 的指向就能迁走。
2. Push vs Pull。 选了 Pull。运维倾向于主动下发(Push),但 Pull 把安全界限缩到了集群内部——不必要向外部袒露任何写入接口。ArgoCD 每 3 分钟轮询的延长是代价,但业务上可担当。守旧选型:先稳再快。
3. 模板化 vs 机动性。 同一模板让 90% 的项目接入极快,新项目几分钟上线。代价是剩下 10% 的复杂需求必要改模板,而改模板影响全部利用者。没有完善解法——我们在模板里预留了"自界说注入"的扩展点,让少数特殊需求有出口。
4. 自研 vs 组合。 没有自研任何核心组件,全用 CNCF 生态——GitLab CI、Harbor、Helm、ArgoCD、Argo Rollouts、Traefik、Prometheus、OpenTelemetry。外貌看是在"搭积木",但选型、组合、调参自己就是架构工作。知道哪些组件拼在一起能形成完备闭环、界限画在那里不容易出标题——这些判断必要踩过坑才气做出来的。
5. 底座手动 vs 完全 GitOps。 坦率地说,没有做到"统统皆 GitOps"。ArgoCD 自己、Traefik、Prometheus 这些底座组件是 Helm 手动安装的,设置存 Git 但安装动作必要人工。这不是本领标题——技能上可以让 ArgoCD 管理 ArgoCD(自举循环),但这是个伤害的循环依赖:假如 ArgoCD 挂了由 ArgoCD 来规复自己?底座应该是平台的锚,锚不能自己拉着自己。一个不优雅但老实的答案。
平台的代价不在于图纸画得多漂亮,而在于开辟推代码之后不必要关心中心发生了什么。哪天它不在的时间你才会感觉到它存在——谁人周一的早上,没人记得前次谁改了什么设置的时间。
各位大佬感爱好可以关注我的公众号:探索者卡尔

免责声明:如果侵犯了您的权益,请联系站长及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金.
页: [1]
查看完整版本: 云原生 CI/CD 平台架构筹划