- 后端
- DevOps
- 云原生
- 微服务
【免费下载链接】spinnaker
Spinnaker is an open source, multi-cloud continuous delivery platform for releasing software changes with high velocity and confidence.
本文围绕 Spinnaker 开源仓库rosco/halconfig目录展开,系统讲解 Rosco(镜像烘焙服务)骨架配置文件的定位、Halyard 部署时配置拼接的工作原理、该目录当前的弃用状态,以及在现代 Rosco 版本中设置默认配置值的正确姿势——涵盖 halconfig 目录、halconfig/rosco.yml、halconfig/images.yml 与 packer 模板目录 的全部内容,并对照 rosco-core 源码 给出实现级证据。读完本文,你将掌握 Rosco 烘焙配置的来龙去脉,能够正确判断哪些配置该写进 halconfig、哪些该迁移到rosco-web/config/rosco.yml或代码默认值,并理解 packer 模板与bakeryDefaults的配合关系。
一、halconfig 目录是什么:Rosco 的“骨架配置”
rosco/halconfig/README.md开门见山地说明了该目录的定位:
This directory contains a skeleton rosco config to which Halyard concatenates its generated deployment-specific config.
即rosco/halconfig存放的是 Rosco 的骨架(skeleton)配置,Halyard(Spinnaker 部署管理工具)在生成部署专属配置时,会把两部分内容**拼接(concatenate)**到一起:骨架配置提供通用默认值,Halyard 生成的配置提供当前部署环境的具体值。这与 Spinnaker 其他微服务的 halconfig 目录设计一脉相承。
当前目录内共包含三类文件:
| 文件 | 作用 |
|---|---|
| README.md | 目录用途与弃用说明 |
| rosco.yml | 骨架主配置:redis、server、以及各云厂商的bakeryDefaults |
| images.yml | 更早期的骨架镜像配置(同样已弃用) |
| packer/ | Rosco 使用的 Packer 构建模板与安装脚本 |
骨架配置中的环境变量占位符
halconfig/rosco.yml 的最典型特征是大量使用${...}占位符,其中一部分引用 Halyard 生成的服务配置,另一部分引用环境变量:
redis: connection: ${services.redis.baseUrl:redis://localhost:6379} server: port: ${services.rosco.port:8087} address: ${services.rosco.host:localhost}${services.redis.baseUrl:redis://localhost:6379}:优先取 Halyard 生成的services.redis.baseUrl,取不到时回退到redis://localhost:6379;${services.rosco.port:8087}:取 Halyard 的services.rosco.port,默认回退8087(即 Rosco 的默认 HTTP 端口);${services.rosco.host:localhost}:绑定地址默认localhost。
这一设计正是“骨架 + Halyard 拼接”的直观体现:骨架文件用带默认值的占位符描述通用行为,具体部署值由 Halyard 注入。
二、重要现状:halconfig 配置已被弃用
README 同时给出了明确的弃用声明,这是理解该目录时最重要的一点:
These configs aredeprecatedand in general should not be further updated. To set a default config value, either set the value in
rosco-web/config/rosco.ymlor set a default in the code reading the config property.
即rosco/halconfig下的配置已弃用,原则上不应继续更新。需要设置默认配置值时,官方推荐两条迁移路径:
- 在 rosco-web/config/rosco.yml 中设置默认值——这是当前 Rosco 运行时真正加载的配置文件;
- 在读取该配置属性的代码中设置默认值——即 Spring 的
${property:defaultValue}语法或代码内直接兜底。
为什么会有这种迁移?
从部署视角看,Rosco 的镜像内实际使用的配置位于/opt/rosco/config/,而 halconfig 中的内容只服务于 Halyard 拼接流程。随着 Spinnaker 部署模型向"统一配置(unified config)"演进,halconfig 骨架的维护成本与歧义(例如多份 yml 的默认值到底以谁为准)超过了它的价值,因此社区选择收敛配置入口。halconfig/images.yml同样处于弃用状态,它列出的 AWS/Azure/Docker/GCE 基础镜像定义,在 halconfig/rosco.yml 中已有更完整的对应版本。
三、当前权威配置入口:rosco-web/config/rosco.yml
按 README 的指引,rosco-web/config/rosco.yml 才是现版本应维护默认值的位置。它涵盖了骨架配置的全部核心项,并补充了 halconfig 中没有的细节,逐项说明如下。
3.1 服务端口与烘焙目录
server: port: 8087 rosco: configDir: /opt/rosco/config/packer jobs: local: timeoutMinutes: 30server.port:Rosco HTTP 端口,默认8087(Dockerfile 的健康检查也探测该端口);rosco.configDir:Packer 模板与脚本所在目录。镜像内固定为/opt/rosco/config/packer,由 Dockerfile.ubuntu 第 78 行COPY halconfig/packer /opt/rosco/config/packer把本仓库的 packer 目录拷入镜像,configDir最终会以{{user \configDir`}}` 形式注入每个 Packer 模板;rosco.jobs.local.timeoutMinutes:本地 Job 执行的超时时间,默认 30 分钟,防止烘焙任务悬挂。
在源码侧,CloudProviderBakeHandler.groovy 通过@Value('${rosco.config-dir}')读取该路径,并在produceBakeRecipe中拼接出模板文件的完整路径:"$configDir/$finalTemplateFileName",再交给PackerCommandFactory生成最终的packer build命令。
3.2 Packer 行为参数
packer: # Set this if running Packer >= 1.4.0 for timestamp prepended output timestamp: false # Add additional parameters that will always be passed to "packer build" here # additionalParameters: # - on-error=abort # - -var "bakedBy=Rosco"packer.timestamp:Packer 1.4.0+ 起,构建日志会自带时间戳前缀,Rosco 解析日志时按此开关适配;packer.additionalParameters:需要无条件附加到每次packer build的参数列表,例如on-error=abort(失败即中止)或自定义-var。
3.3 软件源仓库(debian / yum / chocolatey)
# debianRepository: http://dl.bintray.com/spinnaker/ospackages trusty main;http://other.repo.com/repo/packages trusty main # yumRepository: https://jfrog.bintray.com/yum/repos/some-package # chocolateyRepository: https://chocolatey.org/api/v2/debianRepository:烘焙 Debian 系镜像时追加到/etc/apt/sources.list.d/spinnaker.list的 apt 源,多个源用分号分隔;yumRepository:烘焙 RPM 系镜像时写入/etc/yum.repos.d/的 yum 源;chocolateyRepository:烘焙 NuGet 系(Windows)镜像时的 chocolatey 源;- 均支持空格分隔的多源列表,并且可以在某个
baseImage上通过customRepository覆盖全局配置。
源码印证见 CloudProviderBakeHandler.groovy:三个仓库分别由@Value('${debian-repository:}')、@Value('${yum-repository:}')、@Value('${chocolatey-repository:}')注入,在produceBakeRecipe中按packageType(DEB/RPM/NUPKG)选择对应仓库写入parameterMap.repository,最终传给模板中的install_packages.sh。
3.4 默认云厂商与需要 root 的模板
defaultCloudProviderType: aws templatesNeedingRoot: aws-chroot.jsondefaultCloudProviderType:未显式指定云厂商时的默认值,本仓库中为aws;templatesNeedingRoot:列出需要以 root 身份执行/usr/bin/packer的模板(本仓库为aws-chroot.json,chroot 构建必须挂载块设备)。Rosco 默认以spinnaker用户运行、无 sudo 权限,因此使用这些模板前需在/etc/sudoers.d/spinnaker中添加:
spinnaker ALL=(ALL) NOPASSWD: /usr/bin/packerREADME 与配置注释均特别提示:为 spinnaker 授予 packer 的免密 sudo 存在被恶意利用控制机器的风险,需谨慎评估。源码侧,CloudProviderBakeHandler.groovy 将templates-needing-root读取为列表,并在getBaseCommand中判断:若模板文件名命中列表,则在 packer 命令前加sudo前缀,否则为空串。
四、bakeryDefaults:各云厂商的基础镜像骨架
halconfig/rosco.yml 的主体是按云厂商划分的bakeryDefaults配置(在rosco-web/config/rosco.yml中缺失的部分在此补全),其通用结构为:
<provider>: enabled: ${<PROVIDER>_ENABLED:false} bakeryDefaults: templateFile: <模板文件名> baseImages: - baseImage: id: <镜像 ID,即 base_os> shortDescription: ... detailedDescription: ... packageType: deb | rpm | nupkg virtualizationSettings: - region: ... instanceType: ... sourceImage / sourceAmi / sourceImageId: ... sshUserName: ...4.1 统一的启用开关与条件装配
每个厂商都以enabled: ${XXX_ENABLED:false}开头(如${AWS_ENABLED:false}、${GOOGLE_ENABLED:false}、${DOCKER_ENABLED:false})。这个开关在源码中对应 Spring 的@ConditionalOnProperty:
- RoscoAWSConfiguration.groovy 标注
@ConditionalOnProperty('aws.enabled'); - AWSBakeryDefaultsBean.java 同样以
@ConditionalOnProperty("aws.enabled")控制awsBakeryDefaultsBean,并通过@ConfigurationProperties("aws.bakery-defaults")将 yml 中的aws.bakeryDefaults段映射为配置对象。
也就是说,只有对应enabled: true的厂商才会装配BakeHandler与默认值 Bean,并在@PostConstruct阶段注册进 DefaultCloudProviderBakeHandlerRegistry。
注意:配置注释特别提醒,XXX_ENABLED这类环境变量并不在 spinnaker/spinnaker 项目的 unified config 中定义。若要把本段配置拷贝到预构建镜像的rosco-local.yml,必须把AWS_ENABLED换成SPINNAKER_AWS_ENABLED(其他厂商同理),或显式设enabled: true。
4.2 AWS:最完整的骨架示例
AWS 段的bakeryDefaults覆盖了模板选择、虚拟化类型与竞拍价:
aws: enabled: ${AWS_ENABLED:false} bakeryDefaults: awsAssociatePublicIpAddress: true templateFile: aws-ebs.json defaultVirtualizationType: hvm baseImages: - baseImage: id: ubuntu shortDescription: v12.04 detailedDescription: Ubuntu Precise Pangolin v12.04 packageType: deb templateFile: aws-ebs.json virtualizationSettings: - region: us-east-1 virtualizationType: hvm instanceType: t2.micro sourceAmi: ami-d4aed0bc sshUserName: ubuntu spotPrice: 0 spotPriceAutoProduct: Linux/UNIX (Amazon VPC)关键参数含义:
awsAssociatePublicIpAddress:构建实例是否分配公网 IP(默认true);templateFile:默认 Packer 模板,AWS 默认aws-ebs.json;注释指出需要share_with/copy_to能力时应换成aws-multi-ebs.json,此时还需设置环境变量SPINNAKER_AWS_DEFAULT_ACCOUNT(要共享 AMI 的账号 ID)与SPINNAKER_AWS_DEFAULT_REGION;defaultVirtualizationType:默认虚拟化类型hvm(对应源码 AWSBakeryDefaultsBean.java 中${aws.bakery-defaults.default-virtualization-type:hvm}的读取与兜底);spotPrice:竞拍价上限,auto表示自动探测最优竞拍价,0表示按需实例(默认);spotPriceAutoProduct:使用spotPrice: auto时的必填项,取值限定为Linux/UNIX、Linux/UNIX (Amazon VPC)、SUSE Linux、Windows、Windows (Amazon VPC)等;- 每个
virtualizationSettings由region + virtualizationType + instanceType + sourceAmi + sshUserName唯一确定一种可烘焙镜像组合,同一baseImage下可并列多个 region 与虚拟化类型(如 hvm 用t2.micro、pv 用m3.medium)。
配置注释还说明:baseImage级可覆盖默认模板(templateFile)与全局软件源(customRepository),例如customRepository: http://dl.bintray.com/spinnaker/ospackages bionic main。
4.3 Google(GCE):镜像族与镜像二选一
google: enabled: ${GOOGLE_ENABLED:false} bakeryDefaults: zone: us-central1-f network: default useInternalIp: false templateFile: gce.json baseImages: - baseImage: id: xenial shortDescription: v16.04 detailedDescription: Ubuntu Xenial Xerus v16.04 packageType: deb isImageFamily: true virtualizationSettings: sourceImageFamily: ubuntu-1604-ltssourceImage与sourceImageFamily二选一,同时设置时sourceImage优先;isImageFamily: true时 Deck 会在 UI 提示该选项代表"镜像族"而非具体镜像;zone、network、useInternalIp为 GCE 构建实例的默认参数。
4.4 Azure:publisher / offer / sku 三元组
azure: enabled: ${AZURE_ENABLED:false} bakeryDefaults: templateFile: azure-linux.pkr.hcl baseImages: - baseImage: id: ubuntu-1604 shortDescription: v16.04 detailedDescription: Ubuntu Server 16.04-LTS publisher: Canonical offer: UbuntuServer sku: 16.04-LTS version: 16.04.201612140 osType: Linux packageType: debAzure 的源镜像通过 Marketplace 的publisher/offer/sku/version描述,Windows 基础镜像额外指定templateFile: azure-windows.pkr.hcl与packageType: nupkg。同时注意仓库中已同时提供 azure-linux.pkr.hcl 与更新的托管镜像版本 azure-linux-managed-image.pkr.hcl。
4.5 Docker:最简烘焙模型
docker: enabled: ${DOCKER_ENABLED:false} bakeryDefaults: targetRepository: ${DOCKER_TARGET_REPOSITORY:} templateFile: docker.json baseImages: - baseImage: id: precise shortDescription: v12.04 detailedDescription: Ubuntu Precise Pangolin v12.04 packageType: deb virtualizationSettings: sourceImage: ubuntu:preciseDocker 烘焙以sourceImage(基础镜像 tag)为输入、targetRepository(目标仓库)为输出,不涉及 region 与实例类型。
4.6 阿里云 / 华为云 / 腾讯云
- 阿里云(alicloud):以
region + instanceType + sourceImage + sshUserName定义,如cn-hangzhou区域ecs.c5.large实例、ubuntu_16_04_64_20G_alibase_20190620.vhd源镜像,模板 alicloud.json; - 华为云(huaweicloud):
bakeryDefaults中直接包含一组认证与网络参数占位符:authUrl、username、password、projectName、domainName、insecure、vpcId、subnetId、eipBandwidthSize(默认 2)、securityGroup,源镜像以不可变的 UUID(sourceImageId)标识,可在控制台或镜像 API 查询; - 腾讯云(tencentcloud):
secretId、secretKey认证,virtualizationSettings含region/zone/instanceType/sourceImageId/sshUsername,覆盖 Ubuntu 16.04、Debian 9.0、CentOS 7.6 三类基础镜像。
4.7 一份独立的镜像清单:images.yml
halconfig/images.yml 是更早形态的骨架镜像定义,结构与bakeryDefaults.baseImages一致(AWS 的 ubuntu/trusty/windows-2012-r2、Azure 的五个 Marketplace 镜像、Docker 的 precise/trusty、GCE 的 xenial/bionic 镜像族)。它与 halconfig/rosco.yml 存在部分重复,同样随目录整体弃用,阅读时应以rosco.yml中的bakeryDefaults为准。
五、Packer 模板骨架:烘焙命令的落地形态
rosco/halconfig/packer存放的是直接喂给 Packer 的构建模板与脚本。它们遵循"变量占位符 + 统一安装脚本"模式:所有运行时值通过{{user \xxx`}}` 注入,软件安装统一走 install_packages.sh。
5.1 统一的变量契约
以 aws-ebs.json 为例,其variables定义了各云厂商模板共通的契约字段:
| 变量 | 含义 |
|---|---|
appversion/build_host/build_info_url | 写入镜像标签/描述的构建元数据 |
repository | 本次烘焙使用的软件源(由 3.3 节的仓库配置决定) |
package_type | deb/rpm/nupkg |
packages | 要安装的包名(空格分隔) |
upgrade | 是否先执行系统升级(unattended-upgrade/yum update) |
configDir | 模板与脚本所在目录,用于定位install_packages.sh |
aws-ebs.json使用amazon-ebsbuilder,把source_ami烘焙为ami_name,并把appversion、build_host、build_info_url写入 AMI 标签、packages写入运行标签;aws-subnet_id/aws_vpc_id默认从环境变量AWS_SUBNET_ID/AWS_VPC_ID读取。
5.2 各模板的差异定位
- aws-chroot.json:
amazon-chrootbuilder,直接在块设备上烘焙、不启动实例,因此需要 root 权限(对应templatesNeedingRoot),并通过disable_services=true环境变量让install_packages.sh临时创建/usr/sbin/policy-rc.d阻止服务自动启动(规避 chroot 环境中的服务启动坑); - aws-multi-ebs.json:在
aws-ebs.json基础上增加ami_users(share_with_1..10,默认全部为SPINNAKER_AWS_DEFAULT_ACCOUNT)与ami_regions(copy_to_1..5,默认全部为SPINNAKER_AWS_DEFAULT_REGION),实现 AMI 跨账号共享与跨区域复制;aws-multi-chroot.json 为对应 chroot 版本; - aws-windows-2012-r2.json:Windows 基础镜像,配合 packer/scripts 下的 PowerShell 脚本(如
windows-install-packages.ps1、windows-configure-chocolatey.ps1)完成 NuGet 包安装; - gce.json:
googlecomputebuilder,支持artifactFile文件 provisioner(把 artifacts 传入/tmp/artifacts.json)与manifestpost-processor 输出manifestFile,供 PackerManifestService 解析烘焙产物 ID; - docker.json:
dockerbuilder +docker-tag/docker-pushpost-processor,把基础镜像安装包后提交为新镜像并推送至docker_target_repository; - azure-linux.pkr.hcl:采用 Packer HCL2 语法(
source "azure-arm"+build块),变量以sensitive = true声明azure_client_id/azure_client_secret防止日志泄露,并在构建末尾执行waagent -force -deprovision+user完成 Azure 镜像通用化。
5.3 install_packages.sh:烘焙过程中的"安装引擎"
install_packages.sh 是所有模板共用的软件安装脚本,核心逻辑:
set -e保证构建失败即中止;- 先打印脱敏后的
repository(用sed s/^.*@//g剥离凭据部分),避免仓库 URL 中的凭据泄漏; get_artifact_references:把仓库列表写入/tmp/repos,若存在/tmp/artifacts.json(GCE 等通过 file provisioner 传入的工件清单),用jq解析每个 artifact 的reference——最后一段是包名、其余段是安装源;provision_deb:向/etc/apt/sources.list.d/spinnaker.list追加 deb 源,upgrade=true时执行unattended-upgrade -v,然后按顺序apt-get install各包,结束后清理源文件;provision_rpm:为每个源生成/tmp/spinnaker-<ts>-<i>.repo并移入/etc/yum.repos.d/,upgrade=true时yum update,再逐个yum install;disable_services=true时(chroot 模板)创建/移除policy-rc.d以控制服务启动。
六、从源码看配置如何被消费:一次烘焙的完整链路
把配置文件与源码串起来,一次烘焙请求的消费链路如下(对应 CloudProviderBakeHandler.groovy 的produceBakeRecipe):
- 读取烘焙默认值:
getBakeryDefaults()返回由@ConfigurationProperties("aws.bakery-defaults")等映射的bakeryDefaults对象(仅在xxx.enabled=true时装配,见 RoscoConfiguration.groovy 与各厂商 Configuration); - 匹配基础镜像:
findBaseImage按bakeRequest.base_os在baseImages中查找id匹配项,找不到则抛IllegalArgumentException; - 定位虚拟化设置:
findVirtualizationSettings(region, bakeRequest)根据 region 与请求参数选择对应的virtualizationSettings; - 组装参数:
buildParameterMap把 region、实例类型、源镜像等填入模板变量;repository按 packageType 从全局仓库或customRepository决定; - 拼接命令:
getBaseCommand按templatesNeedingRoot决定是否加sudo,PackerCommandFactory.buildPackerCommand生成完整packer build命令,configDir作为变量一并传入; - 注册与执行:厂商配置在
@PostConstruct中把BakeHandler注册进 DefaultCloudProviderBakeHandlerRegistry,由 Rosco API 分派执行。
此外,RoscoConfiguration中的 BakeStore 基于 Jedis 使用 Redis 记录烘焙状态,这也解释了骨架配置中redis.connection为什么是必须项——Rosco 不依赖 Halyard 默认的 Redis 部署,而是直接连接redis://localhost:6379(可经${services.redis.baseUrl}覆盖)。
七、实战建议:面对 halconfig 该怎么做
基于 README 的弃用声明与仓库现状,落地时建议遵循以下原则:
- 不再修改 halconfig:
rosco/halconfig下的rosco.yml、images.yml保留只读,作为理解烘焙默认值历史形态与迁移的参考; - 默认值写到 rosco-web/config/rosco.yml:新增厂商默认值、模板默认值、仓库配置等一律落到 rosco-web/config/rosco.yml;
- 环境变量启用厂商:在部署环境设置
SPINNAKER_AWS_ENABLED=true等(对应enabled: ${AWS_ENABLED:false}的占位符),而非直接改 halconfig; - 模板与脚本随镜像分发:
packer/目录经 Dockerfile.ubuntu 拷贝到/opt/rosco/config/packer,若要自定义模板,应在构建镜像时替换该目录内容,并保持变量契约(configDir、repository、package_type、packages、upgrade)不变; - root 权限按需最小化:仅当确实使用
aws-chroot.json等需要 root 的模板时,才按 3.4 节配置 sudoers 规则,并充分评估安全风险。
结语
rosco/halconfig是 Spinnaker Rosco 服务配置体系从"Halyard 拼接骨架"向"统一配置文件 + 代码默认值"演进的历史见证。理解它的定位与弃用逻辑,能帮助你在实际部署中快速判断:默认值应写进 rosco-web/config/rosco.yml,厂商开关应通过环境变量控制,而bakeryDefaults与 packer 模板的配合关系(baseImage匹配 →virtualizationSettings定位 →parameterMap组装 →install_packages.sh安装)则构成了 Rosco 镜像烘焙能力的完整闭环。
- 后端
- DevOps
- 云原生
- 微服务
【免费下载链接】spinnaker
Spinnaker is an open source, multi-cloud continuous delivery platform for releasing software changes with high velocity and confidence.
相关推荐
Spinnaker Echo halconfig 配置骨架解析:Halyard 拼接机制、弃用策略与默认值设置规范
Spinnaker Echo halconfig 配置骨架解析:Halyard 拼接机制、弃用策略与默认值设置规范 Echo 是 Spinnaker 多集群持续
后端DevOps云原生微服务Spinnaker Orca 的 Halyard 骨架配置(halconfig)解析与弃用迁移指南
Spinnaker Orca 的 Halyard 骨架配置(halconfig)解析与弃用迁移指南 导读 orca/halconfig/ 目录保存的是 Orca
后端DevOps云原生微服务Pot 划词翻译完整指南:跨平台 OCR 与翻译开箱即用
Pot 划词翻译完整指南:跨平台 OCR 与翻译开箱即用 Pot 是一款开源免费的跨平台划词翻译与 OCR 工具,Windows、macOS、Linux 通用。
后端DevOps云原生微服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考