基于现有镜像构建自定义镜像
基于现有镜像 适合在已有预置镜像或自定义镜像上再运行一段安装命令,把新增软件、配置和基础组件写入新镜像。您只需要选择一个基础镜像,再提供一段可自动执行的 Shell 命令。
如果您需要把本地文件打包进镜像、精确控制 ENTRYPOINT / ENV / 多阶段构建,请改用本文后文提到的其他方式。
这种方式实际会执行一次受控的镜像构建任务:
- 平台基于您选择的基础镜像启动构建。
- 在构建环境中以
root身份执行您提供的非交互式 Shell 命令。 - 将命令写入镜像文件系统的内容保存为新镜像。
- 构建环境只开放构建所需的权限,不等同于一台完整启动的 Linux 主机。
警告
首次在镜像中心构建镜像前,租户必须先完成个人认证或企业认证。如果未完成认证就点击 构建镜像 按钮,会提示错误:Invalid operation [building image is not allowed for this tenant]
选择基础镜像
- 进入镜像中心,切换到 自定义镜像 标签页,点击 构建镜像。
- 填写镜像名称、Tag、可用服务 和 可用区。
- 在 构建方式 中选择 基于现有镜像。
- 在 基础镜像 列表中,选择一个预置镜像或已有自定义镜像。
优先按以下顺序选择基础镜像:
- 优先选择已包含目标环境的预置镜像:例如已带 CUDA、PyTorch,且 Ubuntu 版本满足任务要求的预置镜像。
- 需要复用团队环境时,选择已有自定义镜像:适合在团队已经启动或运行过任务的镜像上继续写入少量软件或配置。
- 镜像将用于极值算力实例时,优先确认基础组件是否齐全:详见下文将镜像用于极值算力实例时补齐基础组件。
编写安装命令
在 安装命令 输入框中填写一段可自动执行、无需人工确认的 Shell 命令。平台会在基础镜像上运行这段命令,并将写入镜像文件系统的结果保存为新镜像。
安装命令不局限于 apt-get 或 pip install。只要相关步骤能在无人值守的构建过程中自动完成,通常也可以用来:
- 下载远程文件或脚本
- 写入
/etc、/opt、/usr/local等路径 - 编译二进制或生成脚本
- 组合多条命令,完成一次完整的软件安装与配置
建议在命令开头添加:
set -eux这样可以在命令失败时立即中断,并把失败位置写入构建日志。
安装系统依赖
推荐使用 apt-get update、apt-get install 这类非交互式命令安装系统包。例如:
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y curl jq python3-pip build-essential安装语言依赖
安装 Python 包时,推荐显式使用解释器调用 pip,并关闭缓存,避免额外占用镜像空间。例如:
python3 -m pip install --no-cache-dir uv如果您使用其他语言运行时,也建议采用同样思路:使用可重复执行的包管理命令,并在构建完成后清理临时缓存。
下载文件或脚本
如果构建需要从网络获取文件,也可以直接在安装命令中完成。例如:
curl -fsSL https://example.com/ -o /opt/example.html建议把下载行为写得尽量显式,并与后续安装、解压、校验步骤放在同一段脚本中,方便通过构建日志定位问题。
写入持久化配置
如果您希望环境变量或配置在后续使用新镜像启动实例时继续生效,请把配置写入文件,而不是只在当前 Shell 中执行 export。例如:
cat > /etc/profile.d/10-project-env.sh <<'EOF'
export UV_LINK_MODE=copy
EOF编译二进制或写入文件
如果您的环境需要编译二进制、写入脚本或准备固定文件,也可以直接在安装命令中完成。例如:
cat > /tmp/hello.c <<'EOF'
#include <stdio.h>
int main(){ puts("hello-from-image-build"); return 0; }
EOF
gcc /tmp/hello.c -o /usr/local/bin/hello-from-image-build下面是一个更接近实际使用的示例。它会在 Ubuntu 22.04 基础镜像上安装常用工具、Python 包,并把持久化环境变量写入 /etc/profile.d/:
set -eux
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y curl jq python3-pip build-essential
python3 -m pip install --no-cache-dir uv
cat > /etc/profile.d/10-project-env.sh <<'EOF'
export UV_LINK_MODE=copy
EOF
cat > /tmp/hello.c <<'EOF'
#include <stdio.h>
int main(){ puts("hello-from-image-build"); return 0; }
EOF
gcc /tmp/hello.c -o /usr/local/bin/hello-from-image-build
apt-get clean
rm -rf /var/lib/apt/lists/*将镜像用于极值算力实例时补齐基础组件
如果您计划将新镜像用于极值算力实例,请在构建时一并补齐基础组件。否则平台虽然会尝试自动修复,但仍可能导致实例无法正常启动,或登录功能受限。
基于 Ubuntu 22.04 的自定义镜像:
language-shellDEBIAN_FRONTEND=noninteractive apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y openssh-server sudo runit runit-systemd基于 Ubuntu 24.04 的自定义镜像:
language-shellDEBIAN_FRONTEND=noninteractive apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y openssh-server sudo runit runit-helper runit-run
确认哪些内容会保存到新镜像
使用这种方式构建镜像时,请把安装命令写成一组一次性执行完成的构建步骤,例如安装软件、写入配置文件、编译二进制文件。不要把它当成登录到一台机器后逐步调试和临时操作的过程,因为平台只会保存写入镜像文件系统的内容。
以下内容会保存到新镜像中:
- 新安装的软件包
- 下载到镜像文件系统中的文件
- 写入
/etc、/opt、/usr/local等路径的配置文件和脚本 - 新建用户、用户组,以及相关系统文件变更
- 编译生成的二进制文件
检查哪些操作不会生效
这种构建方式适合安装软件和写配置,不适合执行必须依靠宿主机权限或完整 init 系统才能完成的操作。请不要把以下类型的命令作为核心步骤:
不要依赖交互式输入
请避免依赖手工确认、密码输入、菜单选择等交互式流程。命令一旦等待输入,构建就会卡住或超时。
同时,以下内容也不会自动保存到新镜像中:
- 仅在当前 Shell 中
export的环境变量 - 依赖当前会话状态的临时变量
不要使用 systemctl 启动或管理服务
构建环境不是一台完整启动的 Linux 主机,systemd 不是 PID 1,因此 systemctl start、systemctl enable、systemctl restart、systemctl status 这类命令不可用。即使构建过程以 root 身份执行,也不要把 systemctl 作为安装或验证步骤。
可以做的是修改镜像文件系统,例如安装软件包、写入配置文件、创建启动脚本,或把 runit 服务目录作为普通文件准备好。用于实例启动和登录的基础组件,参见安装平台必需启动组件。不要在构建阶段真正启动服务,也不要依赖后台进程继续存活;构建时临时启动的进程不会成为新镜像的一部分。
如果需要在实例运行时启动服务,请在镜像中准备好脚本或配置,再通过平台启动命令显式启动前台进程。不要假设放在 /etc/service 下的服务会被平台自动接管。对于开发机和极值算力实例,平台的 runsvdir 会监控 /opt/devmachine/init/service;如需让平台的 runit 接管自定义服务,请在镜像中准备服务目录,并在运行时将其复制或链接到该目录,例如通过平台启动命令或登录 Shell 会执行的 /etc/profile。
示例:让构建期准备的服务在运行时生效
如果您要让一段常驻服务随开发机或极值算力实例运行,不要在构建命令中启动该服务。可以在构建阶段把服务目录写入镜像,再在运行时把服务目录放入平台监控的 runit 目录。
在构建命令中准备服务目录。例如:
language-shellmkdir -p /opt/service/my-service cat > /opt/service/my-service/run <<'EOF' #!/bin/sh exec /usr/local/bin/my-service --foreground EOF chmod +x /opt/service/my-service/run在构建命令中写入运行时激活逻辑。例如,把服务目录复制到运行时的
runit监控目录:language-shellcat >> /etc/profile <<'EOF' if [ -d /opt/service ] && [ -d /opt/devmachine/init/service ]; then for svc in /opt/service/*; do [ -d "$svc" ] || continue name="$(basename "$svc")" [ -e "/opt/devmachine/init/service/$name" ] || cp -a "$svc" "/opt/devmachine/init/service/$name" done fi EOF用新镜像创建开发机或极值算力实例后,验证服务是否已被
runit接管:language-shellsv status /opt/devmachine/init/service/my-service
/etc/profile 只有在登录 Shell 执行时才会运行。如果服务必须在无人登录时启动,请把复制或链接动作放到平台启动命令中,或让启动命令直接启动前台进程。
任务和推理服务不要套用这个 /etc/profile 示例作为自动启动机制。它们的容器生命周期由用户提交的启动命令决定:任务命令结束后容器会退出,推理服务命令必须持续以前台进程运行。需要复用构建期写入的脚本或服务目录时,请在任务或推理服务的启动命令中显式执行激活动作,并用 exec 启动最终业务进程。
不要修改内核和网络
请不要把 mount、unshare、网卡创建或需要更高权限的内核级操作写入安装命令。即使构建过程以 root 身份执行,这类操作通常仍会因为权限限制而失败。
同样地,sysctl 这类修改内核参数的命令,也不适合作为镜像构建的核心步骤。
不要依赖 GPU
构建阶段通常不暴露 GPU 设备。请不要依赖 nvidia-smi、GPU 探测或需要直接访问显卡设备的初始化逻辑。
如果您的软件安装流程依赖上述能力,请改用在实例内构建自定义镜像或本地 Docker 构建流程。
查看构建日志
构建开始后,镜像会出现在 自定义镜像 标签页中。点击列表中的 构建日志,即可查看完整日志。
建议按以下顺序排查:
- 先看失败发生在哪一条命令。
- 再看是否是网络、软件源、安装命令语法或权限相关问题。
- 如果构建时间过长,请检查命令是否依赖外部下载,或是否执行了不必要的大型编译步骤。
常见现象包括:
apt-get或pip下载超时- 命令依赖交互式输入,导致构建卡住
- 脚本中某一步返回非零退出码,构建直接失败
验证新镜像
镜像状态变为 构建成功 后,建议先用少量资源试运行,再大规模复用:
- 用新镜像创建一个测试实例、任务或推理服务。
- 在测试环境中执行核心命令,例如
python3、pip、jq、自定义脚本或二进制。 - 如果镜像将用于极值算力实例,重点确认实例能登录、启动速度正常、基础命令可执行。
- 确认无误后,再将该镜像用于更多资源池或团队环境。
信息
如果只是想快速修复一个已有自定义镜像中的缺失组件,通常也推荐优先使用这种方式。它比直接在单个运行环境里手工补装依赖更容易复用,也更容易回溯镜像版本。
需要本地文件或更强控制时改用其他方式
在以下场景下,基于现有镜像 不是最合适的方式:
需要 COPY 文件时改用 Dockerfile
如果您需要把应用代码、配置文件、模型文件等本地文件打包进镜像,请改用基于 Dockerfile 构建自定义镜像或在实例内构建自定义镜像。
需要控制 Entrypoint 时改用 Dockerfile
如果您需要精确控制 ENTRYPOINT、ENV、多阶段构建,或维护一份可长期复用的镜像定义文件,请改用基于 Dockerfile 构建自定义镜像。