Dokku 基于 Docker 镜像的应用部署指南:git:from-image 与 git:load-image 实战详解
2026/9/10 10:47:25 网站建设 项目流程

Dokku 基于 Docker 镜像的应用部署指南:git:from-image 与 git:load-image 实战详解

【免费下载链接】dokkuA docker-powered PaaS that helps you build and manage the lifecycle of applications项目地址: https://gitcode.com/GitHub_Trending/do/dokku

导读

在 Dokku(一个基于 Docker 的 PaaS 平台)中,应用仓库通常由git push推送的源码构成,但在"镜像已经由 CI/CD 流水线构建完成、只想直接部署"的场景下,源码反而不是最优载体。本文讲解 Dokku 提供的两条专为镜像部署设计的能力:git:from-image(从镜像仓库中的镜像初始化/更新应用,0.24.0 引入)与git:load-image(从标准输入流加载镜像 tar 归档,0.30.0 引入)。读完本文,你将掌握如何把任意 Docker 镜像作为应用部署源、如何解决镜像拉取与幂等重建问题、如何配置私有镜像登录与自定义构建上下文,以及这两条命令在源码层的完整执行链路。


一、为什么需要"从镜像初始化应用仓库"

Dokku 的应用模型以 git 仓库为核心:部署时 Dokku 接收代码、识别构建方式(buildpack / Dockerfile / CNB 等)并产出可运行镜像。但有一种常见场景无法套用这套模型——代码根本不在这台 Dokku 主机上

  • 应用镜像在远程 CI/CD 流水线中构建完成,只希望 Dokku 负责运行;
  • 团队不维护 Dokku 主机上的源码副本,镜像就是唯一交付物;
  • 需要持续跟踪某个第三方基础镜像的变更。

Dokku 的解法是:让一个"只含一行 FROM 的 Dockerfile"成为应用仓库的全部内容git:from-imagegit:load-image负责把这条FROM写入应用仓库,其余构建、部署流程与普通 Dockerfile 部署完全一致。

关联文档:docs/deployment/methods/image.md


二、git:from-image:从镜像仓库初始化应用

2.1 基本用法

git:from-image会初始化一个应用仓库,或将其更新为包含指定镜像的FROM指令:

dokku git:from-image node-js-app my-registry/node-js-getting-started:latest

执行后,Dokku 会像仓库中只包含下面这个 Dockerfile 一样构建应用:

FROM my-registry/node-js-getting-started:latest

这是跟踪"只部署某个镜像"变更的极佳方式,尤其是镜像由远端 CI/CD 流水线推送的场景——仓库里没有代码,只有对镜像的引用。

2.2 本地已存在镜像时的拉取行为与 --force

如果指定镜像已经存在于 Dokku 主机,Dokku 不会再次拉取(这是源码中明确的分支判断:先通过docker image ls -q $DOCKER_IMAGE检查本地是否已有该镜像,有则跳过docker image pull,参见 plugins/git/git-from-image)。

当远端镜像已更新、但 tag 保持不变时,需要强制重新拉取:

dokku git:from-image --force node-js-app my-registry/node-js-getting-started:latest

--force在实现上通过设置DOKKU_APPS_FORCE_DELETE=1环境变量来启用强制拉取分支(见 plugins/git/internal-functions)。

2.3 幂等性与镜像摘要(digest):避免"无变更提前退出"

对相同参数重复触发构建时,Dokku 检测不到任何变更,会提前以 0 退出,不会产生新的部署。源码对应分支在 plugins/git/git-from-directory:当git diff-index --quiet HEAD --判定无差异时,会输出No changes detected, skipping git commit警告并跳过提交。

因此,如果 tag 被复用但底层镜像内容已变化,强烈建议改用镜像 digest 而不是 tag。可通过以下命令获取 digest:

# 适用于已推送到远端 registry 的镜像 docker inspect --format='{{index .RepoDigests 0}}' $IMAGE_NAME # 适用于本地构建、未推送的镜像 # (当上面命令输出为空时使用) docker images --no-trunc --quiet $IMAGE_NAME

将 digest 用于git:from-image

# 其中镜像 sha 为:sha256:9d187c3025d03c033dcc71e3a284fee53be88cc4c0356a19242758bc80cab673 dokku git:from-image node-js-app my-registry/node-js-getting-started@sha256:9d187c3025d03c033dcc71e3a284fee53be88cc4c0356a19242758bc80cab673

2.4 自定义提交作者

git:from-image可选地接受 gituser.nameuser.email(按此顺序)来定制提交作者;留空时分别回退为Dokkuautomated@dokku.sh

dokku git:from-image node-js-app my-registry/node-js-getting-started:latest "Camila" "camila@example.com"

2.5 私有镜像:先登录 registry

如果镜像是需要 docker login 才能访问的私有镜像,应先用registry:login登录 registry,完整流程参见 registry 管理文档。源码层面,trigger-git-git-from-image会读取应用对应的DOCKER_CONFIG目录并导出(fn-registry-docker-config-dir "$APP"),从而让后续docker image pull使用已登录的凭证(见 plugins/git/git-from-image)。

2.6 --build-dir:自定义构建上下文

部分镜像依赖ONBUILD ADD/ONBUILD COPY指令,此时需要一个自定义构建上下文。通过--build-dir指定:

dokku git:from-image --build-dir path/to/build node-js-app domy-registrykku/node-js-getting-started:latest "Camila" "camila@example.com"

--build-dir下所有文件会被复制进仓库docker build过程使用。两个关键限制:

  1. 构建上下文必须每次部署时都指定,不会在构建之间持久化;
  2. 源码中会先校验目录存在性([[ ! -d "$BUILD_DIR" ]]时直接dokku_log_fail "Invalid BUILD_DIR specified for docker build context"),随后用rsync -a将目录内容同步进临时工作目录(见 plugins/git/git-from-image)。

关于 Dockerfile 部署的更多配置方式,参见 Dockerfile 构建文档。


三、git:load-image:无 Registry 场景的镜像部署

3.1 适用场景与基本用法

当环境里没有 Docker Registry 充当镜像存储中介时(例如在 CI 中构建镜像后直接部署,镜像不出 CI 机器),git:load-image可以从镜像归档 tar 文件初始化/更新应用仓库。

镜像通过标准输入流传输,典型的远端调用方式:

docker image save my-registry/node-js-getting-started:latest | ssh dokku@dokku.me git:load-image node-js-app my-registry/node-js-getting-started:latest

上述示例中:docker image save把镜像打成 tar 流 → 经 ssh 管道传送到 Dokku 主机 →git:load-image在输入流上执行。与git:from-image一致,Dokku 会像仓库只包含下面 Dockerfile 一样构建应用:

FROM my-registry/node-js-getting-started:latest

3.2 唯一镜像 tag 建议

通过git:load-image部署时,强烈建议在构建镜像时使用唯一 tag。否则与git:from-image相同的"无变更提前退出"问题会出现:复用 tag 会触发变更检测,若检测不到变化,Dokku 会以 0 提前退出。如果 tag 复用但底层镜像已变化,同样建议改用 digest(获取命令与上节完全相同):

# 适用于已推送到远端 registry 的镜像 docker inspect --format='{{index .RepoDigests 0}}' $IMAGE_NAME # 适用于本地构建、未推送的镜像 # (当上面命令输出为空时使用) docker images --no-trunc --quiet $IMAGE_NAME

使用 digest 的调用示例:

# 其中镜像 sha 为:sha256:9d187c3025d03c033dcc71e3a284fee53be88cc4c0356a19242758bc80cab673 docker image save my-registry/node-js-getting-started:latest | ssh dokku@dokku.me git:load-image node-js-app my-registry/node-js-getting-started@sha256:9d187c3025d03c033dcc71e3a284fee53be88cc4c0356a19242758bc80cab673

3.3 自定义提交作者

git:from-image相同,可选传入 gituser.nameuser.email(按此顺序),留空时回退为Dokkuautomated@dokku.sh

docker image save my-registry/node-js-getting-started:latest | ssh dokku@dokku.me git:load-image node-js-app my-registry/node-js-getting-started:latest "Camila" "camila@example.com"

3.4 --build-dir 自定义构建上下文

同样支持--build-dir以兼容依赖ONBUILD ADD/ONBUILD COPY的镜像:

docker image save my-registry/node-js-getting-started:latest | ssh dokku@dokku.me git:load-image --build-dir path/to/build node-js-app my-registry/node-js-getting-started:latest "Camila" "camila@example.com"

构建上下文同样每次部署都必须指定,不跨构建持久化。Dockerfile 部署的其他配置方式参见 Dockerfile 构建文档。


四、源码级执行链路解析

了解底层调用链有助于排查问题与理解行为差异。两条命令的核心实现位于 git 插件的 internal-functions(cmd-git-load-image见第 148 行、cmd-git-from-image见第 194 行),外层入口分别为 plugins/git/subcommands/from-image 与 plugins/git/subcommands/load-image,帮助信息定义在 plugins/git/help-functions。

4.1 参数解析与前置校验

两条命令共享相似的模式:

  • 遍历参数,识别--build-dir(以及git:from-image独有的--force)旗标,剩余位置参数依次对应APPDOCKER_IMAGEUSER_NAMEUSER_EMAIL
  • 通过verify_app_name校验应用名合法性;
  • git:from-image在镜像参数为空时输出Please specify a docker image并失败退出;
  • git:load-image额外校验标准输入必须是管道流而非终端([[ ! -t 0 ]],否则报Expecting tar archive containing docker image on STDIN),随后执行cat | docker load加载镜像,再用fn-verify-app-image确认 tar 中确实包含指定镜像,否则报Loaded image tarball but the specified docker image was not found

4.2 git-from-image 触发器:生成构建上下文

核心触发器 plugins/git/git-from-image 完成以下工作:

  1. 创建临时工作目录(mktemp);
  2. 若指定了--build-dir,用rsync -a同步构建上下文;
  3. 生成仅含两行的 Dockerfile:FROM $DOCKER_IMAGE与一条LABEL com.dokku.docker-image-labeler/alternate-tags=[\"$DOCKER_IMAGE\"](后者用于镜像标签标注);
  4. 按需导出应用级DOCKER_CONFIG(私有 registry 登录凭证);
  5. 镜像不存在时docker image pull;存在但开启--force(即DOKKU_APPS_FORCE_DELETE=1)时强制重新拉取;否则跳过拉取;
  6. 通过fn-plugin-property-write "git" "$APP" "source-image" "$DOCKER_IMAGE"持久化镜像来源;
  7. 触发git-from-directory进入仓库写入阶段。

4.3 git-from-directory 触发器:初始化或更新仓库

plugins/git/git-from-directory 负责真正的 git 操作:

  • 首次初始化git init、切到计算出的部署分支(fn-git-computed-deploy-branch)、配置user.name/user.emailadd --all后提交Initial commit
  • 更新已有仓库:克隆现有应用仓库、复制新的构建上下文、add --all后通过diff-index --quiet HEAD --做变更检测——无变更时输出No changes detected, skipping git commit并提示可用ps:rebuild从既有源码重建;有变更则以Automated commit @ <timestamp>提交并 fetch;
  • 最后调用git_receive_app进入常规部署流程(构建、发布、调度)。

这也解释了文档中"相同参数重复触发会提前退出"的根因:镜像引用未变 → Dockerfile 未变 → git 无差异 → 跳过提交,自然也就不会触发新的构建。

4.4 部署源记录

两条命令最终都会触发deploy-source-set "$APP" "docker-image" "$DOCKER_IMAGE"(见 plugins/git/internal-functions 与第 191 行),把应用的部署源标记为docker-image类型并记录镜像标识,供报告展示与后续重建使用。这是与git:from-archive(归档文件部署,见 plugins/git/subcommands/from-archive)并列的第三种"非 push 式"部署源。


五、实践建议与适用边界

场景推荐命令说明
镜像在远端 registry,主机可联网拉取git:from-image最直接,主机自行管理拉取;--force应对 tag 复用
CI 构建产物直接部署,无 registrygit:load-image镜像 tar 走 ssh 管道,不落中间存储
镜像 tag 复用且内容变化改用镜像 digest规避"无变更提前退出"
私有镜像registry:login应用级DOCKER_CONFIG自动生效
依赖ONBUILD ADD/COPY的镜像配合--build-dir构建上下文每次部署都要指定,不持久化

几点边界提醒:

  • 两条命令面向的是"镜像即部署物"的交付模式,与常规源码 push 部署是互补关系,不互相排斥;
  • 部署源(docker-image)与提交作者均可通过命令参数定制,未指定作者时统一回退为Dokku <automated@dokku.sh>
  • 若需要从 git 仓库而非镜像初始化/更新应用仓库,可参考同目录下的 git 部署文档 与 归档部署文档;构建阶段的行为细节可进一步阅读 Dockerfile 构建文档。

【免费下载链接】dokkuA docker-powered PaaS that helps you build and manage the lifecycle of applications项目地址: https://gitcode.com/GitHub_Trending/do/dokku

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询