feat(docker): publish multi-arch image to GHCR (#72)

Signed-off-by: Kevin Cui <[email protected]>
This commit is contained in:
Kevin Cui
2026-07-10 20:33:27 -04:00
committed by GitHub
parent dec9989331
commit 6d23b13414
10 changed files with 455 additions and 13 deletions
+147
View File
@@ -0,0 +1,147 @@
name: Publish Docker Image
# Build the OpenConnector image from docker/Dockerfile and publish it to the
# GitHub Packages container registry (GHCR) at ghcr.io/<owner>/<repo>.
#
# Triggers and tags:
# - push to main (this includes merged PRs): `tip` + the short commit hash
# - published release: `latest` + the release version (e.g. v1.0.0)
#
# The image is multi-arch (linux/amd64 + linux/arm64). Each architecture is
# built NATIVELY on its own Blacksmith runner (no QEMU emulation), pushed by
# digest, and the two are then merged into a single multi-arch manifest per tag.
#
# main-branch pushes and releases never overlap: `push` ignores tag refs and
# publishing a release does not fire a branch `push`. See docs/docker-ghcr.md.
on:
push:
branches: [main]
release:
types: [published]
# One in-flight publish per ref. main pushes share a group so a newer commit
# cancels an older, still-running build — this keeps `tip` pointing at the most
# recent commit. Releases use their own per-tag group and are never cancelled.
concurrency:
group: publish-docker-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'push' }}
# Least privilege: read the repo, and write packages to push the image to GHCR.
permissions:
contents: read
packages: write
env:
REGISTRY: ghcr.io
# ghcr.io/oomol-lab/open-connector — GHCR auto-links the package to this repository.
IMAGE_NAME: ${{ github.repository }}
jobs:
# Build each architecture natively and push it to GHCR by digest (no tags yet).
build:
name: Build ${{ matrix.platform }}
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: blacksmith-4vcpu-ubuntu-2404
pair: linux-amd64
# Native arm64 hardware; the `-arm` suffix picks a Blacksmith ARM runner.
- platform: linux/arm64
runner: blacksmith-4vcpu-ubuntu-2404-arm
pair: linux-arm64
runs-on: ${{ matrix.runner }}
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
# OCI image labels; tags are applied later, on the merged manifest.
- name: Compute labels
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Blacksmith's Docker builder keeps a per-Dockerfile layer cache on a
# sticky disk (one per architecture), so no cache-from/cache-to is needed.
- name: Set up Blacksmith Docker builder
uses: useblacksmith/setup-docker-builder@v1
- name: Build and push by digest
id: build
uses: useblacksmith/build-push-action@v2
with:
context: .
file: docker/Dockerfile
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
# Single-manifest per arch; skip the provenance attestation.
provenance: false
outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
- name: Export digest
run: |
mkdir -p "${{ runner.temp }}/digests"
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v7
with:
name: digests-${{ matrix.pair }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
# Merge the per-arch digests into one multi-arch manifest per computed tag.
merge:
name: Merge & Push manifest
needs: build
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- name: Download digests
uses: actions/download-artifact@v8
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Same tag scheme as before: tip + short-sha on push, latest + version on release.
- name: Compute tags
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
flavor: latest=false
tags: |
type=raw,value=tip,enable=${{ github.event_name == 'push' }}
type=sha,prefix=,format=short,enable=${{ github.event_name == 'push' }}
type=raw,value=latest,enable=${{ github.event_name == 'release' && github.event.release.prerelease == false }}
type=raw,value=${{ github.event.release.tag_name }},enable=${{ github.event_name == 'release' }}
- name: Create and push multi-arch manifest
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create \
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
- name: Inspect manifest
run: docker buildx imagetools inspect "$(jq -cr '.tags[0]' <<< "$DOCKER_METADATA_OUTPUT_JSON")"
+17 -2
View File
@@ -128,10 +128,16 @@ run `npm run deploy:cloudflare`.
## Quick Start
Start the runtime with Docker Compose:
Start the runtime from the published image with Docker Compose:
```bash
docker compose up --build
docker compose up
```
This pulls `ghcr.io/oomol-lab/open-connector:latest`. To build from source instead:
```bash
docker compose -f docker-compose.yml -f docker-compose.build.yml up --build
```
Open the local console and generated API reference:
@@ -195,6 +201,14 @@ Fly volume.
See [docs/fly-io.md](docs/fly-io.md) for app creation, volume setup, secrets, deployment, custom
domains, and scaling.
## Docker Image (GHCR)
Run OpenConnector from a prebuilt image on GitHub Packages (GHCR): `ghcr.io/oomol-lab/open-connector`. Use
`latest` for the newest release, a pinned version like `v1.0.0` for production, or `tip` for the
latest `main` build.
See [docs/docker-ghcr.md](docs/docker-ghcr.md) for tags, pulling, and running.
## Want to Use It Directly?
The paths above are for teams integrating connectors into their own products, runtimes, or
@@ -220,6 +234,7 @@ create, and sync across connected tools.
- [Runtime API and MCP](docs/runtime-api.md)
- [Fly.io deployment](docs/fly-io.md)
- [Cloudflare deployment](docs/cloudflare.md)
- [Docker image (GHCR)](docs/docker-ghcr.md)
- [Configuration](docs/configuration.md)
- [Credentials and OAuth](docs/credentials.md)
- [Catalog format](docs/catalog-format.md)
+12
View File
@@ -0,0 +1,12 @@
# Build overlay for local development.
#
# Builds the image from docker/Dockerfile instead of pulling the published one,
# and tags it as ghcr.io/oomol-lab/open-connector:latest (the name in docker-compose.yml).
#
# Usage:
# docker compose -f docker-compose.yml -f docker-compose.build.yml up --build
services:
connector:
build:
context: .
dockerfile: docker/Dockerfile
+3 -3
View File
@@ -1,8 +1,8 @@
# Runs the prebuilt image published to GHCR. To build from source instead, add
# the build overlay: docker compose -f docker-compose.yml -f docker-compose.build.yml up --build
services:
connector:
build:
context: .
dockerfile: docker/Dockerfile
image: ghcr.io/oomol-lab/open-connector:latest
ports:
- "3000:3000"
volumes:
+17 -2
View File
@@ -131,10 +131,16 @@ secrets requis et exécuter `npm run deploy:cloudflare`.
## Démarrage Rapide
Démarrez le runtime avec Docker Compose :
Démarrez le runtime depuis l'image publiée avec Docker Compose :
```bash
docker compose up --build
docker compose up
```
Cela récupère `ghcr.io/oomol-lab/open-connector:latest`. Pour builder depuis les sources :
```bash
docker compose -f docker-compose.yml -f docker-compose.build.yml up --build
```
Ouvrez la console locale et la référence API générée :
@@ -195,6 +201,14 @@ persistant sur un volume Fly.
Consultez [fly-io.md](fly-io.md) pour créer l'app Fly, configurer le volume et les secrets,
déployer, définir un domaine personnalisé et ajuster le scaling.
## Image Docker (GHCR)
Exécutez OpenConnector depuis une image préconstruite sur GitHub Packages (GHCR) :
`ghcr.io/oomol-lab/open-connector`. Utilisez `latest` pour la dernière release, une version épinglée comme
`v1.0.0` en production, ou `tip` pour le dernier build de `main`.
Consultez [docker-ghcr.md (anglais)](docker-ghcr.md) pour les tags d'image, le pull et l'exécution.
## Vous voulez l'utiliser directement ?
Les parcours ci-dessus s'adressent aux équipes qui intègrent le connector dans leurs produits,
@@ -220,6 +234,7 @@ synchroniser dans les outils connectés en natural language.
- [Runtime API et MCP](runtime-api.md)
- [Déploiement Fly.io](fly-io.md)
- [Déploiement Cloudflare](cloudflare.md)
- [Image Docker (GHCR) (anglais)](docker-ghcr.md)
- [Configuration](configuration.md)
- [Credentials et OAuth](credentials.md)
- [Format du catalog](catalog-format.md)
+17 -2
View File
@@ -119,10 +119,16 @@ OpenConnector を Cloudflare の Workers、D1、R2、Web Console で起動する
## クイックスタート
Docker Compose で runtime を起動します。
公開イメージから Docker Compose で runtime を起動します。
```bash
docker compose up --build
docker compose up
```
これは `ghcr.io/oomol-lab/open-connector:latest` を pull します。ソースからビルドする場合:
```bash
docker compose -f docker-compose.yml -f docker-compose.build.yml up --build
```
ローカル console と生成された API reference を開きます。
@@ -182,6 +188,14 @@ volume に永続化します。
Fly app 作成、volume、secret、deployment、custom domain、scaling については
[fly-io.md](fly-io.md) を参照してください。
## Docker イメージ(GHCR)
事前ビルドされた Docker イメージで OpenConnector を実行できます(GitHub Packages / GHCR):
`ghcr.io/oomol-lab/open-connector`。最新 release は `latest`、production では `v1.0.0` のように version を固定、
最新の `main` build は `tip` を使います。
イメージの tag、pull、実行については [docker-ghcr.md(英語)](docker-ghcr.md) を参照してください。
## 先に接続せず直接使う場合
上記の path は、connector を自分たちの product、runtime、または enterprise infrastructure に統合する
@@ -205,6 +219,7 @@ account を接続すれば、自然言語で connected tool を検索、整理
- [Runtime API と MCP](runtime-api.md)
- [Fly.io デプロイ](fly-io.md)
- [Cloudflare デプロイ](cloudflare.md)
- [Docker イメージ(GHCR)(英語)](docker-ghcr.md)
- [設定](configuration.md)
- [Credential と OAuth](credentials.md)
- [Catalog format](catalog-format.md)
+17 -2
View File
@@ -128,10 +128,16 @@ flowchart LR
## Быстрый Старт
Запустите runtime через Docker Compose:
Запустите runtime из опубликованного образа через Docker Compose:
```bash
docker compose up --build
docker compose up
```
Это скачает `ghcr.io/oomol-lab/open-connector:latest`. Чтобы собрать из исходников:
```bash
docker compose -f docker-compose.yml -f docker-compose.build.yml up --build
```
Откройте локальную console и сгенерированную API reference:
@@ -192,6 +198,14 @@ Fly volume.
Создание Fly app, настройка volume, secrets, deployment, custom domain и scaling описаны в
[fly-io.md](fly-io.md).
## Docker-образ (GHCR)
Запускайте OpenConnector из готового образа в GitHub Packages (GHCR): `ghcr.io/oomol-lab/open-connector`.
Используйте `latest` для новейшего release, закреплённую версию вроде `v1.0.0` для production или `tip`
для последнего build из `main`.
О тегах образа, pull и запуске см. [docker-ghcr.md (на английском)](docker-ghcr.md).
## Хотите Использовать Напрямую?
Пути выше предназначены для команд, которые интегрируют connector в свои продукты, runtimes или
@@ -217,6 +231,7 @@ CLI, MCP либо HTTP API.
- [Runtime API и MCP](runtime-api.md)
- [Развертывание Fly.io](fly-io.md)
- [Развертывание Cloudflare](cloudflare.md)
- [Docker-образ (GHCR) (на английском)](docker-ghcr.md)
- [Configuration](configuration.md)
- [Credentials и OAuth](credentials.md)
- [Формат catalog](catalog-format.md)
+16 -2
View File
@@ -114,10 +114,16 @@ secret,然后运行 `npm run deploy:cloudflare`。
## 快速开始
使用 Docker Compose 启动运行时:
使用 Docker Compose 从发布的镜像启动运行时:
```bash
docker compose up --build
docker compose up
```
这会拉取 `ghcr.io/oomol-lab/open-connector:latest`。想改为从源码构建:
```bash
docker compose -f docker-compose.yml -f docker-compose.build.yml up --build
```
打开本地控制台和生成的 API 文档:
@@ -174,6 +180,13 @@ OpenConnector 也可以部署到 Fly.io:使用 Node Docker runtime,并把 SQ
Fly app 创建、volume、secret、部署、自定义域名和扩缩容步骤见 [fly-io.md](fly-io.md)。
## Docker 镜像(GHCR)
可以直接用 GitHub Packages(GHCR)上的预构建镜像运行 OpenConnector:`ghcr.io/oomol-lab/open-connector`。最新
release 用 `latest`,生产环境固定版本号(如 `v1.0.0`),想用最新 `main` 构建则用 `tip`。
镜像标签、拉取和运行的说明见 [docker-ghcr.zh-CN.md](docker-ghcr.zh-CN.md)。
## 不想先接入?可以直接使用 Wanta
上面的路径更适合把 connector 接入自己的产品、runtime 或企业基础设施。如果你只是想先体验连接各种
@@ -197,6 +210,7 @@ HTTP API。
- [Runtime API 和 MCP](runtime-api.md)
- [Fly.io 部署](fly-io.md)
- [Cloudflare 部署](cloudflare.md)
- [Docker 镜像(GHCR)](docker-ghcr.zh-CN.md)
- [配置项](configuration.md)
- [凭据和 OAuth](credentials.md)
- [Catalog 格式](catalog-format.md)
+107
View File
@@ -0,0 +1,107 @@
[English](docker-ghcr.md) | [简体中文](docker-ghcr.zh-CN.md)
# Docker Image (GHCR)
OpenConnector ships a prebuilt Docker image on the GitHub Packages container registry (GHCR), so you
can run it without cloning the repository or building anything. The image is:
```text
ghcr.io/oomol-lab/open-connector
```
## Choose A Tag
| Tag | Points at | Use it when |
| ------------- | ------------------------------------ | -------------------------------------------------------------- |
| `latest` | the newest published release | you want the current stable runtime |
| `v1.0.0` | a specific release (immutable) | you deploy to production and want a pinned, reproducible build |
| `tip` | the latest commit on `main` | you want to try changes that are not released yet |
| `<short-sha>` | a specific `main` commit (immutable) | you want to pin an exact pre-release build |
For production, pin a released version such as `v1.0.0`.
## Pull
The image is public, so no sign-in is required:
```bash
docker pull ghcr.io/oomol-lab/open-connector:latest
```
If you get an `unauthorized` or `denied` error, sign in with a GitHub token that has the
`read:packages` scope:
```bash
echo "$GITHUB_TOKEN" | docker login ghcr.io -u <github-username> --password-stdin
```
The image is multi-arch (`linux/amd64` + `linux/arm64`), so Docker automatically pulls the variant
that matches your machine — running natively on Intel/AMD hosts and on arm64 hosts such as Apple
Silicon and AWS Graviton. No `--platform` flag is needed.
## Run
The image listens on port `3000`, binds to `0.0.0.0`, and stores runtime data in `/app/data`.
First generate the runtime secrets and save them somewhere safe. `OOMOL_CONNECT_ENCRYPTION_KEY`
encrypts stored credentials and OAuth client secrets; if it is lost, the encrypted data in
`/app/data` cannot be recovered. `OOMOL_CONNECT_ADMIN_TOKEN` authenticates the admin API and console.
```bash
# Save both values in a password manager or secrets vault before running.
export OOMOL_CONNECT_ENCRYPTION_KEY=$(openssl rand -base64 32)
export OOMOL_CONNECT_ADMIN_TOKEN=$(openssl rand -base64 32)
```
Then run the image, mounting a volume so data survives restarts:
```bash
docker run -d \
--name open-connector \
-p 3000:3000 \
-v open_connector_data:/app/data \
-e OOMOL_CONNECT_ORIGIN="https://api.example.com" \
-e OOMOL_CONNECT_ENCRYPTION_KEY="$OOMOL_CONNECT_ENCRYPTION_KEY" \
-e OOMOL_CONNECT_ADMIN_TOKEN="$OOMOL_CONNECT_ADMIN_TOKEN" \
ghcr.io/oomol-lab/open-connector:latest
```
See [configuration.md](configuration.md) for the full environment variable reference and
[credentials.md](credentials.md) for connecting providers.
### Docker Compose
The repository ships a [`docker-compose.yml`](../docker-compose.yml) that runs this published image.
From a checkout, export the secrets shown above and start it:
```bash
docker compose up
```
To build from source instead of pulling, add the build overlay:
```bash
docker compose -f docker-compose.yml -f docker-compose.build.yml up --build
```
## Verify
Check the health endpoint:
```bash
curl http://localhost:3000/health
```
The expected response is:
```json
{ "ok": true }
```
## How Images Are Published
Images are built and pushed automatically, so the tags above stay current: every push to `main`
updates `tip` and adds the `<short-sha>` tag, and every published release adds `latest` and the
release version. Each tag is a multi-arch manifest built natively for `linux/amd64` and
`linux/arm64`. The build is defined in
[`.github/workflows/publish-docker.yml`](../.github/workflows/publish-docker.yml).
+102
View File
@@ -0,0 +1,102 @@
[English](docker-ghcr.md) | [简体中文](docker-ghcr.zh-CN.md)
# Docker 镜像(GHCR)
OpenConnector 在 GitHub Packages 容器镜像仓库(GHCR)提供了预构建的 Docker 镜像,你无需克隆仓库或自己构建即可
运行 OpenConnector。镜像地址为:
```text
ghcr.io/oomol-lab/open-connector
```
## 选择标签(Tag)
| 标签 | 指向 | 适用场景 |
| ------------- | -------------------------------- | -------------------------------------- |
| `latest` | 最新发布的 release | 想要当前的稳定 runtime |
| `v1.0.0` | 某个具体 release(不可变) | 部署到生产环境,需要固定、可复现的构建 |
| `tip` | `main` 上的最新 commit | 想体验尚未发布的改动 |
| `<short-sha>` | 某个具体 `main` commit(不可变) | 想固定到某个确切的预发布构建 |
生产环境请固定到某个 release 版本,例如 `v1.0.0`。
## 拉取
镜像是 public 的,无需登录即可拉取:
```bash
docker pull ghcr.io/oomol-lab/open-connector:latest
```
如果遇到 `unauthorized` 或 `denied` 错误,用带 `read:packages` scope 的 GitHub token 登录:
```bash
echo "$GITHUB_TOKEN" | docker login ghcr.io -u <github-username> --password-stdin
```
镜像是多架构的(`linux/amd64` + `linux/arm64`),Docker 会自动拉取与你机器匹配的那个变体——在 Intel/AMD
主机和 arm64 主机(如 Apple Silicon、AWS Graviton)上都是原生运行,无需 `--platform` 参数。
## 运行
镜像监听 `3000` 端口,绑定到 `0.0.0.0`,并把运行时数据存放在 `/app/data`。
先生成运行时 secret 并妥善保存。`OOMOL_CONNECT_ENCRYPTION_KEY` 用于加密存储的凭据和 OAuth client secret;一旦
丢失,`/app/data` 里加密的数据将无法恢复。`OOMOL_CONNECT_ADMIN_TOKEN` 用于 admin API 和控制台的鉴权。
```bash
# 运行前请把两个值保存到密码管理器或 secrets vault。
export OOMOL_CONNECT_ENCRYPTION_KEY=$(openssl rand -base64 32)
export OOMOL_CONNECT_ADMIN_TOKEN=$(openssl rand -base64 32)
```
然后运行镜像,并挂载 volume 让数据在重启后保留:
```bash
docker run -d \
--name open-connector \
-p 3000:3000 \
-v open_connector_data:/app/data \
-e OOMOL_CONNECT_ORIGIN="https://api.example.com" \
-e OOMOL_CONNECT_ENCRYPTION_KEY="$OOMOL_CONNECT_ENCRYPTION_KEY" \
-e OOMOL_CONNECT_ADMIN_TOKEN="$OOMOL_CONNECT_ADMIN_TOKEN" \
ghcr.io/oomol-lab/open-connector:latest
```
完整环境变量参考见 [configuration.md](configuration.md),连接 provider 见 [credentials.md](credentials.md)。
### Docker Compose
仓库自带一个 [`docker-compose.yml`](../docker-compose.yml),直接运行这个发布镜像。在仓库目录下,先 export
上面的 secret,再启动:
```bash
docker compose up
```
想改为从源码构建而不是拉取:
```bash
docker compose -f docker-compose.yml -f docker-compose.build.yml up --build
```
## 验证
检查健康检查端点:
```bash
curl http://localhost:3000/health
```
预期响应为:
```json
{ "ok": true }
```
## 镜像如何发布
镜像会自动构建并推送,因此上面的标签始终保持最新:每次 push 到 `main` 会更新 `tip` 并新增 `<short-sha>`
标签,每次发布 release 会新增 `latest` 和 release 版本号。每个标签都是为 `linux/amd64` 和 `linux/arm64`
原生构建的多架构 manifest。构建定义见
[`.github/workflows/publish-docker.yml`](../.github/workflows/publish-docker.yml)。