环境变量
环境变量是模板配置其中工作负载的方式:一个 Hugging Face 令牌、一个模型名称、一个日志级别。在模板表单的环境部分添加它们,每行一个键和一个值,右侧带一个私密开关。
如何设置
| 组成部分 | 规则 |
|---|---|
| 键 | 最多 256 个字符。键为空的行会在保存时被丢弃。 |
| 值 | 任意字符串。留空则该条目被存储为未设置。 |
| 私密 | 对所属组织之外的任何人遮蔽该值。 |
没有值的条目根本不会被注入容器。这让它很适合当占位符:把 HF_TOKEN 声明为没有值的私密条目,模板就说明了租用者必须提供什么,同时又不会把令牌送给每一个读它的人。
在 API 中,env 是 POST /v1/templates 和 PATCH /v1/templates/{id} 上的一个对象列表:
{
"env": [
{ "key": "MODEL_ID", "value": "meta-llama/Llama-3-8B", "secret": false },
{ "key": "HF_TOKEN", "value": null, "secret": true }
]
}
在 PATCH 中发送 env 会替换整个列表。没有按单个键更新的方式。
私密值遮蔽
私密值只会返回给拥有该模板的组织。其他所有人——包括浏览你公开模板的人,也包括精选 system 模板的读者——拿到的是 value: null,secret 标志保持不变。控制台会显示键名,并用隐藏占位符代替值。
遮蔽跟随数据,而不是跟随端点:GET /v1/templates、GET /v1/templates/{id} 和 GET /v1/templates/by-hash/{hash_id} 都会应用它。
有两个后果值得知道:
- 复制一个不属于你的组织的模板时,副本中的每个私密值都会被清空。你从来没有读取它们的权限,成为副本的所有者不能改变这一点。复制你自己的模板则会保留它们。
- 把一个已存在的值标记为私密,只能从此以后隐藏它,并不能收回已经读到它的人手里的内容。请改为轮换该凭据。
部署时的租用者覆盖
部署时可以用 POST /v1/instances 上的 env_overrides 添加或替换环境变量条目:
{
"offer_id": "…",
"template_id": "…",
"disk_gb": 100,
"env_overrides": [{ "key": "HF_TOKEN", "value": "hf_…", "secret": true }]
}
先应用模板环境变量,再应用覆盖项,按键匹配——覆盖项胜出。任意一侧值为 null 的条目会被丢弃,而不是作为空字符串注入。这就是你在不编辑模板的情况下填上私密占位符的办法,同时也让你的令牌不进入共享的配方。
平台覆盖层总是胜出
在模板环境变量与租用者覆盖合并之后,Superheat 会应用一层平台覆盖,而这层覆盖是最后应用的。覆盖层里的键无法被模板值或 env_overrides 条目压过——你设的任何值都会被无声地替换掉。
| 变量 | 何时设置 | 携带内容 |
|---|---|---|
CONTAINER_ID | 始终 | 工作负载标识符 |
GPU_COUNT | 始终 | 分配给该实例的 GPU 数量 |
SUPERHEAT_TCP_PORT_<n> | 每个已发布的 TCP 端口一个 | 容器端口 <n> 映射到的主机端口 |
PUBLIC_KEY | ssh、jupyter,且部署时附加了 SSH 密钥 | 你的 SSH 公钥 |
SUPERHEAT_SSH_PUBLIC_KEYS | ssh、jupyter,且部署时附加了 SSH 密钥 | 同样的密钥内容,采用换行分隔的形式 |
SUPERHEAT_ONSTART | ssh、jupyter,且已设置时 | 启动脚本的内容 |
OPEN_BUTTON_PORT | ssh、jupyter,且有端口标签为 open 时 | 打开按钮的目标端口 |
JUPYTER_TOKEN | jupyter | 平台生成的访问令牌 |
JUPYTER_PORT | jupyter | 8080 |
JUPYTER_DIR | jupyter | 模板的 Jupyter 工作目录 |
JUPYTER_LAB | jupyter | true 表示 JupyterLab,false 表示经典 notebook |
所以在模板上设置 JUPYTER_TOKEN 毫无作用:令牌由平台生成,好让它能拼出打开按钮的 URL,而这个令牌从不回传。设置 GPU_COUNT 同样没用——它反映的是你实际租到的切片,如果租用者能改它,信任这个值的程序就会被骗。
覆盖是无声的。如果你的代码读 GPU_COUNT 时期待的是你自己的值,它拿到的会是平台的值,而且哪里都不会报错。
在容器内你看到的是什么
在派生自基础镜像的镜像上,sshd 和 Jupyter 会启动不继承容器进程环境的登录 shell,因此入口点会把环境写入 /etc/environment 和 /etc/profile.d/superheat-env.sh。你 SSH 进去时,你的变量以及 CONTAINER_ID、GPU_COUNT 和 SUPERHEAT_TCP_PORT_* 条目都在那里。
预置阶段的机密被有意地从这两个文件中排除:SUPERHEAT_ONSTART、JUPYTER_TOKEN、PUBLIC_KEY 和 SUPERHEAT_SSH_PUBLIC_KEYS 由入口点消费,从不重新导出。在 SSH 会话里 echo $JUPYTER_TOKEN 什么都不会返回,这是设计使然。