Spinnaker Rosco 深入解析:基于 Packer 的机器镜像烘焙与 Helm/Kustomize 清单渲染服务
后端DevOps云原生微服务【免费下载链接】spinnakerSpinnaker is an open source, multi-cloud continuous delivery platform for releasing software changes with high velocity and confidence.项目地址https://gitcode.com/gh_mirrors/sp/spinnaker点击查看免费下载Rosco 是 Spinnaker 持续交付平台中的“烘焙坊”bakery微服务它负责调用 Hashicorp Packer 把基础镜像与待发布软件包合成为全新的机器镜像并调用 Helm、Kustomize 等模板引擎渲染 Kubernetes 部署清单。本文以仓库中的 rosco/README.md 为主干结合源码、配置模板与测试用例系统讲解 Rosco 的定位、REST API、请求字段、执行链路、配置方式与本地开发调试方法读完即可独立上手验证、运行与扩展这一服务。Rosco 在 Spinnaker 中的定位Rosco is Spinnakers bakery, producing machine images with Hashicorp Packer and rendered manifests with templating engines Helm and Kustomize.Rosco 的职责包含两个层面机器镜像烘焙Machine Image Baking以指定的基础镜像base image为起点通过 Packer 启动临时实例、执行软件包安装脚本产出新的机器镜像AMI、GCE 镜像、Azure 镜像等。清单渲染Manifest Rendering将模板化的 Kubernetes 部署清单结合输入参数渲染为最终可发布清单交付给下游部署流程。镜像烘焙链路中Rosco 目前支持以下云平台见 rosco/README.md 与 BakeRequest.groovy 中的CloudProviderType枚举Alibaba Cloudalicloud、AWSaws、Azureazure、Google Compute Enginegce、Huawei Cloudhuaweicloud、Oracleoracle、Tencent Cloudtencentcloud以及 Dockerdocker。其扩展性来自CloudProviderBakeHandler 抽象新增平台只需实现一个 bake handler 并注册到CloudProviderBakeHandlerRegistry无需改动核心烘焙流程。从代码结构看Rosco 是典型的多模块 Gradle 工程位于 monorepo 的rosco/目录下核心模块包括rosco-core领域模型api包、任务执行jobs、状态持久化persistence与各云平台 bake handlerprovidersrosco-webSpring Boot 入口与 REST 控制器controllersrosco-manifestsHelm / Kustomize / Helmfile / CloudFoundry 清单渲染服务rosco-bom依赖物料清单。对外 REST API 与 Swagger UIRosco 以 REST API 形式提供服务默认端口8087见 rosco-web/config/rosco.yml 中的server.port。启动后可访问 Swagger UI 交互式调试http://localhost:8087/swagger-ui.htmlSwagger 文档的启用与扫描范围由 rosco-web/config/rosco.yml 末尾的swagger段控制默认覆盖/api/v1.*、/api/v2.*、/bakeOptions.*、/status.*等路径模式。v1 烘焙 APIBakeryControllerBakeryControllerBakeryController.groovy暴露了镜像烘焙的完整端点集合方法路径说明GET/bakeOptions列出所有已注册云平台的可烘焙选项含基础镜像清单GET/bakeOptions/{cloudProvider}查询指定云平台的烘焙选项GET/bakeOptions/{cloudProvider}/baseImages/{imageId}查询指定基础镜像详情POST/api/v1/{region}/bake发起一次镜像烘焙支持rebake1强制重烤GET/api/v1/{region}/status/{statusId}按状态 ID 查询烘焙进度GET/api/v1/{region}/bake/{bakeId}查询烘焙结果详情含产出的镜像引用GET/api/v1/{region}/logs/{statusId}获取烘焙日志GET/api/v1/{region}/logs/image/{imageId}按镜像 ID 反查烘焙日志DELETE/api/v1/{region}/bake按 bakeKey 删除烘焙记录并取消对应任务POST/api/v1/bakes/delete-requests按 pipeline execution id 批量清理烘焙记录GET/api/v1/{region}/cancel/{statusId}取消一个进行中的烘焙其中核心的createBake流程值得展开控制器先校验/补齐cloud_provider_type缺省时使用default-cloud-provider-type配置默认aws见源码Value(${default-cloud-provider-type:aws})再通过produceBakeKey(region, bakeRequest)生成 bakeKey随后用 Redis 分布式锁acquireBakeLock保证同一 bakeKey 同时只有一个烘焙任务在跑若请求携带rebake1先删除旧烘焙记录并cancelJob取消旧进程否则查询同 bakeKey 下已有的 RUNNING 或 SUCCESS 状态任务命中则直接复用并返回既有BakeStatus避免重复烘焙并累加duplicate计数器获得锁后调用runBakejobExecutor.startJob(jobRequest)启动 Packer 子进程然后以rosco.polling.wait-for-job-start-timeout-millis默认 5000ms为窗口、每rosco.polling.wait-for-job-start-polling-interval-millis默认 500ms轮询一次任务是否已启动实现“快速失败”任务确认启动后写入BakeStatus到 Redis。v2 清单渲染 APIV2BakeryController针对 Helm / Kustomize 渲染场景V2BakeryControllerV2BakeryController.java提供统一入口POST /api/v2/manifest/bake/{type}{type}即模板渲染器类型控制器根据BakeManifestService.handles(type)从注入的ListBakeManifestService中挑选对应实现把请求体转换为该服务的请求类型后调用bake()并返回渲染产物Artifact。BakeRequest一次烘焙请求的完整字段请求体模型定义于 BakeRequest.groovy字段带 Swagger Schema 注解可作为 API 文档与调试参考。核心字段如下字段类型含义request_idString自动生成的 UUID作为烘焙任务的 jobId只读字段userString发起请求的用户packageString要安装的软件包名空格分隔package_artifactsListArtifact以 Spinnaker artifact 形式给出的软件包build_host/job/build_number/commit_hash/build_info_urlStringCI 构建信息构建主机、任务名、构建号、提交哈希、构建地址cloud_provider_type枚举alicloud / aws / azure / docker / gce / huaweicloud / oracle / tencentcloudbase_label枚举release / candidate / previous / unstable / foundationbase_osString从 Rosco 配置中解析的命名基础镜像 IDbase_nameString基础镜像名base_amiString显式指定基础机器镜像绕过配置解析vm_type枚举pv / hvmstore_type枚举ebs / s3 / dockerenhanced_networkingBoolean是否启用增强网络ami_name/ami_suffixString目标镜像名/后缀upgradeBoolean是否先升级系统再装包instance_typeString烘焙实例规格organizationString镜像所属组织template_file_nameString显式指定 Packer 模板文件extended_attributesMap追加到 Packer 命令的键值对var_file_nameString追加的变量文件JSON须与模板同目录account_nameString烘焙所用云账号publisher/offer/skuStringAzure 市场镜像三元组os_type枚举linux / windowspackage_type枚举RPM / DEB / NUPKG各自绑定对应的PackageUtil见 PackageUtil.java 的实现 Rpm/Deb/Nupkgcustom_managed_image_nameString自定义托管镜像名响应的BakeStatusBakeStatus.groovy包含id、stateRUNNING / COMPLETED / CANCELED、resultSUCCESS / FAILURE与resource_id——后者可传给lookupBake获取新镜像的引用信息。从请求到镜像一次烘焙的完整执行链路1. 生成 BakeRecipe控制器拿到BakeRequest后调用对应云平台的CloudProviderBakeHandler.produceBakeRecipe(region, bakeRequest)把请求翻译成一条可执行的命令。BakeRecipeBakeRecipe.groovy由name、version、commandtokenized 命令序列和可选的env环境变量组成。2. 构造 Packer 命令PackerCommandFactoryPackerCommandFactory.groovy负责把参数序列化为packer build命令行其默认实现LocalJobFriendlyPackerCommandFactoryLocalJobFriendlyPackerCommandFactory.groovy生成的命令形态为packer build -colorfalse [-timestamp-ui] [-var keyvalue ...] [-var-filepath] template-file其中-timestamp-ui仅当配置packer.timestamp: true时追加适用于 Packer 1.4.0additionalParameters可注入每次构建都携带的固定参数例如-on-errorabort配置位置见 rosco-web/config/rosco.yml 的packer段。3. 本地任务执行与状态持久化命令通过JobExecutor的本地实现JobExecutorLocalJobExecutorLocal.groovy以子进程方式执行超时默认 30 分钟rosco.jobs.local.timeoutMinutes: 30见 rosco-web/config/rosco.yml。任务状态与日志持久化在 RedisRedisBackedBakeStoreRedisBackedBakeStore.groovy实现BakeStore接口负责 bakeKey 锁、状态存取、日志存取与按 pipeline execution id 清理。BakePollerBakePoller.groovy后台周期性地轮询进行中的任务并把最新状态回写 Redis。这也是 README 强调“Rosco 需要本地 Redis 实例”的原因。4. 镜像内软件包安装无论是 AWS 的aws-ebs.json、GCE 的gce.json还是其他模板Packer 的 provisioner 都会执行统一的安装脚本 install_packages.sh。该脚本按package_type分发deb把repository写入/etc/apt/sources.list.d/spinnaker.listapt-get update后按序安装packages与 artifact 引用的包upgradetrue时先执行unattended-upgrade支持disable_services时创建/usr/sbin/policy-rc.d抑制服务自启适配 chroot 构建rpm生成/tmp/spinnaker-ts.repo并移动到/etc/yum.repos.d/随后yum install脚本会先用jq解析/tmp/artifacts.json中 artifact 的reference形如“仓库 包名”解析后卸载 jq避免把临时工具遗留进镜像。5. 镜像产物回传构建成功后Packer 的manifestpost-processor见 gce.json 中的post-processors输出 JSON manifestRosco 通过PackerManifestServicePackerManifestService.java解析并入库最终由lookupBake端点把对应 region 的镜像引用AMI ID 等返回给上层编排如 Orca / Deck。Manifest 渲染Helm 与 Kustomize 的实现细节清单渲染统一继承抽象类BakeManifestServiceBakeManifestService.java其doBake与 v1 镜像烘焙共用JobExecutor启动任务后每秒轮询BakeStatus直至非 RUNNING失败则抛出携带日志的异常成功则返回渲染输出。HelmHelmBakeManifestServiceHelmBakeManifestService.java同时支持HELM2与HELM3两种渲染器输入HelmBakeManifestRequestHelmBakeManifestRequest.java可携带apiVersions、kubeVersion、namespace、rawOverrides、includeCRDsHelm v3 是否包含 CRD 清单以及helmChartFilePathchart 位于 git/repo artifact 子目录时指定Chart.yaml路径等参数渲染结果以embedded/base64类型的 artifact 返回并剥离tests/目录下的模板。KustomizeKustomizeBakeManifestServiceKustomizeBakeManifestService.java支持KUSTOMIZEv3、KUSTOMIZE4、KUSTOMIZE5三类渲染器并配套KustomizationFileReader与 ConfigMapGenerator 等映射工具见 kustomize/mapping。此外还内置helmfile与cloudfoundry渲染服务分别位于 helmfile 与 cloudfoundry。容器镜像中这些工具的版本由 Dockerfile.ubuntu 统一固定Packer 1.15.4、Helm 2.17.0 与 Helm 3、kustomize 3.9.4 / 4.5.7 / 5.8.1、helmfile 1.7.0且以packer plugins install方式安装 amazon / azure / googlecompute 插件——若在本地手动复现需按相同方式准备 Packer 及其插件。本地开发与运行指南Rosco 位于本 monorepo 的rosco/目录但所有./gradlew命令都必须从monorepo 根目录执行而不是从rosco/内部执行完整构建/测试/运行命令见根目录 CLAUDE.md。1. 准备本地 RedisRosco 依赖 Redis 存放烘焙状态与锁先启动一个本地实例docker run -d -p 6379:6379 redisRedis 连接地址可在 halconfig/rosco.yml 中通过redis.connection配置覆盖默认redis://localhost:6379。需要注意的是Rosco 并不复用 Halyard 默认部署的 Redis而是独立连接redis://localhost:6379因此本地调试时必须自行启动 Redis。2. IDE 环境准备生成 IntelliJ Gradle 工程文件./gradlew idea应用 Groovy 代码格式化方案Preferences - Editor - Code Style - Manage ... - Import选择项目根目录的 codestyle.xml应用spinnaker代码风格方案。3. 启动服务./gradlew rosco4. 调试模式通过 Java 系统属性DEBUGtrue以调试模式启动 JVM./gradlew rosco -DDEBUGtrueJVM 会在8187 端口监听调试器连接注意不会等待调试器接入才启动 Rosco相关 JVM 参数可在rosco-web/build.gradle中查看与调整。5. 验证服务服务启动后用 curl 验证烘焙选项端点curl -v localhost:8087/bakeOptions该端点由BakeryController.bakeOptions()实现遍历CloudProviderBakeHandlerRegistry中所有已注册 handler返回各自getBakeOptions()包含cloudProvider与baseImages列表模型见 BakeOptions.groovy。6. 收尾停止 Docker 容器调试结束后停止并清理本地 Redis 容器docker stop redis-container-id配置要点启用云平台、基础镜像与软件源各云平台的启用开关与基础镜像定义集中在 rosco-web/config/rosco.ymlhalconfig 侧另有 images.yml 作为参考样本。关键配置项启用开关每个云平台默认禁用如aws.enabled: ${AWS_ENABLED:false}、google.enabled: ${GOOGLE_ENABLED:false}。若在预构建 Spinnaker 镜像中使用需将AWS_ENABLED等替换为SPINNAKER_AWS_ENABLED形式的环境变量或显式置为true。默认模板如aws.bakeryDefaults.templateFile: aws-ebs.json若要使用镜像共享/复制能力可切换为aws-multi-ebs.json或aws-multi-chroot.json此时还需设置SPINNAKER_AWS_DEFAULT_ACCOUNT环境变量为 Spinnaker 实例所在 AWS 账号 ID。相关模板文件位于 rosco/halconfig/packer。基础镜像baseImages每个条目包含id、shortDescription、detailedDescription、packageType、可选的templateFile、osType与customRepository以及按区域细分的virtualizationSettings如 AWS 的sourceAmi/instanceType/sshUserName/spotPriceAzure 的publisher/offer/skuGCE 的sourceImage或sourceImageFamily。GCE 支持isImageFamily: true表示按镜像族解析Deck 会在 UI 上据此标注。Packer Spot 价格AWSspotPrice设为auto时自动探测最优价格此时必须同时配置spotPriceAutoProduct取值如Linux/UNIX (Amazon VPC)、Windows (Amazon VPC)等设为0则使用按需实例默认。软件源仓库可在rosco.yml顶层配置debianRepository/yumRepository/chocolateyRepository每个类型支持分号分隔的多个仓库烘焙 deb/rpm/nupkg 镜像时注入也可在单条 baseImage 上通过customRepository覆盖。需要 root 的模板templatesNeedingRoot: aws-chroot.json列出的模板要求/usr/bin/packer以 sudo 运行。若使用此类模板需在/etc/sudoers.d/spinnaker中添加spinnaker ALL(ALL) NOPASSWD: /usr/bin/packer该文件同时给出安全警告——为 spinnaker 用户授予 packer 的 sudo 权限可能带来被恶意利用的风险。Packer 版本适配packer.timestamp在 Packer 1.4.0 时建议置true以获得带时间戳前缀的输出packer.additionalParameters可追加每次构建都生效的参数。扩展新云平台CloudProviderBakeHandler 抽象Rosco 的云平台支持是可插拔的。核心抽象接口CloudProviderBakeHandlerCloudProviderBakeHandler.groovy定义了getBakeOptions()、produceBakeKey(region, request)、produceBakeRecipe(region, request)与getMaskedPackerParameters()等方法现有实现如 AWSBakeHandler.groovy、GCEBakeHandler.groovy、AliCloudBakeHandler.java、TencentCloudBakeHandler.java 等均通过DefaultCloudProviderBakeHandlerRegistry注册并被BakeryController通过lookup(cloudProvider)按类型查找。每个 handler 配套的 Spock 测试如 AWSBakeHandlerSpec.groovy、GCEBakeHandlerSpec.groovy与控制器测试BakeryControllerSpec.groovy验证了 bakeKey 生成、Packer 命令组装与去重/重烤语义可作为新增平台时的实现范本。若要接入新平台从源码结构看需要新增一个实现CloudProviderBakeHandler的 handler 类编写对应的 Packer 模板放入 rosco/halconfig/packer在 rosco-web/config/rosco.yml 中补充bakeryDefaults与enabled开关并在BakeRequest.CloudProviderType枚举中登记新类型。核心的烘焙、轮询、存储链路无需改动。小结Rosco 以“Packer 烘焙镜像 模板引擎渲染清单”双能力支撑 Spinnaker 的持续交付对外通过/bakeOptions、/api/v1/{region}/bake与/api/v2/manifest/bake/{type}提供统一 REST 入口对内以CloudProviderBakeHandler实现多云抽象、以 Redis 实现任务状态与锁、以JobExecutor驱动本地 Packer 子进程。开发与调试时只需一条 Redis 容器、一个./gradlew rosco命令即可快速起服并通过curl -v localhost:8087/bakeOptions或 Swagger UIhttp://localhost:8087/swagger-ui.html完成交互验证。赞分享后端DevOps云原生微服务【免费下载链接】spinnakerSpinnaker is an open source, multi-cloud continuous delivery platform for releasing software changes with high velocity and confidence.项目地址https://gitcode.com/gh_mirrors/sp/spinnaker点击查看免费下载相关推荐Spinnaker Rosco halconfig 配置骨架解析Halyard 拼接机制、弃用迁移与烘焙默认值配置指南Spinnaker Rosco halconfig 配置骨架解析Halyard 拼接机制、弃用迁移与烘焙默认值配置指南 本文围绕 Spinnaker 开源仓库后端DevOps云原生微服务Entities Graphics URP 光照探针Light Probes示例深度解析基于 URPSamples Lightprobes 场景的烘焙与渲染实践Entities Graphics URP 光照探针Light Probes示例深度解析基于 URPSamples Lightprobes 场景的烘焙与渲示例工程深入解读 HashiCorp Packer从单一配置构建多平台机器镜像深入解读 HashiCorp Packer从单一配置构建多平台机器镜像 导读 本文以本仓库HashiCorp Packer 官方开源仓库的 README.云原生DevOps运维上一篇Paddle Lite 程序开发全流程指南从模型转换到端侧推理下一篇Fleet 可观测性属性命名规范日志、Trace 与 Metrics 的统一命名指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考