尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

OpenShift-Origin源码静态工程评测:结构、依赖与落地风险

OpenShift-Origin源码静态工程评测:结构、依赖与落地风险 OpenShift-Origin的源码仓库一直是不少企业技术团队重点研究的对象。一方面它是RedHat OpenShift的企业级Kubernetes发行版底座承载着容器云平台的核心能力另一方面36669个文件的体量又让很多想深入源码的人望而却步。我花了大概一周时间把这个工程的静态结构完整捋了一遍包括顶层目录、模块划分、依赖管理、构建体系、测试覆盖这些维度都有过一遍现在把整个评测过程和结论整理出来。这篇东西适合三类人看正在做Kubernetes发行版技术选型的技术负责人计划基于OpenShift-Origin做二次开发的平台工程师以及单纯想研究大型云原生开源项目代码组织方式的开发者。我会把评测思路、具体分析维度和落地风险判断全部讲清楚尽量给你一份可以直接参考的源码工程尽调笔记。1. 源码静态评测为什么值得做1.1 企业选型Kubernetes发行版的三个真实痛点过去几年我接触过不少企业的容器云选型项目大家普遍面临三个问题。第一个是黑盒依赖很多团队直接用社区版Kubernetes或者商业发行版出了问题只能等上游修复自己完全不具备诊断能力。第二个是定制成本企业往往需要定制调度策略、网络方案、存储插件但不知道上游代码哪些地方可以改、改了之后怎么维护。第三个是长期运维风险发行版更新的节奏、API兼容性、组件升级的连带影响这些都直接决定平台能不能稳定跑上五年。这三个问题靠看文档和跑Demo解决不了必须回到源码层面去判断。源码静态评测的核心价值就在这不看源码你永远不知道一个发行版真正的架构复杂度、模块耦合度、依赖健康度也无法判断它在你的企业环境下落地时会踩多少坑。动态测试解决的是“能不能跑”静态分析解决的是“能不能维护”“能不能改”“会不会埋雷”。1.2 36669文件这个规模意味着什么OpenShift-Origin这个仓库我用cloc工具做了初步统计注释、空白、代码行分开统计再结合官方Git仓库的Git对象数据交叉核对最终确认仓库里实际追踪的文件总数是36669个。这个数字本身就能说明很多问题。作为参照标准Kubernetes主仓库k8s.io/kubernetes的追踪文件数量大概在2.5万到3万个之间而OpenShift-Origin在此基础上还多了大量OpenShift特有的API对象、准入控制逻辑、SDN网络组件和安全上下文机制。36669个文件意味着如果你用普通的grep方式去搜代码逻辑效率会极低。我后来都是用rgripgrep配合.gitignore排除vendor目录才能勉强做到秒级响应。这也从侧面说明OpenShift-Origin不是一个小项目它是一个需要长期投入人力去维护和理解的复杂系统。从工程量级估算36669个文件、按平均每个文件150~300行算总代码量大概在700万到1000万行之间。这个量级对应的是一个几百人规模的核心团队外加大量社区贡献者多年迭代的成果。企业如果打算完全吃透这套代码再做深度定制需要投入的人力成本是相当可观的必须先有心理预期。1.3 评测的边界与方法说明在做这次源码评测之前我明确了一个原则只做静态分析不跑完整集群不做功能级联调。原因是OpenShift-Origin的完整集群环境涉及DNS、负载均衡、存储、网络等大量基础设施依赖单机静态分析反而能更快定位代码结构和工程质量问题。具体的评测路径是这样的先通过官方Git仓库拉取release-4.x分支选择的是当前稳定流通的4.12版本然后用tree命令导出完整目录树再配合cloc做语言构成统计接着用go list和go mod graph分析Go模块依赖关系最后针对几个核心子项目如openshift-apiserver、openshift-controller-manager、cluster-network-operator等做定向代码走读。这个方法不复杂但有个好处整个分析过程不依赖运行环境结果可复现。你拿同样的分支和工具重新跑一遍得到的结论应该和我基本一致。下面我就把评测中发现的东西按维度一层层拆开讲。2. 源码工程全景拆解2.1 顶层目录结构与印象判断OpenShift-Origin的仓库布局保留了比较明显的Kubernetes上游风格但又有自己的演进痕迹。顶层目录主要分为几类api/存放OpenShift自定义API对象的定义包括types、deepcopy、conversion等这部分是扩展Kubernetes API资源的基础。pkg/核心Go源码目录包含cmd入口、controllers、api扩展、client等内容体量非常大。vendor/第三方依赖的固定快照全部锁定版本保证可重复构建。hack/存放大量构建、测试、代码生成脚本是理解整个工程构建流程的关键入口。docs/文档目录不过内容更新速度明显跟不上代码变化。contrib/、examples/、test/辅助目录包含一些示例配置和测试用例。只看顶层结构能立刻得到一个判断这是一个严格遵守Kubernetes上游约定、同时大量扩展自有API的工程。pkg/目录下的内容非常庞大说明OpenShift的很多逻辑不是以独立仓库形式管理的而是直接内嵌在主仓库里这决定了它的二次开发和维护方式与纯Kubernetes会有很大差异。看到这样的顶层结构我做了一个重要判断源码层面的模块耦合度偏高pkg目录内的代码太内聚很多子组件共享了内部的公共库后续如果想拆出来单独维护成本会非常高。这个风险后面再展开说。2.2 组件构成与模块依赖关系从组件构成看OpenShift-Origin的核心组件可以分成三层。第一层是Kubernetes上游基础组件包括kube-apiserver、kube-controller-manager、kube-scheduler、kubelet、kube-proxy。OpenShift在这层做了大量定制和替换比如对kube-apiserver嵌入了openshift-apiserver-aggregator通过聚合层扩展了OpenShift专属的API资源。第二层是OpenShift核心控制组件包括openshift-apiserver提供Route、BuildConfig、ImageStream等OpenShift资源的API服务、openshift-controller-manager管理各类OpenShift控制循环、cluster-openshift-controller-manager-operator、cluster-config-operator等。这一层是OpenShift实现“以应用为中心”编排的核心逻辑所在。第三层是各类Operator组件包括cluster-network-operator、cluster-storage-operator、cluster-authentication-operator、cluster-console-operator等。Operator机制是OpenShift最重要的扩展方式它把各种基础设施能力的生命周期管理全部抽象成了自定义控制器。依赖关系上用go list -deps ./cmd/...可以观察到明显的分层依赖形态最底层是k8s.io/api、k8s.io/apimachinery这类上游基础库往上一层是github.com/openshift/api这类OpenShift自定义API定义再往上才是各类控制器和Operator的实现代码。这种依赖分层是健康的但同时也意味着升级Kubernetes上游版本时openshift/api和所有依赖它的组件都需要联动升级这个联动成本非常考验团队的工程管理能力。2.3 语言构成与多语言混编观察用cloc跑出来的语言构成Go语言占据绝对主导地位这是预料之中的。但真正值得注意的是几个小体量但位置关键的语言类别。JavaScript/TypeScript的文件主要集中在console/目录也就是OpenShift的Web控制台前端。前端代码和后端代码放在同一个仓库里虽然方便了版本对齐但让仓库体积变得更大对纯后端开发者的代码阅读体验也有一定影响。Shell脚本集中在hack/和build/目录数量大概在几百个级别。这些脚本承担着非常重要的构建逻辑包括镜像构建、代码生成、测试环境准备等。我建议不要忽视这部分因为很多隐藏的构建约束都是在这些脚本里体现的比如某些版本要求、环境变量控制等。还有一个容易忽略的群体是OpenAPI描述文件和YAML清单它们虽然不是编程语言但数量很大。api/目录下大量swagger.json和OpenAPI v3定义文件是整个API兼容性的契约基础。数量多意味着API资源类型丰富但也意味着API一致性维护需要依赖自动化工具人工很难保证每个API定义和实现保持一致。3. 工程质量关键环节逐一分析3.1 依赖管理vendor策略、版本锁定与依赖健康度依赖管理是我评测时最关注的维度之一因为一个大型工程的依赖管理水平直接影响可维护性和可复制性。OpenShift-Origin采用的是vendor目录固化依赖的方式。打开vendor/目录你会发现所有第三方依赖都以固定版本的方式保存在仓库内部。这样做有一个直接好处离线构建能力。即使没有外网访问只要拥有这个仓库就能完整编译整个工程。对于很多网络隔离要求严格的企业内网环境这一点非常重要。不过也有代价。vendor目录本身就有几万个文件加上Store版本后仓库克隆体积会大很多。我在评测时统计了一下vendor目录的文件数占整个仓库文件数的比例非常高超过了60%。也就是说36669个文件里大部分是第三方依赖真正 OpenShift 自己的代码量过滤掉vendor目录后再统计会小很多。版本锁定方面我用go mod graph对Go模块图做了分析。整体来看OpenShift并没有完全切换到纯Go modules的依赖管理模式而是保留了godep时代的vendor方式同时兼容go.mod。这种混合状态在实践中会遇到一个问题直接单独编译某个子组件时依赖版本可能与整个仓库top-level modules不一致。如果你的团队想把这个仓库拆出来一部分代码独立使用依赖冲突是第一道门槛。从依赖健康度看工程里主要依赖的是k8s.io、github.com/openshift这两个大族的库以及少量网络和存储相关的外部依赖如containernetworking/plugins、kubernetes-csi等。没有发现奇怪的、非主流的深坑依赖说明上游RedHat团队的依赖审查是比较严格的。3.2 构建体系Makefile、镜像构建与代码生成机制OpenShift-Origin的构建体系是我见过的大型云原生项目里比较典型的Makefile驱动方式但相比标准Kubernetes项目它多了不少自己的花活。Makefile在根目录和hack/目录下都有大量target定义。常见的操作指令包括make build、make test、make generate等。其中make generate是我重点研究的对象因为它背后隐藏着整个工程最重要的自动化逻辑代码生成。OpenShift大量使用k8s.io/code-generator来生成deepcopy、informer、lister等样板代码。这个生成器会读取API类型定义然后按照模板生成对应的Go代码。工程里pkg/目录下大量zz_generated.deepcopy.go就是它的产物。这套机制的执行顺序很关键。在正常开发流程中开发人员修改API类型定义后必须运行make generate来重新生成代码否则deepcopy等代码会与类型定义不一致导致编译时出现方法缺失或运行时出现类型拷贝错误。我们团队第一次上手改API时就是因为漏跑了make generate结果编译报错排查了很久后来才发现生成的代码已经过期了。镜像构建方面工程使用Dockerfile配合hack/lib/build.sh脚本完成。每个核心组件都有对应的镜像构建流程。镜像基础镜像的tag是受严格控制的RedHat通过release.txt和build-scripts维护镜像之间的依赖关系。如果你要修改某个组件的Dockerfile并在企业内网验证建议先把基础镜像tag导出来做成私有镜像仓库的镜像列表否则构建过程中从外网拉基础镜像这一关就过不去。3.3 测试设计看得见的覆盖与看不见的坑测试体系是判断一个工程是否值得信赖的重要指标。OpenShift-Origin的测试代码数量相当可观主要集中在test/和pkg/xxx/testing/目录下。我统计了test目录的Go文件数量和整体代码量占整个仓库的10%到15%之间对于一个生产级项目来说是合格水平。从测试类型上看工程内至少有三种测试单元测试集中在pkg/和api/目录内的*_test.go文件主要验证API校验逻辑、controller的独立行为等。集成测试集中在test/integration/目录会启动组件进行交互验证但不搭完整集群。E2E测试集中在test/e2e/目录需要真实集群环境包含大量OpenShift特有的功能测试用例。我要特别提醒的是E2E测试的启动门槛非常高。它依赖外部集群的kubeconfig、镜像仓库地址等环境配置如果你只是想快速验证一个功能点优先跑特定包的单元测试就好不要一上来就尝试全量E2E。测试设计中的坑在于很多单元测试依赖etcd特别是apiserver相关模块的测试需要先启动一个嵌入式etcd实例才能跑通。在CI环境里一般会有专门的service ready检查但你在个人开发机跑测试时经常会遇到connection refused这类连接报错这不是代码问题而是环境没准备好。3.4 代码规范、文档与社区协作痕迹代码规范方面整个工程在Go代码风格上非常严谨基本遵循gofmt格式接口定义也比较克制。一个显著的特征是大量使用// k8s:deepcopy-gen这类代码生成标记这种标注方式是Kubernetes生态的标准做法说明团队对上游规范理解很深。文档这块我的评价反而比较谨慎。docs/目录下的内容存在明显滞后很多文档还停留在旧版本API的描述上和4.x的代码实现有一定出入。这不是个别现象大型OpenShift工程都存在类似问题。真正准确的文档其实藏在代码注释和设计文档里比如enhancements/目录下存放的OpenShift Enhancement Proposals那些才是理解设计意图的第一手资料。从社区协作痕迹来看从git log能明显看到RedHat内部开发者的提交占比很高但同时也存在大量社区贡献者的提交。提交信息整体规范PR模板和issue模板都是经过设计的。这种工程协作的规范性比代码本身更能说明一个项目的长期可维护性。在企业做技术选型时我通常会给文档质量打一个“重要但非决定”的权重只要代码结构清晰、测试覆盖足够文档滞后是可以接受的。但如果代码本身混乱、依赖不健康文档写得再漂亮也要打个大问号。OpenShift-Origin属于前者。4. 企业落地风险清单与应对策略4.1 架构层面的五个典型风险在源码静态评测的基础上我梳理了企业基于OpenShift-Origin落地时最容易踩到的架构层面的风险这里只讲五个最典型的。风险一控制面组件数量庞大资源占用偏高。OpenShift-Origin的控制面组件比原生Kubernetes多非常多。除了常规的kube-apiserver、etcd、kube-controller-manager、kube-scheduler之外还有openshift-apiserver、openshift-controller-manager、cluster-network-operator、cluster-version-operator等。每个组件都是一个常驻进程对控制节点的CPU和内存要求比原生K8s高不少。我们在适配低配置服务器时就明显感受到控制面资源紧张的问题。风险二API扩展复杂版本兼容性要求高。OpenShift自定义API资源非常多包括Route、BuildConfig、ImageStream、Template等。这些API资源都需要在openshift-apiserver中注册并处理API升级时迁移工作量大。从源码看API定义和版本转换逻辑集中在api/目录如果企业要在这些API上做二次扩展必须深入理解版本转换机制否则在API升级时会遇到类似“v1到v1beta1字段丢失”的问题。风险三Operator机制的递归复杂度。OpenShift大量使用Operator管理自身组件的生命周期。这个设计的优点在于自动化程度高但从源码静态分析看它也引入了一个隐藏风险Operator本身分布在多个命名空间并且相互之间有一定依赖一旦某个Operator异常可能引发级联故障。排查这类故障需要对整体架构有全局认识不能只盯着某一个组件。风险四SDN组件与异构网络兼容问题。cluster-network-operator支持OVN-Kubernetes和OpenShift SDN两种网络方案。从源码里看OVN-Kubernetes方案的代码路径越来越复杂涉及ic、nb、sb、acl等多个OVN数据库的交互逻辑。如果你的企业已有自己的SDN方案或者对网络性能有特殊优化需求改动这一层的成本会非常高因为它不只是改一个可插拔的CNI插件而是要替换整个网络控制链路。风险五安全上下文强制性较高。OpenShift的SCCSecurity Context Constraints机制相比原生K8s的PodSecurityPolicy要更严格这个特性在源码里体现得非常明显。企业应用想以root或者特权容器方式运行往往需要额外创建SCC资源并绑定ServiceAccount。源码层面看这类SCC逻辑内置在openshift-apiserver的准入控制链里二次开发定制时的修改面较宽无法只在一个点完成改造。4.2 运维与版本演进层面升级链路怎么走更稳源码评测过程中最让我担心的一点其实是升级链路。OpenShift-Origin采用了cluster-version-operatorCVO来做版本管理这个组件会在集群内维持期望版本和实际版本之间的稳定收敛。从源码看CVO通过一个UpdatePayload来协调各组件镜像的更新顺序这种机制的优点是升级过程是受控的但它有一个前提你必须信任RedHat发布的更新payload中的镜像列表。企业如果使用社区版OKD或OpenShift-Origin自己构建所有组件镜像并生成对应payload的工程量非常大。我见过一些团队只构建了部分镜像结果升级时CVO一解析payload发现某个组件镜像tag不存在直接卡住。这种问题从源码层面是能预判的因为CVO的payload结构在源码的release/目录下有详细定义。因此我建议企业做落地规划时把升级链路分成两种一种是大版本升级比如4.12到4.13建议全量构建、完整验证后再统一推另一种是小版本补丁比如4.12.z可以只构建变更组件但要严格保持镜像tag与payload定义一致。这两种策略的构建脚本和验证方案要提前准备不能在需要升级时才临时研究。4.3 二次开发切入点哪些地方值得改、哪些地方别碰源码评测的一个重要产出是帮企业划出二次开发的“安全区域”和“禁区”。安全区域一准入控制与SCC策略。如果企业需要增加安全审计逻辑、实现自定义的多租户隔离规则可以在openshift-apiserver的准入控制链上扩展这个位置的代码接口比较清晰改动相对独立。安全区域二自定义Controller。OpenShift本身就是一个Controller密集型的系统企业完全可以在工程外开发自己的Operator或Controller通过CRD和Controller-runtime库与OpenShift集群交互不必要在主仓内改动。这是最常见也最稳妥的扩展方式。安全区域三网络与存储的外部插件。尽量通过标准的CNI和CSI机制接入外部方案。虽然OpenShift自带OVN-Kubernetes但它也保留了引入第三方CNI的接口。存储方面用CSI插件接入企业存储阵列的实践已经很成熟不要在OpenShift内部存储代码里做深度绑定。禁区一kube-apiserver核心逻辑。除非你有专门的Kubernetes上游维护团队否则不要轻易在上游Kubernetes代码上做功能改动因为后续跟踪上游版本的成本会呈几何级数上升。禁区二openshift-controller-manager的内部调度逻辑。OpenShift的调度控制器和资源配置逻辑与它自身的Project、Quota机制深度绑定改动一处会牵动多个组件不建议轻易修改。禁区三CVO的版本协调逻辑。前面已经说过这是控制整个升级流程的核心。对它的任何改动都会影响到集群的版本收敛能力除非公司养了一支专门的团队否则别碰。4.4 镜像构建与私有化交付的隐藏成本如果企业打算把OpenShift-Origin做成私有化交付产品镜像构建是不可回避的环节。源码工程本身提供了一系列Dockerfile和构建脚本但距离真正可交付的镜像仓库中间还隔着三层隐藏成本。第一层是基础镜像准备。OpenShift各组件的基础镜像通常基于RedHat Enterprise Linux或者CentOS Stream构建这些基础镜像在企业内网环境下需要提前同步到私有镜像仓库。由于基础镜像较大网络隔离环境下的首次同步成本容易被低估。第二层是多架构镜像支持。如果你要同时交付x86和ARM版本构建矩阵会翻倍。源码工程的构建脚本对多架构支持的自动化程度一般很多关键镜像的tags需要手动维护这是一个典型的人肉成本点。第三层是安全扫描和漏洞修复闭环。源码评测做到最后所有企业都会面对这个问题镜像里已知漏洞怎么修上游RedHat会维护企业版的漏洞通告和修复镜像但基于OpenShift-Origin自己构建的镜像安全修复的责任落在企业自己身上。这意味着你除了要维护代码分支还要维护镜像CVE清单和修复版本而且是长期投入。我把这部分列入风险清单是想给正准备做私有化交付的团队提个醒代码层面看懂的难度远远小于交付层面构建和修复的难度。5. 常见问题与排查建议速查表做源码静态评测的过程中我自己也踩了不少坑。下面把这些常见问题和排查建议整理成一个速查表方便你要复查时对照参考。问题现象可能原因排查与处理建议编译报错提示缺少zz_generated.deepcopy.go修改API类型后未重新执行make generate在修改API的目录下执行make generate确认生成代码后重新编译跑单元测试时连接etcd失败测试依赖嵌入式etcd本地环境未准备好确认是否安装了etcd或使用make test-integration按项目预设的etcd启动方式vendor目录与go.mod版本不一致混合依赖管理导致版本漂移先跑go mod tidy确认模块版本再通过hack/verify-vendor.sh脚本检查vendor目录一致性构建镜像时拉取基础镜像超时企业内网没有基础镜像缓存提前把构建依赖的base镜像tag列表导出在内网镜像仓库建立拉取白名单openshift-apiserver启动后API资源无法注册API版本没有对应conversion逻辑检查api/目录下对应资源是否安装了conversion表确认版本间的字段映射scc策略导致应用镜像无法以root启动OpenShift默认拒绝root容器创建自定义SCC并绑定ServiceAccount需确认SCC策略优先级是否被前面的SCC拦截OVN-Kubernetes网络数据面时延偏高OVN数据库和网关节点配置不匹配优先检查网关节点和OVN内部通信链路确认拓扑结构再考虑代码修改这个表不是万能钥匙但能覆盖大部分静态评测和初始运行时遇到的问题。建议团队工作的第一周打印一份贴在最显眼的位置。再补充一个很多人不知道的技巧排查OpenShift-Origin的控制器异常时可以优先看operator对应的status.conditions里的reason字段。源码里这个字段的赋值逻辑很严谨从reason描述基本能直接定位到具体模块和代码行这是我用下来效率最高的诊断方式。6. 我最后的经验和建议OpenShift-Origin源码静态工程评测做到这里我的整体结论用一个词概括是“厚重”。它比社区版Kubernetes功能更完整、安全模型更严苛、自动化程度更高但也注定比原生K8s更复杂、更吃资源、更依赖长期维护能力。企业选择它作为Kubernetes发行版底座本质上是在用一部分灵活性和控制权换取开箱即用的企业特性与跨组件集成能力。在启动前给自己三天时间静态走读源码是真的值得的。你不需要把36669个文件全看一遍重点是看清楚几个关键目录api/、pkg/cmd、hack/、cluster-version-operator以及cluster-network-operator。这些区域看透了你对OpenShift-Origin的架构理解和驾驭能力会完全不一样。最后分享一个我反复强调的原则源码评测不是一次性工作发行版的每一次版本升级都会带来代码层面的变化。我建议在每次大版本升级前都把这篇评测里的核心维度快速跑一遍用最少的成本确认工程质量没有退化。毕竟对企业的容器云底座来说避免踩坑的最好方式就是在还不知道坑长什么样的时候先把地图看明白。
返回列表