
mise oci 命令深度指南从 mise.toml 构建、运行与推送 OCI 容器镜像【免费下载链接】misedev tools, env vars, task runner项目地址: https://gitcode.com/GitHub_Trending/mi/misemise oci是 mise 的实验性子命令组它把一份mise.toml直接变成 OCI 容器镜像——每个工具安装成为一个独立的 OCI 层从而让升级某个工具版本只失效一个内容寻址的 blob而不是像 Dockerfile 那样让早先的RUN变更使上方所有层全部失效。本文以 docs/cli/oci.md 为主线结合mise oci build / run / push三个子命令的完整 CLI 参考、深度指南 docs/dev-tools/mise-oci.md 以及src/oci/下的源码实现覆盖从构建、运行、推送、认证到多架构发布的完整实战链路。读完你将掌握如何把项目工具链声明式地固化为镜像、如何用容器引擎直接运行镜像内命令、如何用内置 registry 客户端做增量推送以及[oci]、[bootstrap.packages]、[dotfiles]等配置段的每一个细节。功能概述与核心设计mise oci的定位在 src/oci/mod.rs 的模块注释中写得很清楚The core invariant: each installed tool version becomes its own OCI layer. Because mise installs tools to isolated, non-overlapping directories, layerorderingis semantically irrelevant — swapping a tool version swaps exactly one content-addressable blob.即核心不变量每个已安装的工具版本都对应一个独立的 OCI 层。由于 mise 将工具安装到彼此隔离、互不重叠的目录中层的顺序在语义上无关紧要——更换一个工具版本就只会替换恰好一个内容寻址的 blob。相比之下Dockerfile 中修改早期RUN指令会使其上方的每一层都失效而这里升级单个工具如 Node.js不会影响其他工具的层。该命令当前为实验特性需要mise settings experimentaltrue或环境变量MISE_EXPERIMENTAL1。未来的版本中行为、标志位和输出布局都可能发生变化。在源码层面mise oci build的入口会先执行Settings::get().ensure_experimental(mise oci build)?见 src/cli/oci/build.rs来强制校验实验开关未开启时直接报错。命令一览命令作用mise oci build在磁盘上生成一个 OCI image layout镜像布局目录。mise oci run构建或复用镜像并通过 podman/docker 在其中执行命令。mise oci push构建或复用镜像并推送到 registry。三个子命令共享同一个 one layer per tool 的构建引擎区别仅在于产物的去向build产出目录符合 OCI image-layout 规范可用skopeo inspect oci:./mise-oci检查run等价于mise oci build后跟docker run/podman run且 stdin/stdout/stderr 被继承push使用 mise 自带的 registry 客户端推送无需 skopeo、crane 或 docker daemon。启用实验特性mise settings set experimentaltrue # 或者仅在单次调用时启用 MISE_EXPERIMENTAL1 mise oci build …也可以在项目mise.toml的[settings]中直接写入[settings] experimental true快速上手在Linux 主机、目标架构上从一个最小的项目配置开始[settings] experimental true [tools] node 24构建本地镜像布局再通过容器引擎验证其中的可执行文件mise oci build -o ./mise-oci mise oci run --image-dir ./mise-oci -- node --version要点说明默认基础镜像为debian:bookworm-slim把生成的mise-oci/目录加入.gitignore这创建的是一个工具环境不会自动复制你的应用代码也不会安装应用自身的包依赖开发期建议用 volume 挂载代码需要真正进入镜像的文件用oci.copy配置用外部工具检查布局安装skopeo后执行skopeo inspect oci:./mise-oci发布镜像则按 推送认证 配置凭据后选择一个你有写权限的 registry/repositorymise oci push --image-dir ./mise-oci ghcr.io/OWNER/IMAGE:TAG将大写的占位符替换为实际值。该命令负责发布镜像与本地构建/运行检查是相互独立的步骤。分层机制每个工具一层给定如下mise.toml[tools] node 20 python 3.12 jq 1.8.1mise oci build产出的层大致如下基础镜像层如debian:bookworm-slim——从 registry 原样复制registry 的 dedup 机制直接生效mise 二进制位于/usr/local/bin/mise可用--no-mise跳过若配置了 apt 或 apk 的[bootstrap.packages]安装进基础 rootfs 后作为一个包层输出每个工具一层各自根目录为/mise/installs/plugin/version/层带dev.mise.tool.short与dev.mise.tool.version注解若配置了[dotfiles]烘焙为镜像内文件合成的/etc/mise/config.toml将数据目录指向/mise。升级 Node.js 不会影响其他无关工具层其归档 blob 可直接复用。但镜像配置、manifest 以及输入发生变化的层仍需要更新例如 Python 版本变化可能使依赖它的 pipx 层失效。复用的前提还包括镜像内路径、文件属主以及任何 relocation 输入的一致性。mise oci build的输出会打印布局路径、manifest digest 以及每个工具层的摘要信息short、版本、digest 短值、字节数实现见 src/cli/oci/build.rs。mise oci build全参数mise oci build [-o PATH] [--from REF] [--tag REF] [--mount-point PATH] [--copy HOST_PATH:IMAGE_PATH]... [--no-mise] [--owner UID[:GID]]-o, --output PATH— 输出目录默认./mise-oci--from REF— 基础镜像引用覆盖[oci].from与oci.default_from设置。传scratch表示无基础镜像构建-t, --tag REF— 写入index.json的标签作为org.opencontainers.image.ref.name注解--mount-point PATH— 镜像内工具安装位置默认/mise必须是绝对路径--copy HOST_PATH:IMAGE_PATH— 将主机文件或目录复制到镜像内的绝对路径可重复传入多个。每个 payload 在工具层之后作为独立的内容寻址层输出--no-mise— 不将当前运行的 mise 二进制嵌入/usr/local/bin/mise--owner UID[:GID]— 生成层中每个条目的数字属主。默认取[oci].user_id/[oci].group_id再兜底为0:0省略 GID 时默认等于 UID。只影响文件属主不影响镜像的USER指令--include-global— 默认只打包项目配置及项目根目录或以下的父级配置如 monorepo 根配置中声明的工具~/.config/mise/config.toml里的个人工具不会被烘焙进项目镜像加上该标志则恢复合并所有加载配置的旧行为-h --help— 打印帮助示例需在 Linux 主机、目标架构上运行mise oci build mise oci build --from ubuntu:24.04 --tag myorg/dev:latest -o ./img skopeo inspect oci:./img mise oci run --image-dir ./img -- /bin/sh源码层面的注意点来自 src/cli/oci/build.rs 的构建注释镜像只包含项目 mise 配置中的工具含项目根及以下配置~/.config/mise/config.toml中的工具不包含除非传入--include-globalv1 不支持 asdf 和 vfox 插件请为每个工具改用 core、aqua、ubi、github、cargo、npm、go、pipx、spm、http 等后端默认将主机 mise 二进制嵌入/usr/local/bin/mise请在目标镜像同一 OS/arch 上构建或传--no-misebuild必须产出完整、独立的镜像目录因此其BuildOptions中reuse_from恒为None层复用会在布局中留下没有 blob 的空洞见 src/cli/oci/build.rs。mise oci run全参数构建或复用镜像并在其中运行命令用法类似docker run/podman runstdin/stdout/stderr 被继承。mise oci run [--engine ENGINE] [--image-dir DIR] [--from REF] [--mount-point PATH] [--no-mise] [--owner UID[:GID]] [-i] [-t] [-e KEYVAL]... [--volume HOST:CONTAINER]... [-w DIR] [--keep] -- cmd [args...]--engine—auto默认优先 podman、podman或docker--image-dir— 跳过构建直接使用已有的 OCI layout--owner UID[:GID]— 全新构建时设置生成层条目的数字属主不能与--image-dir同时使用-i、-t、-e、--volume、-w、--keep— 与docker run相同的透传语义。注意--volume没有-v短标志因为 mise 保留-v给--verbose请使用--volume或--mount--keep— 默认命令退出后容器--rm与被加载的镜像都会被移除反复调用不会在 podman/docker 存储中堆积镜像加--keep则按 mise 使用的标签保留镜像docker 为mise-oci:run-*podman 为拉取的镜像 ID示例# 交互式 shell mise oci run -it -- bash # 一次性命令env volume workdir mise oci run -e DEBUG1 --volume $PWD:/work -w /work -- npm test # 复用先前构建的布局 mise oci build -o ./img mise oci run --image-dir ./img -- node --version运行前提需要 podman原生支持 OCI layout或 dockermise 通过docker load把镜像流入 daemon。mise 自身没有内置容器运行时。mise oci push全参数与推送细节构建或复用镜像并用 mise 内置的 registry 客户端推送到 registry——无需 skopeo、crane 或 docker daemon。mise oci push [--image-dir DIR] [--from REF] [--mount-point PATH] [--no-mise] [--owner UID[:GID]] REGISTRY_REFREGISTRY_REF— 完全限定的目标地址如ghcr.io/me/devenv:latest必须包含 registry 主机名--image-dir— 推送已有 OCI layout 而不是现场构建--from REF— 构建时的基础镜像--image-dir时忽略--mount-point PATH— 覆盖镜像内挂载点--image-dir时忽略--no-mise— 不嵌入 mise 二进制--image-dir时忽略--owner UID[:GID]— 构建时设置层条目的数字属主与--image-dir冲突--cache-from REF— 从该镜像复用未变化的工具层而不是从目标 ref 复用必须与目标位于同一 repository。适用于每次推送使用唯一标签的场景如 CI 中按 commit 打标签mise oci push --cache-from ghcr.io/me/dev:latest ghcr.io/me/dev:$GIT_SHA--no-cache— 关闭层复用从本地安装全量重建docker 式逃生舱复用逻辑信任 registry 中层的注解与内容一致而不是在本地重建出精确字节--update-index— 将标签维护为多架构 image index见下文多架构镜像-h --help— 打印帮助增量上传与层复用推送时只上传 registry 中尚不存在的 blob因此对基本未变化的工具集重复推送时传输量极小。当基础镜像就在目标 registry 上时其 blob 会以 cross-repository mount 方式挂载而非重新上传零字节传输。大层分块上传并显示进度条瞬时网络故障会按退避策略重试http_retries控制尝试次数见 src/config/settings.rs 与 src/oci/registry.rs 的retry_transient!宏。层复用缓存键工具、版本、镜像内前缀、文件属主与先前推送镜像匹配的工具层会直接从 registry 复用而不重建——完全跳过本地 tar/gzip 工作。被复用的工具甚至不需要在本地安装这让 CI 推送非常快只有版本真正变化的工具才需要安装并打包。缓存默认使用目标 ref 本身该标签下先前推送的镜像。一个已知陷阱环境推导JAVA_HOME这类exec_env变量是针对本地安装执行的。对于未安装的复用工具大多数后端仍能正确推导路径但特殊后端可能贡献出不完整的 env——如果镜像配置看起来不对请安装该工具后传--no-cache强制重建。上述行为有端到端测试背书e2e/oci/test_oci_push_layer_reuse 完整验证了首次全量推送 → 卸载工具后同标签推送仍复用 registry 层打印1 tool layer(s) reused from previous image→--cache-from到新标签复用层且 digest 完全一致 →--cache-from必须同 repository →--no-cache在工具卸载时失败 → 重装后--no-cache推送出字节一致镜像0 blob(s) uploaded这一整条链路。推送认证凭据按 docker 与 podman 相同的来源顺序解析$REGISTRY_AUTH_FILE$XDG_RUNTIME_DIR/containers/auth.jsonpodman~/.config/containers/auth.json~/.docker/config.json或$DOCKER_CONFIG/config.json内联auths条目与凭据助手credsStore/credHelpers如docker-credential-osxkeychain、docker-credential-ecr-login都受支持——所以只需一次docker login ghcr.io或podman login ghcr.io即可。未找到凭据时mise 会匿名推送对本地 registry 有用并给出警告。对 ghcr.iotoken 需要write:packages权限。不安全HTTPregistry回环地址localhost:5000/…按 docker 同款默认不安全约定走明文 HTTP。非回环的明文 HTTP registry如家庭环境的registry.lan:5000必须通过oci.insecure_registries设置显式放行[settings.oci] insecure_registries [registry.lan:5000]对应实现见 src/oci/registry.rsis_insecure_registry先检查回环地址再查oci.insecure_registries条目支持精确匹配或裸主机名匹配源码中还附带了insecure_registry_entries_match_exact_or_bare_host单元测试。示例# 一步构建 推送 mise oci push ghcr.io/me/devenv:latest # 推送先前构建好的镜像 mise oci build -o ./img mise oci push --image-dir ./img ghcr.io/me/devenv:v1[oci]配置段mise.toml[oci] from debian:bookworm-slim # 基础镜像引用 tag ghcr.io/me/devenv:v1 # 构建镜像的默认标签 workdir /workspace # WORKDIR entrypoint [] # ENTRYPOINT cmd [] # CMD user 1000:1000 # USER user_id 1000 # tar 层条目 UID文件属主 group_id 1000 # tar 层条目 GID默认等于 user_id mount_point /mise # 镜像内工具安装位置 [[oci.copy]] host dist/my-app image /usr/local/bin/my-app [[oci.copy]] host assets image /srv/app/assets # 烘焙进镜像配置的额外 env仅镜像内生效不会遮蔽 MISE_*。 [oci.env] NODE_ENV production # 烘焙进镜像配置的标签。 [oci.labels] org.opencontainers.image.source https://github.com/me/my-app字段语义与优先级源码结构见 src/oci/mod.rs 的OciConfig#[serde(deny_unknown_fields)]意味着未知字段会直接报错copy 示例要求dist/my-app与assets真实存在[oci].user设置镜像的USER指令但不会创建账号、家目录或可写工作区请使用数字 UID/GID 或基础镜像已提供的用户[oci].user_id/[oci].group_id设置层文件属主未配置group_id时默认取解析后的user_idCLI 标志 [oci]段 oci.default_from/oci.default_mount_point设置当mise.toml分层全局 项目时各段按字段逐一合并更具体的文件逐字段胜出。合并逻辑在OciConfig::fill_defaults_fromsrc/oci/mod.rs中实现标量字段先到先得map 字段键级合并copy 条目则累积排列——从fill_defaults_from的单元测试layered_copies_put_more_specific_entries_lastsrc/oci/mod.rs可以看出合并后顺序为 parent → project即更具体的配置排在后、最后输出、优先生效。copy 的细节规则源可以是文件、目录或符号链接目录内容落在image路径下不会附加源目录名镜像路径必须绝对且不得包含.或..成分validate_image_path在 src/oci/mod.rs 中强制校验并拒绝根路径/父目录自动创建可执行位保留属主遵循--owner或[oci].user_id/[oci].group_idcopy 层带dev.mise.copyimage path注解便于检查时识别配置文件中相对host路径以声明它的配置文件所在目录为基准CLI 相对路径以当前工作目录为基准分层配置复制到同一镜像路径时低优先级条目先输出保证最具体配置胜出CLI 的 copy 最后输出。[bootstrap]与[dotfiles]在 OCI 镜像中的应用mise oci build会把项目作用域的[bootstrap.packages]和[dotfiles]条目应用到镜像——这是mise bootstrap中声明式包与 dotfile 部分的 OCI 等价物。传--include-global可同时纳入全局配置中的这两类条目。[bootstrap.packages] apt:curl latest [dotfiles] /etc/profile.d/project.sh { source profile.sh, mode copy } ~/.config/app/config.toml { source config.toml, mode template }包层规则OCI 构建支持 Debian/Ubuntu 基础镜像下的apt:条目与 Alpine/Wolfi 基础镜像下的apk:条目mise 先把基础镜像解包到临时 rootfs调用匹配的主机包管理器安装进该 rootfs再把文件系统变更输出为一个OCI 层注解为dev.mise.system.packagesapt或dev.mise.system.packagesapk一次构建只能用与基础镜像匹配的包管理器混用apt:与apk:条目会被拒绝主机必须提供apt-get与dpkgapt 层或apkapk 层apk 包的脚本在 chroot 内执行因此 apk 层目前要求 Linux 主机且 mise 以 root 运行--no-cache会传给 apk创建层前会清理临时包管理器缓存与日志文件。dotfile 规则镜像构建时symlink与symlink-each条目按文件内容复制——主机符号链接通常指回检出路径容器内会失效因此镜像收到的是解析后的内容以~/开头的目标写到/root/下。不适用部分[bootstrap.macos.defaults]与命令式bootstraptask 不会被mise oci build执行——macOS 默认项不适用于 Linux OCI 镜像容器专属的启动工作应放在镜像 entrypoint 或 command 中。相关设置设置默认值说明oci.default_fromdebian:bookworm-slim未指定时的默认基础镜像。oci.default_mount_point/mise镜像内工具的安装位置。选择与打包二进制及其共享库兼容的基础镜像默认基础镜像基于 glibcAlpine/musl 基础镜像要求 musl 兼容或合适的静态二进制且更换--from不会为不同的 libc 重建已安装工具。运行时所需的系统库必须存在于镜像中。镜像内的环境变量镜像配置的Env按如下顺序构建后者胜出基础镜像 env来自拉取的--from镜像配置mise.toml中的[env]段完整解析——模板展开、读取.env文件每个工具的exec_env()——如JAVA_HOME、GOROOT、GEM_HOME路径会从主机安装目录重定向到镜像内路径[oci].env条目合成的 PATH镜像内各工具 bin 路径加继承的 PATHMISE_DATA_DIR/mise与MISE_CONFIG_DIR/etc/mise——总是最后应用确保不会被遮蔽。⚠️[env]中的秘密会被烘焙进镜像[env]段中的任何内容——包括从.env文件加载的值——都会写入镜像配置 JSON任何执行docker inspect/skopeo inspect的人都能看到。切勿把秘密放在这里。请改用docker run -e、secret mounts 或编排器 secret。[oci].env只放可以安全存在于镜像中的值。mise 会打印一条包含烘焙进镜像的[env]变量数量的警告。支持的 backend构建器接受内置后端打包每个选中工具的安装目录并重定位受支持的可执行路径与 shebang。被接受并不保证工具自包含系统库、外部运行时或安装目录之外的路径仍可能是依赖。请把所需运行时与工具一同声明并用项目实际运行的命令验证镜像。asdf 与 vfox 插件含自定义 vfox 后端插件会被拒绝它们的安装钩子可能写到按版本目录之外的地方这种写入无法被每工具一层的模型可靠捕获。基础镜像支持基础镜像可从任意 OCI Distribution v2 registry 拉取——Docker Hub、ghcr.io、quay.io、自建 registry 等。公共镜像的匿名 token 认证自动处理已登录docker login/podman login时使用这些凭据因此私有基础镜像同样可用。支持 digest 引用mise oci build --from REGISTRY/IMAGEsha256:FULL_DIGEST用真实镜像引用与完整 SHA256 digest 替换占位符。digest 钉死基础镜像可变的 tag 在后续构建中可能解析到新的基础镜像。可复现性同一台主机上输入不变的条件下重复运行mise oci build会产生字节级一致的工具层 digest。跨机器时层 digest 可能漂移因为编译产物pyc 字节码、生成的 node-gyp 输出等可能嵌入绝对路径。要获得完全可复现的镜像配置时间戳设置SOURCE_DATE_EPOCHSOURCE_DATE_EPOCH$(git log -1 --format%ct) mise oci build跨平台构建与多架构镜像OCI 镜像以 Linux 为目标。在 macOS 或 Windows 上构建会得到os字段为linux的镜像但其中嵌入的二进制mise 与每个工具层仍是主机原生格式——容器内执行时会以Exec format error失败。请在有 mise 及所需工具安装依赖的 Linux 主机或 Linux 开发容器中构建一个普通的debian镜像并不自带 mise也不要把 macOS/Windows 的工具安装挂载进该容器充当 Linux 安装的替代品。主机与镜像平台不匹配时 mise 会告警。多架构multi-arch镜像单个主机只能构建单个平台但mise oci push --update-index允许每个架构各用一个 runner 组装出多架构 tag每次推送按 digest 上传自己的平台 manifest并把 tag 指向一个保留了其他平台条目的 OCIimage index。例如下面的 GitHub Actions job 一次构建一个架构假设项目有mise.toml发布到 GHCR且 workflow 有该包访问权限name: Publish development image on: workflow_dispatch permissions: contents: read packages: write concurrency: group: mise-development-image cancel-in-progress: false jobs: publish: strategy: max-parallel: 1 matrix: runner: [ubuntu-24.04, ubuntu-24.04-arm] runs-on: ${{ matrix.runner }} env: MISE_EXPERIMENTAL: 1 steps: - uses: actions/checkoutv6 - uses: jdx/mise-actionv4 - name: Authenticate to GHCR env: GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: printf %s $GHCR_TOKEN | docker login ghcr.io -u $GITHUB_ACTOR --password-stdin - name: Publish this architecture run: mise oci push --update-index ghcr.io/${GITHUB_REPOSITORY,,}/dev:latest要点与 e2e/oci/test_oci_push_update_index 覆盖的行为一致选择仓库可用的 runner 标签矩阵串行化max-parallel: 1防止两个平台的推送互相竞争workflow 级 concurrency 防止该 workflow 的并发运行同时更新同一 tag重新推送同一平台会替换其条目不产生重复原本单架构的 tag 会升级为 index 且不丢失已有平台层复用在 index 下同样生效——缓存解析到与构建平台匹配的条目index 更新是 read-modify-writeDistribution API 没有条件写因此不同 runner 并发推同一 tag 可能竞争——请按上面的方式串行化。已知限制v1asdf/vfox后端被拒绝见上文跨平台构建产生不可用的镜像二进制为主机原生格式请在 Linux 主机上构建基础镜像必须提供兼容的 libc 及其他运行时库mise oci run需要容器引擎podman 或 docker——mise 没有内置容器运行时推送则无需任何外部工具。源码与测试索引如果你想深入实现以下是关键路径src/cli/oci/mod.rs —oci子命令组入口与核心不变量说明src/cli/oci/build.rs —build参数定义、实验开关校验与构建结果输出src/cli/oci/common.rs — 三个子命令共享的构建编排src/oci/mod.rs —OciConfig配置结构、OciCopy解析与校验、normalize_arch/normalize_os平台归一化、分层配置合并逻辑src/oci/builder.rs — 构建器主体oci.default_from/oci.default_mount_point的兜底取值src/oci/registry.rs — 内置 registry 客户端认证、不安全 registry 判定、http_retries退避重试、blob 增量上传src/oci/layer.rs / src/oci/layout.rs / src/oci/manifest.rs / src/oci/packages.rs — 层、布局、manifest 与系统包层的实现e2e/oci/test_oci_push_layer_reuse、e2e/oci/test_oci_push_registry、e2e/oci/test_oci_push_update_index、e2e/oci/test_oci_build_slow、e2e/oci/test_oci_run_push_errors_slow — 覆盖层复用、registry 推送、多架构 index、构建与错误路径的端到端测试。延伸阅读mise oci build完整 CLI 参考mise oci push完整 CLI 参考mise oci run完整 CLI 参考构建与运行 OCI 镜像深度指南全部 CLI 命令索引 与 全局标志与参数语法【免费下载链接】misedev tools, env vars, task runner项目地址: https://gitcode.com/GitHub_Trending/mi/mise创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考