使用 Encore CLI 集成 CI/CD 流水线:Docker 镜像构建与自动化部署实战
【免费下载链接】encoreThe infrastructure platform for the intelligence era项目地址: https://gitcode.com/GitHub_Trending/encor/encore
Encore 提供了与任何主流 CI/CD 流水线无缝集成的 CLI 工具链,其中最核心的是encore build docker命令——一条命令即可把 Encore 应用打包为可移植的 Docker 镜像,从而接入 GitHub Actions、GitLab CI、Jenkins 等任意构建编排系统。本文基于 Encore 开源仓库中的 docs/go/self-host/ci-cd.md,结合 CLI 与镜像构建的源码实现,完整讲解 CI 环境中的 CLI 安装认证、镜像构建参数、平台差异处理与端口定制,并给出一个可直接照抄的 GitHub Actions + DigitalOcean 部署示例。读完本文,你将能够把 Encore 应用稳定地接入自己的 CI/CD 流水线,实现"代码推送即自动构建、推送、部署"的完整闭环。
一、CI/CD 集成总体思路:四个关键步骤
虽然每家 CI/CD 流水线的形态各不相同,但集成 Encore 遵循一个非常统一的流程:
- 安装 Encore CLI:在 CI 环境中安装 Encore CLI(runner 或构建容器内);
- 构建 Docker 镜像:使用
encore build docker命令生成应用镜像; - 推送镜像:将镜像推送到你的容器镜像仓库(Container Registry);
- 部署:由你的基础设施按既定策略拉取并部署新镜像。
所有主流 CI/CD 平台都能按此模式集成,差异仅在于各平台调用 CLI 的具体语法(如 GitHub Actions 的run步骤、GitLab CI 的script字段等)。具体到 CLI 工具的接入方式,可以参考你所使用平台的官方文档。
二、CI 环境中的 CLI 安装与认证
2.1 安装 Encore CLI
Encore CLI 本身就是一个静态分发的命令行工具。在你的 CI 流水线中,下载官方安装脚本并执行即可完成安装。以 GitHub Actions 为例,可以通过curl拉取安装脚本后执行:
curl --output install.sh -L https://encore.dev/install.sh bash install.sh安装完成后,可执行文件位于/home/runner/.encore/bin/encore(不同平台的默认安装目录可能不同,建议在安装步骤中确认实际路径,并在后续步骤中统一使用该绝对路径调用)。
2.2 使用 Auth Key 进行非交互式认证
在本地开发环境中,开发者通常通过encore auth login的交互式设备授权(Device Auth)流程登录。但在 CI 环境中无法进行交互式浏览器授权,因此 Encore 提供了Auth Key(认证密钥)机制用于非交互式认证。
在 Encore Cloud(若你的应用与其关联)中,从App Settings > Auth Keys页面生成一个 Auth Key,将其作为 CI secret 存储到你的 CI 平台中,然后在构建之前执行:
encore auth login --auth-key=${{ secrets.ENCORE_AUTH_KEY }}从源码看,该机制位于 cli/cmd/encore/auth/auth.go:
encore auth login支持--auth-key(短选项-k)参数,定义见 auth.go 第 76 行;- 当
--auth-key非空时,CLI 调用DoLoginWithAuthKey(),内部走login.WithAuthKey()流程,将凭证写入本地配置文件(auth.go 第 123-133 行);未指定时则回退到设备授权流程。
这也意味着:如果你的自托管/自有基础设施部署不依赖 Encore Cloud,而是完全通过本地 daemon 与 Docker 交互构建,那么这一步认证可以按需省略(详见下文对--push与镜像推送的说明)。
三、GitHub Actions 完整示例:构建、推送并部署到 DigitalOcean
下面这段工作流来自 ci-cd.md,展示了完整的"提交到main分支 → 构建镜像 → 推送镜像 → 触发部署"闭环。示例中 DigitalOcean 应用被配置为:每当仓库中出现latest标签的镜像被上传时,自动重新部署。
name: Build, Push and Deploy a Encore Docker Image to DigitalOcean on: push: branches: [ main ] permissions: contents: read packages: write jobs: build-push-deploy-image: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Download Encore CLI script uses: sozo-design/curl@v1.0.2 with: args: --output install.sh -L https://encore.dev/install.sh - name: Install Encore CLI run: bash install.sh - name: Authenticate with Encore run: /home/runner/.encore/bin/encore auth login --auth-key=${{ secrets.ENCORE_AUTH_KEY }} - name: Log in to DigitalOcean container registry run: docker login registry.digitalocean.com -u my-email@gmail.com -p ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} - name: Build Docker image run: /home/runner/.encore/bin/encore build docker myapp - name: Tag Docker image run: docker tag myapp registry.digitalocean.com/<YOUR_CONTAINER_REGISTRY_NAME>/<YOUR_IMAGE_REPOSITORY_NAME>:latest - name: Push Docker image run: docker push registry.digitalocean.com/<YOUR_CONTAINER_REGISTRY_NAME>/<YOUR_IMAGE_REPOSITORY_NAME>:latest拆解各步骤的作用:
| 步骤 | 说明 |
|---|---|
| Checkout repository | 拉取源码,actions/checkout@v4是官方 checkout action |
| Download / Install Encore CLI | 下载并执行官方安装脚本,安装 Encore CLI |
| Authenticate with Encore | 使用ENCORE_AUTH_KEY这个 CI secret 完成非交互式登录 |
| Log in to DigitalOcean container registry | 使用DIGITALOCEAN_ACCESS_TOKEN登录 DigitalOcean 容器仓库(此处账号替换为你自己的注册邮箱) |
| Build Docker image | 调用encore build docker myapp,在本地 Docker daemon 中生成名为myapp的镜像(IMAGE_TAG即myapp) |
| Tag Docker image | 将本地镜像打上目标仓库的latest标签 |
| Push Docker image | 推送到容器仓库,触发 DigitalOcean 侧配置的自动重部署 |
使用这套工作流时,需要把my-email@gmail.com、<YOUR_CONTAINER_REGISTRY_NAME>、<YOUR_IMAGE_REPOSITORY_NAME>替换为你自己的实际值,并在 GitHub 仓库的 Settings → Secrets 中配置ENCORE_AUTH_KEY与DIGITALOCEAN_ACCESS_TOKEN。
3.1 为什么先encore build docker再用docker tag
细心的读者会发现:示例中先让 Encore 构建出本地镜像,再用docker tag打上目标仓库标签。这是因为encore build docker默认把镜像输出到本地 Docker daemon(镜像名即你传入的IMAGE_TAG),而不是直接推到远端。从 cli/daemon/export/export.go 的源码可以看到:
- 未指定
--push时,LocalDaemonTag被设置,镜像导出到本地 daemon; - 指定
--push时,PushDestinationTag被设置,镜像直接推送远端。
因此,默认模式下构建完成后用docker tag+docker push手动编排标签与推送,是灵活且常见的做法。
四、深入encore build docker:参数与平台定制
encore build docker提供了丰富的选项用于定制构建行为。以下是 ci-cd.md 中给出的三种典型用法:
# 构建指定的服务和网关 encore build docker --services=service1,service2 --gateways=api-gateway MY-IMAGE:TAG # 自定义基础镜像 encore build docker --base=node:18-alpine MY-IMAGE:TAG # 为特定架构构建(当 CI 架构与部署目标不一致时尤其有用) encore build docker --arch=arm64 MY-IMAGE:TAG结合 cli/cmd/encore/build.go 的源码,该命令支持的全部参数如下:
| 参数 | 源码定义 | 默认值 | 说明 |
|---|---|---|---|
IMAGE_TAG(位置参数) | cobra.ExactArgs(1) | 必填 | 镜像标签名,作为镜像名称使用 |
--services | StringSlice | 全部 | 仅包含指定服务,多个用逗号分隔 |
--gateways | StringSlice | 全部 | 仅包含指定网关,多个用逗号分隔 |
--base | String | scratch | 基础镜像;Go 应用默认scratch,TS 应用自动回退为node:slim |
--arch | Oneof | amd64 | 目标架构,仅允许amd64/arm64 |
--os | Oneof | linux | 目标操作系统,当前仅允许linux |
--cgo | Bool | 默认取CGO_ENABLED或应用配置 | 是否启用 cgo |
--push/-p | Bool | false | 构建后直接推送镜像到远端仓库 |
--config | String | 空 | 指定基础设施配置文件(infra config)路径 |
--skip-config | Bool | false | 不读取也不生成基础设施配置文件 |
几点从源码确认的重要细节:
- 基础镜像的默认值不是写死的:CLI 会读取应用根目录下的应用配置文件(
appfile.ParseFile),当检测到是 TypeScript 应用且用户未显式指定--base时,自动使用node:slim作为基础镜像(见 build.go 第 51-59 行);Go 应用则保持scratch空镜像。 - 架构选择应对"CI 与部署目标不一致":例如 CI runner 是 amd64,而生产环境是 arm64 服务器,通过
--arch=arm64即可在 x86 的 CI 上产出 arm64 镜像。 build命令带有eject别名:encore build整体负责"为部署构建你的应用",docker是它的子命令;从源码结构看,未来还可能扩展其他输出格式。
4.1 关于--push直推模式
如果你的部署流水线希望跳过docker tag的中间步骤,可以直接使用--push配合完整的目标仓库地址:
encore build docker --push registry.example.com/myorg/myapp:latest此时镜像构建完成后会直接推送到远端仓库(对应PushDestinationTag逻辑),推送认证依赖执行环境中已配置好的 Docker/仓库凭据。
五、镜像运行时行为:端口与环境变量
encore build docker产出的镜像默认在 8080 端口监听,你可以通过设置PORT环境变量在启动时自定义端口:
docker run -e PORT=8081 -p 8081:8081 MY-IMAGE:TAG这条规则的实现位于 supervisor(镜像内的进程管理组件)源码中。镜像入口由 supervisor 进程代理,它启动时会读取环境变量来决定监听端口:
- supervisor/src/bin/supervisor-encore.rs:从
PORT环境变量读取端口,未设置时回退到默认值8080; - supervisor/src/config.rs:将
PORT写入 supervisor 的运行时配置中,供内部各服务端口分配使用。
因此在容器编排平台(如 Kubernetes、DigitalOcean App Platform)中,直接通过环境变量注入PORT即可适配平台要求的不同端口,无需重新构建镜像。
六、源码视角:encore build docker背后发生了什么
理解镜像构建的内部实现,有助于排查 CI 中的构建问题。整个流程分布在两个层面:
6.1 CLI 层:把参数翻译成 daemon 请求
encore build docker的 CLI 实现(cli/cmd/encore/build.go)本身并不直接打镜像,而是:
- 解析参数,组装
DockerExportParams(基础镜像、本地 daemon 标签或推送目标标签); - 解析
--config为绝对路径(build.go 第 121-127 行); - 连接本地 daemon,通过 gRPC 调用
daemon.Export,请求中携带Goos/Goarch/CgoEnabled、Services/Gateways列表以及基础设施配置路径; - 实时流式输出构建日志(
cmdutil.StreamCommandOutput)。
6.2 daemon 层:镜像如何被组装
真正执行镜像构建的是 pkg/dockerbuild/dockerbuild.go 中的BuildImage函数。其核心步骤包括:
- 解析基础镜像:
scratch或空字符串解析为空镜像,其他基础镜像通过remote.Image从远端拉取(dockerbuild.go 第 135-153 行),并按目标 OS/架构(remote.WithPlatform)拉取对应平台变体; - 分层打包文件系统:
buildImageFilesystem依次组装源码层、依赖层、运行时层(supervisor 二进制)、配置层(supervisor 配置、构建信息)以及证书层(CA 证书,写入/etc/ssl/certs/ca-certificates.crt)等多个镜像层; - 固定时间戳保证可复现:所有文件使用固定的
layerEpoch(Unix 时间 0)作为时间戳,使未变化的层在不同构建之间保持相同 digest(dockerbuild.go 第 32-35 行)——这意味着 CI 中重复构建相同代码可以得到可复现的镜像层,利于缓存与增量部署; - 设置镜像配置:写入入口点(Entrypoint)、工作目录、环境变量、架构与系统类型,并标注
encore.dev作为作者。
需要 CA 证书的场景(如镜像内需要访问外部 HTTPS 服务)由--base基础镜像的内容与证书层共同决定;使用scratch作为基础镜像时,默认不包含证书,这一点在定制基础镜像时需要注意。
七、CI/CD 集成最佳实践小结
综合文档与源码,落地 Encore CI/CD 集成时建议遵循以下几点:
- 在 CI 中始终使用非交互式认证:通过 Auth Key(
encore auth login --auth-key=<KEY>)代替本地设备授权;Auth Key 作为 CI secret 管理,详见 auth-keys 文档。 - 固定 CLI 安装路径:CI 中安装 Encore CLI 后,后续步骤统一使用绝对路径(如
/home/runner/.encore/bin/encore)调用,避免 PATH 不一致导致的偶发失败。 - 区分构建机架构与目标架构:当 CI runner 架构与部署目标不同(如 amd64 runner 部署到 arm64 集群)时,用
--arch指定目标架构。 - 按需裁剪镜像内容:多服务应用可通过
--services/--gateways仅打包需要的部分,加快构建与拉取速度。 - 端口交给平台注入:镜像默认监听 8080,通过
PORT环境变量适配各平台,尽量不在镜像内硬编码端口。 - 善用"推送即部署"模式:配合 DigitalOcean、Kubernetes 等平台的"镜像更新自动重部署"能力,构建完成后直接推送带
latest或版本标签的镜像即可触发部署,无需额外部署步骤。
至此,你已经掌握了 Encore 应用接入 CI/CD 的完整链路:安装认证 →encore build docker构建 → 镜像推送 → 平台自动部署。接下来可以进一步阅读配置基础设施与自托管总览,了解镜像部署到自有基础设施时的环境变量、基础设施配置与服务发现细节。
【免费下载链接】encoreThe infrastructure platform for the intelligence era项目地址: https://gitcode.com/GitHub_Trending/encor/encore
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考