十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用 kustomize transformer 插件集成 kubeval:为 K8s 资源构建验证流水线

用 kustomize transformer 插件集成 kubeval:为 K8s 资源构建验证流水线 用 kustomize transformer 插件集成 kubeval为 K8s 资源构建验证流水线【免费下载链接】kustomizeCustomization of kubernetes YAML configurations项目地址: https://gitcode.com/gh_mirrors/ku/kustomizekustomize 本身只负责对 YAML 配置做定制化渲染并不会校验输入或输出的资源是否符合 Kubernetes API 规范本指南以 examples/zh/validationTransformer.md 为骨架演示如何编写一个 bash 形式的 transformer 插件把第三方校验工具 kubeval 接入 kustomize 的构建流程在资源进入集群前完成校验。读完本文你将掌握 kustomize transformer 插件的运行协议stdin/stdout、配置入参、退出码约定、插件的目录发现规则与启用方式并能独立实现一个可复用的资源验证插件。背景kustomize 不校验资源kubeval 来补位kustomize 在其文档与示例中明确说明它不会对其输入或输出做超出依赖包marshal/unmarshal之外的验证。也就是说一份kustomization.yaml即使引用了结构上非法的资源kustomize 也可能照常完成渲染把问题留给集群侧。另一款开源工具kubeval则专门做 Kubernetes 感知的校验例如对下面的非法 ReplicationController 文件$ kubeval my-invalid-rc.yaml The document my-invalid-rc.yaml contains an invalid ReplicationController -- spec.replicas: Invalid type. Expected: integer, given: string思路由此而来kustomize 允许用户编写 transformer 插件把已加载的资源交给任意外部程序处理。于是我们可以写一个 transformer 插件让 kubeval 在 kustomize 构建过程中对资源做校验从而把校验变成 kustomization 构建流水线的一环。仓库中该示例的英文原版位于 examples/validationTransformer/README.md中文版即本文主体完整可运行的示例插件目录见 plugin/someteam.example.com/v1/validator。transformer 插件的运行协议插件假设kustomize 对外部 transformer 插件有五个明确的运行假设理解它们是编写任何插件无论用 bash、Python 还是 Go 编写的前提资源从stdin传入 transformer 插件插件的配置文件作为第一个参数传入实际是一个临时文件内容为插件配置 YAML即transformers:字段引用的那个文件插件的工作目录是使用该 transformer 的 kustomization 所在目录转换后的资源由插件写入stdout如果 transformer 插件的返回码非 0kustomize 就认为转换过程发生错误。这五个假设在源码中有完整对应实现api/internal/plugins/execplugin/execplugin.go 的invokePlugin方法把插件配置写入一个以kust-plugin-config-为前缀的临时文件然后执行cmd : exec.Command(p.path, append([]string{f.Name()}, p.args...)...)即可执行文件 配置文件路径作为第一个参数同时把待转换资源放入cmd.Stdin并通过cmd.Dir p.h.Loader().Root()将插件工作目录设置为 kustomization 所在目录。插件 stdout 会被收集为转换结果非零退出码则触发错误包装并附带 stderr 内容Transform中对应fmt.Errorf(%v %s, err, string(output))的逻辑见同文件。第一步创建工作空间按下面的命令建立演示目录PLUGINDIR指向插件将来的存放位置DEMO_HOME$(mktemp -d) mkdir -p $DEMO_HOME/valid mkdir -p $DEMO_HOME/invalid PLUGINDIR$DEMO_HOME/kustomize/plugin/someteam.example.com/v1/validator mkdir -p $PLUGINDIR注意PLUGINDIR的路径形态plugin/someteam.example.com/v1/validator。其中someteam.example.com是插件配置里的apiVersion分组v1是版本validator是kind的小写形式。这正是 kustomize 定位外部插件的约定详见后文插件的发现机制。第二步下载 kubeval 并写入 $PATH按操作系统下载 kubeval 二进制并加入$PATHOSuname | sed -e s/Linux/linux/ -e s/Darwin/darwin/ wget https://github.com/instrumenta/kubeval/releases/download/0.9.2/kubeval-${OS}-amd64.tar.gz tar xf kubeval-${OS}-amd64.tar.gz export PATH$PATH:pwd第三步用 bash 编写 validator transformer 插件基于上面的运行协议可以用一个 bash 脚本充当 transformer 插件它从 stdin 读取资源、调用 kubeval 校验、按结果决定 stdout 输出与退出码。将脚本写入$PLUGINDIR/Validator并赋予可执行权限cat EOF $PLUGINDIR/Validator #!/bin/bash if ! [ -x $(command -v kubeval) ]; then echo Error: kubeval is not installed. exit 1 fi temp_file$(mktemp) output_file$(mktemp) cat - $temp_file kubeval $temp_file $output_file if [ $? -eq 0 ]; then cat $temp_file rm $temp_file $output_file exit 0 fi cat $output_file rm $temp_file $output_file exit 1 EOF chmod x $PLUGINDIR/Validator脚本逻辑拆解cat - $temp_file把 stdin 传入的资源暂存到临时文件因为 kubeval 接受的是文件路径而非 stdin 流kubeval $temp_file $output_file执行校验错误信息写入output_filekubeval 返回 0校验通过原样cat $temp_file把资源回写到 stdout并exit 0让 kustomize 继续后续转换kubeval 返回非 0校验失败cat $output_file输出错误日志exit 1让 kustomize 判定转换失败并终止构建。这种裸可执行文件是 kustomize 支持的插件风格之一。仓库 plugin/README.md 中将其归纳为三种风格裸可执行文件shell 脚本、Python、JVM 程序皆可接受 stdin 的 YAML 资源流、向 stdout 输出 YAML 流、以第一个命令行参数接收配置文件、KRM 函数容器化执行体要求ResourceList对象输入、以及 Go plugin.so共享库。本示例属于第一种也是门槛最低的一种。第四步编写使用插件的 kustomization有效 variant创建一个包含合法 ConfigMap 和 transformer 插件的 kustomizationcat EOF $DEMO_HOME/valid/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: cm data: foo: bar EOF cat EOF $DEMO_HOME/valid/validation.yaml apiVersion: someteam.example.com/v1 kind: Validator metadata: name: notImportantHere EOF cat EOF $DEMO_HOME/valid/kustomization.yaml resources: - configmap.yaml transformers: - validation.yaml EOF关键点validation.yaml中的apiVersion: someteam.example.com/v1与kind: Validator必须和插件目录someteam.example.com/v1/validator一一对应——kind小写化决定了插件目录名apiVersion决定了插件目录的上级路径。metadata.name内容不影响执行插件配置中也可以携带其他自定义字段供插件自身解析本例的 bash 脚本未读取配置文件内容。无效 variant再创建一个包含非法 ConfigMap 的 kustomization两者唯一区别是data字段的形态cat EOF $DEMO_HOME/invalid/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: cm data: - foo: bar EOF # ConfigMap 的 data 字段需要传入的数据类型为 object这里传入一个 array cat EOF $DEMO_HOME/invalid/validation.yaml apiVersion: someteam.example.com/v1 kind: Validator metadata: name: notImportantHere EOF cat EOF $DEMO_HOME/invalid/kustomization.yaml resources: - configmap.yaml transformers: - validation.yaml EOF目录结构总览此时工作空间的目录结构如下/tmp/tmp.fAYMfLZJs4只是mktemp -d生成的示例路径/tmp/tmp.fAYMfLZJs4 ├── invalid │ ├── configmap.yaml │ ├── kustomization.yaml │ └── validation.yaml ├── kustomize │ └── plugin │ └── someteam.example.com │ └── v1 │ ├── kubeval │ └── Validator └── valid ├── configmap.yaml ├── kustomization.yaml └── validation.yaml注意kustomize/plugin这个层级它对应插件主目录plugin home而$DEMO_HOME之所以被设为XDG_CONFIG_HOME正是为了让 kustomize 在这里发现插件详见后文。第五步用正确的环境和标志运行 kustomize外部非 builtin插件默认被禁用需要显式开启。定义一个 helper 函数在正确的环境变量和插件开关下执行构建function kustomizeBd { XDG_CONFIG_HOME$DEMO_HOME \ kustomize build \ --enable_alpha_plugins \ $DEMO_HOME/$1 }这里两个要素缺一不可XDG_CONFIG_HOME$DEMO_HOME把插件主目录指向$DEMO_HOME/kustomize/plugin。从源码 api/konfig/plugins.go 的DefaultAbsPluginHome可以看出kustomize 会依次尝试$KUSTOMIZE_PLUGIN_HOME、$XDG_CONFIG_HOME/kustomize/plugin、默认的~/.config/kustomize/plugin、以及$HOME/kustomize/plugin取第一个存在的目录作为插件根目录--enable_alpha_plugins将插件限制PluginRestrictions置为无限制从而允许加载非 builtin 插件。对应的底层约束在 api/internal/plugins/loader/loader.go 中当限制非PluginRestrictionsNone时插件主目录会被替换为哨兵路径/No/non-builtin/plugins!非 builtin 插件只有在无限制模式下才会走loadPlugin分支。构建结果有效资源放行无效资源报错构建有效 variantkustomizeBd valid输出的 ConfigMap 内容为apiVersion: v1 data: foo: bar kind: ConfigMap metadata: name: cm资源被 kubeval 判定合法后validator 脚本原样回写kustomize 正常完成渲染。构建无效 variantkustomizeBd invalid构建失败可以查看到输出错误日志为data: Invalid type. Expected: object, given: array这条错误信息来自 kubevalConfigMap的data字段应为 object示例中却被写成了 array- foo: bar是列表项语法。插件脚本因 kubeval 返回非 0 而exit 1kustomize 据此判定转换出错并终止构建从而在渲染阶段就拦截了非法资源。插件发现机制与源码级细节除了怎么用理解 kustomize 是怎么找到并执行这个插件的有助于排查插件不生效的问题。以 api/internal/plugins/loader/loader.go 为准链路如下kustomize 读取transformers:列表中的每个配置如validation.yaml得到其apiVersion与kind通过relativePluginPath拼出相对路径group/version/lowercase(kind)再以AbsolutePluginPath拼接到插件主目录下最终插件路径形如${pluginHome}/someteam.example.com/v1/validator/ValidatorloadExecOrGoPlugin先尝试把该路径当作可执行文件加载ErrIfNotExecutable检查执行位Windows 除外失败则回退尝试同名的.soGo 插件加载成功后把配置 YAML 序列化结果交给Config再以invokePlugin执行上述的临时配置文件 stdin stdout 退出码协议。此外执行插件时 kustomize 还会注入两个环境变量见 execplugin.go 的getEnvKUSTOMIZE_PLUGIN_CONFIG_STRING插件配置内容的字符串形式KUSTOMIZE_PLUGIN_CONFIG_ROOTkustomization 根目录。两者都有 131071 字符的硬上限超限时会被省略并打印日志。插件配置还支持两个可选特殊字段argsOneLiner以 shell 词法切分的单行参数见同目录 shlex.go和argsFromFile从文件逐行读取参数供不需要解析 YAML 的可执行程序使用——本例的 bash 脚本虽然未使用但它们是编写更复杂外部插件时的常用入口。测试验证仓库中的自动化用例该示例插件并非一次性演示仓库为其配套了 Go 单元测试 plugin/someteam.example.com/v1/validator/validator_test.goTestValidatorHappy通过PrepExecPlugin(someteam.example.com, v1, Validator)预置插件环境加载并运行 transformer断言合法 ConfigMap 原样通过TestValidatorUnHappy加载data为数组的非法 ConfigMap断言必然返回错误且错误信息包含failure in plugin configured via——这与invokePlugin中插件配置文件临时路径 失败包装的实现吻合可作为排查插件错误的定位线索。测试框架位于 api/testutils/kusttest任何自定义插件都可以参照该测试方式编写自己的回归用例。这也是 plugin/README.md 中无论插件用什么风格编写都应当配套使用 kustomize 维护者提供的框架编写 Go 单元测试这一约定的实际范例。清理演示结束后删除工作目录rm -rf $DEMO_HOME小结通过本示例可以总结出一条清晰的插件化验证路径写插件任何能从 stdin 读 YAML、向 stdout 写 YAML、按退出码上报成败的可执行文件都可以作为 kustomize transformer 插件放对位置按${pluginHome}/${apiVersion}/LOWERCASE(kind)的约定放置插件并通过XDG_CONFIG_HOME或KUSTOMIZE_PLUGIN_HOME指向插件主目录开启开关构建时加--enable_alpha_plugins否则外部插件会被 kustomize 拒绝加载接入构建在kustomization.yaml的transformers:中引用插件配置kubeval 的校验即成为构建流水线的强制关卡。这种模式不仅适用于校验同样的机制也可以用于注入注解、改写字段、执行任意策略检查等场景。想进一步了解插件体系全貌可继续阅读仓库中的 plugin/README.md 与 api/internal/plugins/loader/loader.go。【免费下载链接】kustomizeCustomization of kubernetes YAML configurations项目地址: https://gitcode.com/gh_mirrors/ku/kustomize创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表