SkyPilot 配置来源与覆盖机制详解:从用户配置到 CLI 覆盖的完整优先级体系
【免费下载链接】skypilotThe AI Compute Platform for frontier teams. SkyPilot turns fragmented AI compute into one AI supercomputer, so frontier AI teams build custom intelligence faster.项目地址: https://gitcode.com/GitHub_Trending/sk/skypilot
SkyPilot 允许通过多种来源设置配置,并实现了一套带优先级的合并机制来分层组合它们:管理员可以在 API 服务器上定义全局默认值,团队可以在项目目录中存放共享默认值,而单个任务可以通过 Task YAML 的config字段或 CLI 的--config参数实现按任务覆盖。读完本文,你将掌握 SkyPilot 五种配置来源的确切位置与作用域、从低到高的覆盖优先级规则、列表与字典各自的合并语义,以及如何用命令行点号键值对(dotlist)精准覆盖任意深层配置项。
上图(仓库中同时提供明暗两个版本:config-cheatsheet-light.svg与config-cheatsheet-dark.svg)直观展示了各配置层的位置与优先级关系,下文将逐一展开。
配置来源总览:五层配置各司其职
SkyPilot 的配置可以来自五个不同的来源,每一层的作用域由粗到细逐步收窄:
| 配置类型 | 配置位置 | 说明 |
|---|---|---|
| Server configuration | API 服务器上的~/.sky/config.yaml | 应用于发送到 SkyPilot API 服务器的所有请求 |
| User configuration | ~/.sky/config.yaml | 应用于本机所有 SkyPilot 调用 |
| Project configuration | $pwd/.sky.yaml | 应用于当前目录下的所有 SkyPilot 调用 |
| SkyPilot YAML | SkyPilot YAML 文件中的config字段 | 应用于某个特定的 SkyPilot 任务 |
| CLI flags | 使用--configCLI 参数 | 覆盖特定命令的配置 |
所有配置来源都遵循相同的配置语法(完整字段定义见 高级配置文档)。需要特别注意的是:任何新的配置变更都不会影响已经存在的集群——配置在集群创建时被捕获,后续修改配置只会作用于新启动的任务。
当多个来源同时指定了配置时,SkyPilot 会按照后文所述的优先级机制进行合并(merge),而不是简单丢弃低优先级来源中的其余字段。
服务器配置(Server Configuration):管理员的全局基准
如果你使用的是远程 SkyPilot API 服务器(部署细节见 SkyPilot API 服务器文档),服务器会在其自身实例或容器的~/.sky/config.yaml中查找服务器配置。这份配置由管理员统一维护,对通过该 API 服务器发出的所有请求生效,是整棵配置合并树的最低优先级基准层。
从源码实现看,服务器加载路径由_resolve_server_config_path()决定(sky/skypilot_config.py):优先读取SKYPILOT_GLOBAL_CONFIG环境变量指向的文件,否则回退到~/.sky/config.yaml。此外,服务器端配置还支持持久化到数据库:当配置中包含db连接串时,服务器配置会被存入config_yaml数据表(键为api_server_config),下次启动时从数据库恢复(见 sky/skypilot_config.py)。
如果你使用的是本地 API 服务器(即skyCLI 直连本机),则不存在独立的服务器配置层,请直接使用下面的用户配置来设置全局默认值。
用户配置(User Configuration):全局默认值
SkyPilot 客户端会在~/.sky/config.yaml中查找用户配置。这是最常用的全局配置层,适用于本机发起的所有 SkyPilot 调用——包括认证、云厂商参数、Kubernetes 集群偏好等。
源码中对应的默认路径常量定义在 sky/skypilot_config.py:
# Path to the client config files. _GLOBAL_CONFIG_PATH = '~/.sky/config.yaml' _PROJECT_CONFIG_PATH = '.sky.yaml'如果你希望为非默认位置指定用户配置文件,可以设置SKYPILOT_GLOBAL_CONFIG环境变量指向目标路径;若该路径不存在,客户端会直接报错并提示"请检查路径或取消该环境变量"(unset SKYPILOT_GLOBAL_CONFIG),这一行为同样由resolve_user_config_path()(sky/skypilot_config.py)实现。
项目配置(Project Configuration):团队级共享默认值
SkyPilot 客户端会在当前工作目录下查找.sky.yaml文件作为项目配置,适用于该目录下的所有 SkyPilot 调用。这非常适合在 monorepo 或多租户仓库中存储团队共享的默认值(例如统一指定 Kubernetes 的allowed_contexts或云厂商标签),避免每个成员各自维护一份全局配置。
要指定不同的项目配置文件,可通过SKYPILOT_PROJECT_CONFIG环境变量指向所需路径。对应实现位于 sky/skypilot_config.py,其查找逻辑与用户配置一致:先看SKYPILOT_PROJECT_CONFIG环境变量,若未设置则回退到$pwd/.sky.yaml。
客户端在启动时会按"先用户配置、再项目配置"的顺序加载并叠加这两层(_reload_config_as_client(),见 sky/skypilot_config.py),项目配置中出现的字段会覆盖用户配置中的同名字段。
SkyPilot YAML 内联配置:任务级配置
你可以在 SkyPilot YAML 文件的config字段中直接编写内联配置(完整 YAML 字段语法见 yaml-spec 文档)。该层配置仅作用于该 YAML 定义的具体任务,适合随任务一起版本化、可移植的配置项。
SkyPilot YAML 内联配置支持以下字段:
docker.run_optionsnvidia_gpus.disable_ecckubernetes.pod_configkubernetes.provision_timeoutkubernetes.dwskubernetes.kueuegcp.managed_instance_group
示例:
# In your SkyPilot YAML config: docker: run_options: ... kubernetes: pod_config: ... provision_timeout: ... dws: ... kueue: ... gcp: managed_instance_group: ... nvidia_gpus: disable_ecc: ...从源码来看,"哪些键允许在任务级覆盖"由白名单机制严格控制。OVERRIDEABLE_CONFIG_KEYS_IN_TASK定义了完整的可覆盖键集合(sky/skylet/constants.py),除了文档列出的字段外,还包括ssh.pod_config、ssh.provision_timeout、kubernetes.remote_identity、kubernetes.quota、azure.remote_identity、gcp.subnet_names、gcp.placement_policy、slurm.sbatch_options、active_workspace等。任何试图覆盖白名单之外键的配置都会被_recursive_update中的键检查逻辑拒绝(见 sky/utils/config_utils.py),从而保证任务无法越权修改全局配置。
CLI 参数覆盖:单条命令的临时配置
通过--config标志可以向 CLI 传入配置参数,这是优先级最高的一层,只对当前执行的命令生效。
--config标志有两种用法:
- 传入配置文件路径:此时只允许一个
--config标志; - 传入点号键值对(dotlist):可以重复使用多个
--config来覆盖多个字段。
# pass a config file sky launch --config my_config.yaml ... # pass individual config options sky launch --config 'kubernetes.provision_timeout=600' --config 'kubernetes.pod_config.spec.priorityClassName=high-priority' ... sky launch --config 'kubernetes.custom_metadata.annotations.myannotation1=myvalue1' --config 'kubernetes.custom_metadata.annotations.myannotation2=myvalue2' ...CLI 层的实现位于 sky/client/cli/flags.py:config_option装饰器定义了--config选项(multiple=True,即允许重复出现),每个值在命令执行前通过回调被送入skypilot_config.apply_cli_config()应用到全局配置上。解析逻辑_compose_cli_config()(sky/skypilot_config.py)会先判断参数是否为已存在的文件:若是文件则走parse_and_validate_config_file()并强制只允许单个--config;否则按点号键值对解析。
点号键值对的解析由_parse_dotlist()(sky/skypilot_config.py)实现:以第一个=分割键值,键按.拆分为嵌套键路径,值则通过 YAML 安全加载(yaml_utils.safe_load)解析,因此你可以传入数字、布尔值或字符串:
sky launch --config 'kubernetes.provision_timeout=600' --config 'kubernetes.pod_config.spec.priorityClassName=high-priority' --config 'aws.labels.Owner=my-team'另外值得一提的是,--workspace/-w参数本质上也是--config active_workspace=<name>的语法糖(见 sky/client/cli/flags.py)。
配置覆盖优先级与合并规则
当同一个配置字段在多个来源中都被指定时,SkyPilot 按下述优先级从高到低依次覆盖:
- CLI flag(最高优先级)
- SkyPilot YAML
- Project configuration
- User configuration
- Server configuration(最低优先级)
合并规则如下:
- 列表(List)默认被更高优先级的来源整体覆盖。
- 例外:
kubernetes.pod_config中 Kubernetes 定义了补丁合并键(patch merge key)的字段(例如containers和volumes按name合并,volumeMounts按mountPath合并)会按该键逐项合并:键与已有项匹配的项会被合并进已有项,其余项则被追加到列表末尾。而args、command和imagePullSecrets作为整体被替换,因此一个空的imagePullSecrets列表即可清空低优先级来源设置的密钥。剩余的列表字段则被追加到已有列表之后。
- 例外:
- 字典(Dict)按键逐项合并,各个键由高优先级来源覆盖。
这段合并语义在源码中有完整实现。merge_k8s_configs()(sky/utils/config_utils.py)定义了 Kubernetes 配置的合并行为,其中_PATCH_MERGE_KEYS常量(sky/utils/config_utils.py)给出了完整的关键映射表:
| 列表字段 | 合并键 | 行为 |
|---|---|---|
containers/initContainers/ephemeralContainers | name | 按 name 逐项合并 |
volumes | name | 按 name 逐项合并 |
volumeMounts | mountPath | 按 mountPath 逐项合并 |
env | name | 按 name 逐项合并 |
hostAliases | ip | 按 ip 逐项合并 |
ports | containerPort | 按 containerPort 逐项合并 |
volumeDevices | devicePath | 按 devicePath 逐项合并 |
args/command/imagePullSecrets | —(原子字段) | 整体替换,空列表可清空继承值 |
| 其余列表字段 | — | 追加到已有列表 |
此外,_validate_mergeable_types()(sky/utils/config_utils.py)会在合并前校验覆盖值的类型是否与基准值兼容,若用标量覆盖字典或列表等不兼容类型会抛出InvalidSkyPilotConfigError,避免产生难以排查的静默错误。而显式的null值则用于"清空"继承的子树——Kubernetes 将 null 字段视为不存在。
覆盖示例:从两份配置推导最终结果
假设用户配置文件(~/.sky/config.yaml)中配置了:
kubernetes: allowed_contexts: [context1, context2] provision_timeout: 600 aws: labels: map-migrated: my-value Owner: user-unique-name而项目配置文件($pwd/.sky.yaml)中配置了:
# project config overrides user config kubernetes: allowed_contexts: [context3, context4] provision_timeout: 300 aws: labels: Owner: project-unique-name根据上述合并规则,最终合并后的配置为:
kubernetes: # lists are overridden by config sources with higher priority allowed_contexts: [context3, context4] provision_timeout: 300 aws: # dicts are merged, with individual keys overridden by # config sources with higher priority labels: map-migrated: my-value Owner: project-unique-name分析要点:
kubernetes.allowed_contexts是列表,由更高优先级的项目配置整体覆盖,[context1, context2]被[context3, context4]取代;kubernetes.provision_timeout被覆盖为300;aws.labels是字典,按键合并:map-migrated保留用户配置中的值,Owner被项目配置覆盖为project-unique-name。
如果你还想针对单条命令进一步覆盖,比如把这次启动的 K8s 上下文限制到context5,可以在 CLI 层补充--config 'kubernetes.allowed_contexts=[context5]'——CLI 层优先级最高,列表将被整体替换。
客户端忽略的字段与管理员策略
有两类字段需要特别留意:
- 以下字段如果由客户端指定会被忽略:
admin_policyallowed_clouds
这背后是SKIPPED_CLIENT_OVERRIDE_KEYS机制(sky/skylet/constants.py):当客户端配置与服务器配置合并时,api_server、allowed_clouds、workspaces、db、daemons、metrics、控制器 consolidation 模式、Slurm 集群身份映射等键一律以服务器端为准,客户端的不同取值会被忽略并打印警告。这是出于安全与职责划分的考虑——云供应商白名单和策略审计必须由服务器管理员统一把控。
- 如果你是 SkyPilot API 服务器的管理员,可以通过实施**管理员策略(admin policy)**禁用覆盖,或只允许特定字段被覆盖。管理员策略的配置方法详见 管理员策略文档。
深入原理:客户端配置的加载与分层叠加
把上述各层串联起来的核心逻辑是客户端启动时的_reload_config_as_client()(sky/skypilot_config.py),其执行顺序与配置文档完全对应:
- 解析用户配置(
resolve_user_config_path()→~/.sky/config.yaml或SKYPILOT_GLOBAL_CONFIG); - 解析项目配置(
_resolve_project_config_path()→$pwd/.sky.yaml或SKYPILOT_PROJECT_CONFIG); - 按优先级依次调用
overlay_skypilot_config()将项目配置叠加到用户配置之上; - 通过
validate_schema校验最终配置是否符合 配置 schema 定义; - 在 CLI 命令执行时,
apply_cli_config()再以同样的 overlay 方式把--config的覆盖施加到已加载的配置上(sky/skypilot_config.py)。
叠加的核心是Config.get_nested()与_recursive_update()(sky/utils/config_utils.py):前者返回深层拷贝并应用覆盖,后者递归逐键合并字典、按规则处理列表,从而保证任意层的合并都不会污染其他来源的配置对象。
对于 Kubernetes 这类支持上下文(context)区分的云平台,配置还支持按上下文/节点池分层的context_configs:在读取配置时,get_cloud_config_value_from_dict()(sky/utils/config_utils.py)会优先查找<cloud>/context_configs/<context>/<keys>,找不到再回退到云级<cloud>/<keys>,与全局合并语义保持一致。这与配置来源分层一起,构成了 SkyPilot "一处基准、多层覆盖、按需精调"的完整配置管理体系。
【免费下载链接】skypilotThe AI Compute Platform for frontier teams. SkyPilot turns fragmented AI compute into one AI supercomputer, so frontier AI teams build custom intelligence faster.项目地址: https://gitcode.com/GitHub_Trending/sk/skypilot
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考