跳转到内容

使用 Docker 部署

本指南面向用 Docker 将 Olivares AI control plane 投入生产的工程师与 SRE。 整个产品是一个 distroless 单镜像——引擎内嵌 web UI——因此单台主机即可运行 SQLite 拓扑而无需任何外部依赖,在需要时通过 Postgres override 即可获得多租户拓扑。 每条路径都保持相同的安全默认值:无默认凭据、一次性 setup token、默认开启 TLS, 以及将主机端口绑定到 loopback。

要从决策页的角度查看所有部署选项及其默认值,参见 自托管 control plane。对于断网站点,参见 在 air-gapped 环境中安装;对于横向扩展, 参见下文的 Kubernetes/Helm 路径。

主要的容器拉取来源是 Docker Hub

Terminal window
docker pull docker.io/olivaresai/olivares:26.8.0

相同的内容也发布到 ghcr.io/olivaresai/olivares——按 digest 完全一致, 用作备份和构建 registry。Docker Hub 对匿名拉取施加速率限制;ghcr.io 不对公共镜像的匿名拉取 限速——因此当 CI 节点或大规模集群触及上限时,可以先 docker login,或改用 ghcr.io 坐标。 Tag 不带前导 v:26.8.0 固定一个版本,:latest 浮动,而 :26.8.0-fips / :26.8.0-stig 是加固变体。基础 tag 和 :latest 是多架构的 (linux/amd64linux/arm64);fips/stig 仅有 amd64

control plane 是一款安全产品,所以运行前先验证。签名是 **无密钥(keyless,Sigstore)**的,针对项目的 GitHub Actions 身份, 并且对任一 registry 工作方式相同——签名与证明(attestation)通过 cosign copy 复制到 Docker Hub,因此 digest 相同:

Terminal window
IMAGE=docker.io/olivaresai/olivares # fallback: ghcr.io/olivaresai/olivares (same digest)
DIGEST="$(crane digest "$IMAGE:26.8.0")"
REF="$IMAGE@$DIGEST"
cosign verify "$REF" \
--certificate-identity-regexp '^https://github\.com/olivaresai/olivares/\.github/workflows/release\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
cosign verify-attestation "$REF" --type spdxjson \
--certificate-identity-regexp '^https://github\.com/olivaresai/olivares/\.github/workflows/release\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com

完整的信任链——校验和签名、SBOM、OpenVEX、SLSA provenance——在 验证你下载的内容中。验证完成后, 请按你所验证的 digest 进行部署,绝不要用可变的 tag (参见 §8)。

镜像的默认命令在容器内部绑定 0.0.0.0,以便你用 ingress 在前面承载它; 下面的主机侧端口映射将暴露面限定在 loopback。以非 root、只读、丢弃所有 capabilities 的方式运行:

Terminal window
docker volume create olivares-data
docker run -d --name olivares \
--user 65532:65532 \
--read-only \
--tmpfs /tmp \
--cap-drop ALL \
--security-opt no-new-privileges \
-v olivares-data:/var/lib/olivares \
-p 127.0.0.1:8443:8443 \
-p 127.0.0.1:8444:8444 \
docker.io/olivaresai/olivares:26.8.0 \
serve \
--listen=0.0.0.0:8443 \
--grpc-listen=0.0.0.0:8444 \
--data-dir=/var/lib/olivares \
--checkpoint-interval=1h
标志原因
--user 65532:65532以烘焙进 distroless 镜像的非 root nonroot UID 运行
--read-only根文件系统不可变;只有数据卷和 /tmp 可写
--tmpfs /tmp一个可写的临时 tmpfs,因 rootfs 只读而必需
--cap-drop ALL引擎不需要任何 Linux capabilities
--security-opt no-new-privileges阻止通过 setuid 二进制提权
-v olivares-data:/var/lib/olivares持久化数据目录(参见 §5
-p 127.0.0.1:8443:8443仅向 loopback 发布 HTTPS(REST + web UI)
-p 127.0.0.1:8444:8444仅向 loopback 发布 gRPC(摄取 / ControlPlane API)

从日志读取一次性 setup token 并创建第一位管理员:

Terminal window
docker logs olivares | sed -n '/FIRST-BOOT SETUP/,/========================/p'
curl -fsS -k -X POST https://127.0.0.1:8443/v1/setup \
-H 'Content-Type: application/json' \
-d '{"token":"<olst_ token>","email":"you@example.com","password":"<strong-password>"}'

-k 接受引擎在首次启动时签发的自签名证书;请通过反向代理 (§6)或你自己的 TLS 材料将其替换为 真实证书。该 token 只显示一次,且为一次性使用。

仓库附带一套 Compose stack,它接好数据卷、loopback 端口映射, 以及与上文相同的加固标志:

Terminal window
docker compose -f deploy/compose/docker-compose.yml up -d
# Read the one-time first-boot setup token:
docker compose -f deploy/compose/docker-compose.yml logs olivares | sed -n '/FIRST-BOOT SETUP/,/========================/p'
# Then open https://localhost:8443 (self-signed TLS by default)

基础文件将镜像默认设为 docker.io/olivaresai/olivares:latest(Docker Hub); 若要进行可验证的生产部署,请在 deploy/compose/.env 中将 OLIVARES_IMAGE 设为一个 digest 固定的引用(参见 §8)。 数据持久化在 olivares-data 卷中。

对于多租户拓扑,在基础文件之上叠加 Postgres override。 先设置两个密码,再拉起 stack:

Terminal window
cp deploy/compose/.env.example deploy/compose/.env # set POSTGRES_SUPERUSER_PASSWORD + OLIVARES_DB_PASSWORD
docker compose -f deploy/compose/docker-compose.yml \
-f deploy/compose/docker-compose.postgres.yml up -d

该 override 会拉起 postgres:16-alpine,在首次初始化时配置最小权限olivares_app 角色和 olivares 数据库(通过 initdb/10-app-role.sh 运行 规范的 deploy/postgres/01-app-role.sql),并用 --engine=postgres 将引擎 指向该非超级用户角色。这使得 FORCE-RLS 租户兜底真正生效: 引擎面对超级用户/BYPASSRLS 角色时拒绝启动

backup profile 生成定时的、账本连续性安全的 DR 包:存储快照加上签名密钥, 在你的 KEK 下加密,并附带一份各租户链尖(chain tip)的清单。先将你的口令写入 一个置于仓库与镜像之外保存的文件,然后运行一次性的 backup profile:

Terminal window
printf 'a strong DR passphrase' > deploy/compose/dr-pass
# the host stamps the bundle name (the distroless image has no `date`):
BACKUP_TS="$(date -u +%Y%m%dT%H%M%SZ)" \
docker compose -f deploy/compose/docker-compose.yml \
-f deploy/compose/docker-compose.backup.yml \
--profile backup run --rm backup

该作业共享引擎的数据卷,将包写入 olivares-backups 卷,并且——由于镜像是 distroless 的——把保留策略交给主机:用主机 cron 清理旧包 (find <backups> -name '*.drbundle' -mtime +14 -delete)。把该运行包进主机 cron 以实现定时 RPO,并olivares-backups 卷异地镜像——同主机的备份 不构成灾难恢复。用以下命令恢复并验证:

Terminal window
olivares dr restore --in <bundle> --data-dir <dir> --passphrase-file dr-pass

完整的 RPO/RTO、密钥保管和 DR 演练流程随仓库的 DR runbook 一同提供; 更高层的演练在备份与恢复中。

从主机而非容器探测健康状态。 该镜像是 distroless 的——没有 shell 也没有 curl,因此有意不在容器内设 HEALTHCHECK。引擎在 HTTPS 端口上暴露 /livez/readyz;请从主机(或你的编排器)探测它们:

Terminal window
# liveness — process is up; no dependency checks, so a store outage never restart-loops:
curl -fsS -k https://127.0.0.1:8443/livez
# readiness — store ping (and HA leadership): 200 when serving, 503 when the store is down:
curl -fsS -k https://127.0.0.1:8443/readyz

/readyz 的可达性就是可用性信号——把它接入你的外部监控 (参见 用 Prometheus 监控)。

setup token 只在日志中出现一次。 首次启动会在容器输出中打印一个一次性的 olst_… token。请在缓冲区轮转之前用 docker logs olivares | sed -n '/FIRST-BOOT SETUP/,/========================/p'(或 Compose 等效命令) 将其捕获;它在你创建第一位管理员时被消耗。

备份数据目录。 /var/lib/olivares(即 olivares-data 卷)保存着 SQLite 存储、审计签名密钥以及 TLS 材料。丢失它就会丢失账本的签名身份 并破坏审计连续性,所以请保护并备份该卷——使用 §4 中的 DR profile,而非对运行中存储的临时拷贝。

开箱即用时引擎提供自己的自签名证书,这对评估足够,但不适用于会校验 信任的客户端。在生产环境中,用一个以运营者提供的证书(来自你的 CA 或 ACME) 终止 TLS 的反向代理来承载绑定在 loopback 上的引擎,并让该代理成为网络上唯一 被暴露的东西。

由于引擎本身讲 TLS,代理通过 loopback 端口以 HTTPS 连接它。一个最小的 nginx server 块:

server {
listen 443 ssl;
server_name olivares.example.com;
ssl_certificate /etc/ssl/olivares/fullchain.pem; # operator-provided cert
ssl_certificate_key /etc/ssl/olivares/privkey.pem;
location / {
proxy_pass https://127.0.0.1:8443; # engine's own TLS on loopback
proxy_ssl_verify off; # engine cert is self-signed
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

用 Caddy 的等效配置,它会自动配置一张公开证书:

olivares.example.com {
reverse_proxy https://127.0.0.1:8443 {
transport http {
tls_insecure_skip_verify # engine cert is self-signed on loopback
}
}
}

将引擎的主机端口保持绑定在 127.0.0.1(上文的默认值),这样只有代理可达。 gRPC 摄取端口(8444)用于 collector;只有在你运行分布式拓扑时,才有意地、 用其自己的 TLS 路径暴露它。

数据卷在容器替换间保持持久,所以一次升级即为:备份、拉取新的固定 tag、 重新创建容器。

Terminal window
# 1. Back up first (see §4).
# 2. Pull the new release and re-verify it (see §1):
docker pull docker.io/olivaresai/olivares:26.8.1
# docker run:
docker stop olivares && docker rm olivares
# re-run the §2 command with the new tag — the olivares-data volume is reused.
# Compose: set OLIVARES_IMAGE to the new digest in .env, then:
docker compose -f deploy/compose/docker-compose.yml up -d

重新创建容器不会触及命名卷,因此存储、签名密钥和 TLS 材料会延续过来。 始终在升级前备份,并在重新创建之前重新验证新镜像。

可变 tag(:26.8.0:latest)用于评估。在生产环境中,请固定你所验证的 digest——digest 不可变,且正是你签字确认过的东西:

Terminal window
docker run ... docker.io/olivaresai/olivares@sha256:<digest> serve ...

对于 Compose,在 deploy/compose/.env 中设置 digest 引用:

Terminal window
OLIVARES_IMAGE=docker.io/olivaresai/olivares@sha256:<digest>

对于横向扩展和多节点,使用 Helm chart——它作为 OCI artifact 发布于 oci://ghcr.io/olivaresai/charts/olivares,经 cosign 签名,并按镜像 digest 固定。 chart 命令参见自托管 control plane, 完全断网站点参见在 air-gapped 环境中安装