mcpField
D
dokploy-ghcr-deploy

dokploy-ghcr-deploy

github.com/jeffreyyvdb云与 DevOps251 次安装27 周前更新
代码仓库

关于 dokploy-ghcr-deploy

dokploy-ghcr-deploy 是部署技能,用于配置 Docker 化的 GitHub 仓库,将镜像发布到 GHCR,并在 main 分支更新时通过 Dokploy 部署。它按阶段指导设置 GitHub Actions、Dokploy、密钥及手动配置镜像仓库令牌。

主要功能

  1. 01准备 GitHub Actions 发布工作流
  2. 02将 Docker 镜像发布到 GHCR
  3. 03通过 Dokploy MCP 工具配置应用
  4. 04使用 gh 设置 GitHub 仓库密钥
  5. 05指导手动配置 GHCR 令牌

适用场景

  1. 01设置 main 更新后的自动部署
  2. 02将 GitHub 仓库连接到 Dokploy 应用
  3. 03配置 GHCR 镜像发布和访问
  4. 04在首次发布前验证部署触发流程

MCP 相关

此技能要求连接 Dokploy MCP 服务,并使用其工具创建和配置 Dokploy 项目、应用、域名及 API 密钥。随后由 GitHub Actions 调用 Dokploy 部署 API。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jeffreyyvdb/dokploy-ghcr-deploy --skill dokploy-ghcr-deploy

安装后在 Claude Code 中输入/dokploy-ghcr-deploy确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

LICENSE
README.md
assets/
docker-publish.yml.template

详细介绍

Dokploy + GHCR 自动部署

端到端操作指南:将 GitHub 仓库中的 Docker 化应用配置为 Dokploy 应用,使其在每次推送到 main 时自动重新部署。构建在 GitHub Actions 中进行;镜像推送到 GHCR(默认私有);工作流的最后一步通过 REST 调用让 Dokploy 拉取并重新部署。

采用此流程的原因:

  • 选择 GHCR,而非 Docker Hub——Docker Hub 的免费套餐最多只能有 1 个私有仓库,而 GHCR 提供无限量的私有包。推送端使用内置的 GITHUB_TOKEN 进行身份验证,工作流端无需额外的 PAT。
  • 选择 API 触发,而非仓库 Webhook——GHCR 不会触发推送 Webhook,因此工作流会向 Dokploy 的 /api/application.deploy 发送 POST 请求,而不是依赖仓库端 Webhook(Docker Hub → Dokploy 的工作方式就是如此)。

请按顺序完成各阶段。每个阶段都有明确的停止条件;如果有步骤未通过,请勿跳到后续阶段。

前置条件——开始前检查

尽可能在后台并行完成以下检查;只向用户说明发现的问题。

  1. Dockerfile 存在并公开一个端口。 阅读 Dockerfile。搜索 EXPOSE,记录端口号——稍后配置 Dokploy 域名时会用到。如果没有 Dockerfile 或没有 EXPOSE,请停止并询问用户;不要根据框架默认值擅自编写 Dockerfile(这属于未经确认的猜测)。
  2. .dockerignore 存在。 如果缺失,提出添加一个最简文件(包含 node_modules、.git、build、dist、测试文件、.env*)。这不是阻塞项。
  3. gh CLI 已通过身份验证。 gh auth status 应显示一个已激活的账户。如果没有,请停止并让用户先运行 gh auth login。
  4. 已连接 Dokploy MCP。 调用 mcp__dokploy-mcp__user-session。如果调用报错,请停止并让用户先连接 Dokploy MCP;没有它,此技能无法完成 Dokploy 相关操作。
  5. GitHub 远程仓库。 解析 git remote get-url origin 以提取 owner/repo。将其转为小写——GHCR 不接受镜像路径中的大写字母。如果远程仓库不在 GitHub 上,则此技能不适用;请告知用户。

收集用户输入

将以下问题合并到一次 AskUserQuestion 调用中,让用户一次性回答,而不是分五次询问。括号中为默认值——预先填入并允许用户修改:

  • Dokploy 项目名称(默认:仓库名称)
  • Dokploy 应用名称(默认:web)
  • 要绑定的公开域名(该域名必须已解析到 Dokploy 主机;如果用户有类似 *.example.com 的通配符域名,建议使用 <project>.example.com)
  • Dokploy 基础 URL(例如 https://dokploy.example.com)——无法推断此 URL,务必询问
  • 除 APP_ENV=production 之外的额外环境变量——可选择跳过;之后也可以在 Dokploy UI 中添加。发送到 application-saveEnvironment 前,验证每一项是否匹配 ^[A-Z_][A-Z0-9_]*=,并拒绝包含原始换行符的值,避免某个值中意外出现换行符后悄悄注入另一个变量。

阶段 A——准备仓库

  1. 根据 assets/docker-publish.yml.template 编写 .github/workflows/docker-publish.yml。该模板使用 ${{ github.repository }},并在运行时将其转为小写,因此大多数仓库都可以直接使用——通常无需替换任何内容。
  2. 如果当前不在功能分支上,请创建一个功能分支(不要直接提交到 main——我们希望配置好密钥后,通过 PR 原子性地合入该工作流)。 3.暂存并提交该工作流。暂时不要推送——我们希望先配置好 Dokploy 和 GitHub 密钥,否则首次工作流运行时会针对尚未就绪的应用启动,导致部署历史中留下失败记录。

阶段 B — 通过 MCP 设置 Dokploy

按顺序执行,遇错即停。每次工具调用都会生成后续步骤需要的 ID——请在执行过程中记录。

  1. 解析组织 — 调用 mcp__dokploy-mcp__organization-active 并保存 organizationId。
  2. 使用 name 和简短的 description 调用 mcp__dokploy-mcp__project-create。响应包含 projectId 和自动创建的默认 environmentId(名为 production)——请同时保存。
  3. 使用 name(应用名称)和 environmentId 调用 mcp__dokploy-mcp__application-create。保存 applicationId。应用的初始 sourceType 为 "github";保存 Docker 提供程序后,它会切换为 docker。
  4. 使用以下参数调用 mcp__dokploy-mcp__application-saveDockerProvider:
    • applicationId
    • dockerImage: "ghcr.io/<lowercase-owner>/<lowercase-repo>:latest"
    • registryUrl: "ghcr.io"
    • username: "<lowercase-owner>"
    • password: "PAT_PLACEHOLDER" — 此占位值可确保 MCP 调用有效,并且会保留原样。真实 PAT 由用户在阶段 E 直接设置到 Dokploy UI 中,因此不会经过本次对话。
  5. 使用以下参数调用 mcp__dokploy-mcp__application-saveEnvironment:
    • applicationId
    • createEnvFile: true
    • env: "APP_ENV=production\n..."(以及用户添加的其他内容)
    • buildArgs: ""、buildSecrets: "" — 显式设置为空字符串,不能使用 undefined。参见注意事项。
  6. 使用以下参数调用 mcp__dokploy-mcp__domain-create:
    • applicationId
    • host: "<domain-the-user-gave>"
    • port: <port-from-Dockerfile>
    • https: true、certificateType: "letsencrypt"
    • path: "/"、stripPath: false、domainType: "application"
  7. 使用 name: "github-actions-deploy-<repo>" 和 metadata: {"organizationId": "<from step 1>"} 调用 mcp__dokploy-mcp__user-createApiKey。保存 key——它只会显示一次。提醒用户默认速率限制为每 24 小时 10 次请求;如果经常向 main 推送,可建议用户通过 Dokploy UI 提高限制。

阶段 C — 通过 gh 设置 GitHub 密钥

一次性批量执行三个密钥的 Bash 调用,这样用户只需批准一次:

gh secret set DOKPLOY_URL --repo <owner>/<repo> --body "<dokploy-base-url>" && \
gh secret set DOKPLOY_API_KEY --repo <owner>/<repo> --body "<api-key-from-B7>" && \
gh secret set DOKPLOY_APPLICATION_ID --repo <owner>/<repo> --body "<applicationId-from-B3>"

接着,在推送代码前对 API 进行冒烟测试。read -s 可避免将密钥写入 ~/.bash_history;末尾的 unset 会将其从 shell 中清除,避免它残留在进程环境中:

read -rsp "Paste DOKPLOY_API_KEY (not echoed): " DOKPLOY_API_KEY; echo
DOKPLOY_URL='https://your-dokploy.example.com'
APP_ID='<applicationId from B3>'
DOKPLOY_API_KEY="$DOKPLOY_API_KEY" \
  curl -fsS --max-time 30 -o /dev/null -w "%{http_code}\n" \
  -X POST "${DOKPLOY_URL%/}/api/application.deploy" \
  -H "x-api-key: $DOKPLOY_API_KEY" \
  -H "Content-Type: application/json" \
  --data "$(jq -cn --arg id "$APP_ID" '{applicationId:$id}')"
unset DOKPLOY_API_KEY

预期结果为 200。其他任何结果都表示 URL、密钥或应用 ID 有误——请先修复再继续。部署会失败(尚未推送镜像),但触发操作应该成功;这能证明身份验证链路正常。

阶段 D — 推送并创建 PR

推送分支,并使用 gh pr create 创建 PR。PR 正文应说明:

  • 必须设置的三个密钥(确认它们已设置)
  • Dokploy 应用详情(项目、应用、域名、端口)
  • 合并后会触发首次实际部署

阶段 E — GHCR PAT(唯一的手动步骤)

GitHub 没有用于生成 PAT 的 API,所以用户必须在 UI 中完成这一步。不要假装可以自动完成。

PAT 绝不能经过本次对话。 聊天记录中的 read:packages PAT 属于凭据泄露——对话记录通常会保留在服务器端,而且该 PAT 可以拉取用户能访问的所有私有软件包。因此,用户应将其直接粘贴到 Dokploy,而不是粘贴到聊天中。不要要求用户在这里粘贴,也不要使用 mcp__dokploy-mcp__application-saveDockerProvider 调用真实值;应通过 Dokploy UI 原位替换阶段 B 步骤 4 中的 PAT_PLACEHOLDER 占位值。

请逐字告诉用户:

  1. GitHub → Settings → Developer settings → Personal access tokens (classic) → Generate new token → 仅勾选 read:packages 权限范围 → 将有效期设为 90 days(这是 GitHub 为机器凭据推荐的最长有效期;不要选择“No expiration”)→ 生成 → 将令牌复制到剪贴板。
  2. Dokploy → Projects → 你的项目 → 你的应用 → General → Docker provider → 将令牌粘贴到 Password 字段 → Save。
  3. 在此回复“saved”(不要发送令牌,也不要粘贴令牌)。

只有在用户确认“saved”后,才进入阶段 F。

如需轮换,流程相同:在 GitHub 撤销旧 PAT,生成新的 PAT,然后粘贴到 Dokploy UI。无需经过聊天。

这一步无法自动化的原因:gh CLI 令牌默认不包含 read:packages(其权限范围通常为 repo, read:org, gist, admin:public_key);运行 gh auth refresh -s read:packages 会生成一个用户范围的 OAuth 令牌,且仍附带其他所有权限范围——将它作为服务密码存储会带来过多权限。通过 Dokploy UI 设置一个权限范围仅为 read:packages 的专用 classic PAT,是最妥当的做法。

阶段 F — 首次部署

  1. 合并 PR(或推送到 main)。工作流将会触发。
  2. 查看 Actions 选项卡:构建应推送两个标签(latest 和 sha-<short>),最后一步应从 Dokploy 收到 2xx 响应。
  3. 在 Dokploy → app → Deployments 中,确认有一次新部署依次从“Pulling”→“Running”→“Done”。
  4. 访问域名;预期应用会在 Dockerfile 指定的端口上响应。

如果 Dokploy 部署显示来自 ghcr.io/v2/ 的“denied: denied”,说明 PAT 错误或已过期——返回阶段 E。

注意事项(都是血泪教训)

  • MCP zod 联合类型不接受 undefined。 application-saveDockerProvider 要求必须提供 registryUrl, username, password 的全部值(传入空字符串或真实值,不要省略)。application-saveEnvironment 要求提供 buildArgs 和 buildSecrets——传入 ""。省略这些值会因不透明的验证错误而白白多耗一轮。
  • GHCR 镜像路径必须全部使用小写字母。 工作流模板通过 ${IMAGE_NAME,,} 处理了这一点。若手动编写,别忘了。
  • 不要为 GHCR 推荐 Docker Hub webhook 流程。 GHCR 不支持推送 webhook。Dokploy 文档只在 Docker Hub 的相关说明中提到了 webhook 流程。
  • Docker Hub 免费套餐仅支持 1 个私有仓库。 这就是此技能默认使用 GHCR 的原因。只在解释为何不使用 Docker Hub 时提到它。
  • 软件包可见性。 GHCR 软件包首次推送时会继承源仓库的可见性——私有仓库 → 私有软件包。无需额外的 API 调用。如果仓库是公开的,软件包也会公开;只需告知用户一次。
  • Dokploy API 密钥的默认速率限制为 10 次/24 小时。 对大多数“推送到 main”工作流来说足够了。如果用户每天部署很多次(例如,采用基于主干开发且经常合并),可在 Dokploy UI 中提高限制。
  • gh auth status 显示的权限范围不足以拉取 GHCR 镜像。 典型的 gh 令牌包含 repo, read:org, gist, admin:public_key——不包含 read:packages。因此阶段 E 不能依赖 CLI 令牌。
  • 不要重命名 APP_ENV。 同时支持 Vercel 和 Dokploy 部署的代码库通常会专门根据 APP_ENV 分支,以避免与 VERCEL_ENV 混淆。在 Dokploy 中始终将其设为 production。

此技能有意不做的事

  • 不迁移现有 Dokploy 应用的域名——如果用户要替换一个以 GitHub 为源的 Dokploy 应用,请询问是要在新项目中创建新应用(干净无影响,旧应用也不会停机),还是就地重新配置(需要切换域名)。默认选择新项目。
  • 不会将环境变量从一个应用复制到另一个应用。列出环境变量没问题;盲目地在应用之间复制 Stripe/DB 密钥,可能会导致覆盖或重复写入。
  • 不设置预览部署、健康检查或副本。这属于范围蔓延;用户提出要求时再添加。

评论

支持 Markdown