Keep Docker Compose 部署指南
用 Docker Compose 在 Ubuntu 22.04 服务器上部署 Keep(keephq/keep)0.54.3 三服务栈(API 后端 + Web 控制台 + 实时推送):镜像选型、持久化、环境变量表、等价 docker run 与 4 则实测排障实录。
Keep Docker Compose 部署指南
目标:在一台 Ubuntu 22.04 服务器上,用 Docker Compose 把 Keep(keephq/keep,开源 AIOps 告警管理平台)的完整服务栈(API 后端 + Web 控制台 + 实时推送)跑起来,并完成告警注入验证。本文全部命令与回显出自 0.54.3 版本在真实服务器上的逐条实测(2026-10-23),含 4 个实际踩坑的排障实录。项目背景与选型对比见 《Keep 介绍与选型指南》。
一、环境信息
| 项目 | 值 | 说明 |
|---|---|---|
| 操作系统 | Ubuntu 22.04(64 位) | 实测服务器 |
| Docker | 29.8.1(build 4a63305) | docker --version 实测 |
| Docker Compose | v5.5.1(v2 插件形态) | docker compose version 实测 |
| Keep 版本 | v0.54.3(2026-09-09 发布的最新稳定版) | 实测拉取的 latest 镜像即该版本 |
| 实测端口 | 前端 8150 / 后端 API 8148 / 实时推送 8146 | 因服务器上 3000/8080/6001 及部分备选端口已被占用,统一映射到高位端口 |
| 实测网络 | keep-0543-net(10.89.71.0/24) | 显式指定子网,避免与同机其他 Compose 栈的地址池冲突 |
| 实验产物目录 | /opt/data/quzuo/tmp/keep-alerts/ | compose 文件与持久化目录均约束在该目录内 |
二、镜像选型说明
Keep 官方没有发布到 Docker Hub,而是托管在 Google Artifact Registry(us-central1-docker.pkg.dev/keephq/keep/),实时推送组件直接复用 Soketi 官方镜像。0.54.3 实测用到的镜像如下(docker images 实测大小):
| 镜像 | 角色 | 实测大小 |
|---|---|---|
us-central1-docker.pkg.dev/keephq/keep/keep-api:latest | 后端 API(FastAPI),告警摄入/workflow 引擎/REST 服务 | 1.26 GB |
us-central1-docker.pkg.dev/keephq/keep/keep-ui:latest | 前端控制台(Next.js),内置 entrypoint 启动脚本 | 952 MB |
quay.io/soketi/soketi:1.4-16-debian | 实时推送服务器(Pusher 协议兼容) | 1.59 GB |
us-central1-docker.pkg.dev/keephq/keep/keep-cli:latest | CLI 工具镜像(可选,日常用 docker run 临时调用) | 1.48 GB |
选型要点:
- 官方 Compose 是「两文件 + extends」结构:GitHub 仓库根目录的
docker-compose.yml通过extends复用docker-compose.common.yml里的公共定义。extends在依赖镜像内 entrypoint 传参时容易踩细节,本文将其摊平为单文件写法,行为等价、更适合直接照抄到自己的服务器(实测即按单文件部署验证)。 - 镜像 tag 用 latest 还是固定版本:
latest即当时的最新稳定版(实测为 v0.54.3)。Keep 处于 0.x 快速迭代期,生产环境建议部署后记录当前镜像摘要(docker images --digests | grep keep),后续升级时按摘要比对,避免盲目跟随 latest。 - 不要用 Docker Hub 上的第三方 keep 镜像:Docker Hub 存在同名/近似镜像,与 keephq 官方制品无关。
三、前置条件
- Docker 与 Compose v2 插件:
docker compose version能正常输出版本号(本文 v5.5.1)。 - 端口规划:三个服务各需一个宿主端口。默认为前端 3000、后端 8080、推送 6001;若被占用改高位端口即可(实测用 8150/8148/8146)。检查端口是否空闲:
ss -ltnp | grep -E ':(8150|8148|8146)\b'(无输出即空闲)。 - 网络子网规划:同机跑多个 Compose 栈时,建议显式指定互不重叠的子网(实测取 10.89.71.0/24)。查看已占用网段:
docker network ls --format '{{.Name}}' | xargs -n1 docker network inspect --format '{{.Name}} {{range .IPAM.Config}}{{.Subnet}}{{end}}' 2>/dev/null。 - 磁盘空间:三个镜像解压后约 3.8 GB(实测
docker images合计),外加 SQLite 数据与日志预留 2 GB 以上。 - 出口网络:镜像仓库在
us-central1-docker.pkg.dev(Google Artifact Registry)与quay.io,服务器需能访问这两个仓库;拉取缓慢时为 Docker 配置代理(/etc/systemd/system/docker.service.d/http-proxy.conf)再systemctl daemon-reload && systemctl restart docker。 - 不需要提前安装数据库:默认 SQLite 零依赖;MySQL/PostgreSQL 可后续按需切换(见第七节)。
四、部署步骤
4.1 目录结构
mkdir -p /opt/data/quzuo/tmp/keep-alerts/stack/state/workflows
cd /opt/data/quzuo/tmp/keep-alerts/stack
最终结构:
stack/
├── docker-compose.yml
└── state/ # 持久化目录(挂载到容器 /state)
└── workflows/ # 预置 workflow 目录(KEEP_WORKFLOWS_DIRECTORY 指向)
4.2 编写 docker-compose.yml
name: keep-0543-stack
services:
keep-frontend:
image: us-central1-docker.pkg.dev/keephq/keep/keep-ui
container_name: keep-0543-frontend
ports:
- "8150:3000"
environment:
- AUTH_TYPE=NO_AUTH
- API_URL=http://keep-backend:8080
- NEXTAUTH_SECRET=secret
- NEXTAUTH_URL=http://localhost:8150
- NEXT_PUBLIC_API_URL=http://localhost:8148
- PUSHER_HOST=localhost
- PUSHER_PORT=8146
- PUSHER_APP_KEY=keepappkey
volumes:
- ./state:/state
depends_on:
- keep-backend
networks:
- keep-net
keep-backend:
image: us-central1-docker.pkg.dev/keephq/keep/keep-api
container_name: keep-0543-backend
ports:
- "8148:8080"
environment:
- PORT=8080
- AUTH_TYPE=NO_AUTH
- KEEP_DEFAULT_API_KEYS=cli-demo:admin:q1w2e3r4-keep-demo-key
- KEEP_JWT_SECRET=keep-demo-jwt-secret
- KEEP_PROVIDERS={"console-yaml-prov":{"type":"console","authentication":{}},"bash-local":{"type":"bash","authentication":{}}}
- KEEP_WORKFLOWS_DIRECTORY=/state/workflows
- SECRET_MANAGER_TYPE=FILE
- SECRET_MANAGER_DIRECTORY=/state
- DATABASE_CONNECTION_STRING=sqlite:////state/db.sqlite3?check_same_thread=False
- OPENAI_API_KEY=$OPENAI_API_KEY
- PROMETHEUS_MULTIPROC_DIR=/tmp/prometheus
- KEEP_METRICS=true
- PUSHER_APP_ID=1
- PUSHER_APP_KEY=keepappkey
- PUSHER_APP_SECRET=keepappsecret
- PUSHER_HOST=keep-websocket-server
- PUSHER_PORT=6001
- USE_NGROK=false
volumes:
- ./state:/state
networks:
- keep-net
keep-websocket-server:
image: quay.io/soketi/soketi:1.4-16-debian
container_name: keep-0543-websocket
ports:
- "8146:6001"
environment:
- SOKETI_USER_AUTHENTICATION_TIMEOUT=3000
- SOKETI_DEBUG=1
- SOKETI_DEFAULT_APP_ID=1
- SOKETI_DEFAULT_APP_KEY=keepappkey
- SOKETI_DEFAULT_APP_SECRET=keepappsecret
networks:
- keep-net
networks:
keep-net:
name: keep-0543-net
driver: bridge
ipam:
config:
- subnet: 10.89.71.0/24
三个环境变量按你的实际取值修改:
KEEP_DEFAULT_API_KEYS=cli-demo:admin:q1w2e3r4-keep-demo-key:启动时预置一个 API Key,格式为名称:角色:密钥。这是实测中打通告警注入的关键(见第 11.3 节排障实录)。NEXTAUTH_URL/NEXT_PUBLIC_API_URL/PUSHER_PORT:前端侧的三个对外地址,要与宿主端口映射一致(这里分别是 8150、8148、8146)。PUSHER_APP_KEY/APP_SECRET与 SOKETI 的三个SOKETI_DEFAULT_APP_*必须成对一致,否则前端实时推送连不上。
4.3 修正持久化目录属主(关键步骤)
官方 keep-api 镜像以非 root 用户 keep(uid/gid 1000)运行,而 bind mount 出来的 state/ 默认归 root 所有。先执行属主修正再启动,否则后端起不来(实测踩坑,见第 11.1 节):
chown -R 1000:1000 state
4.4 拉起服务栈
docker compose up -d
实测回显(首次部署在此前还有三个镜像的分层拉取进度,此处为栈重建时的回显,可完整展示创建过程):
Network keep-0543-net Creating
Network keep-0543-net Creating
Network keep-0543-net Created
Network keep-0543-net Created
Container keep-0543-websocket Creating
Container keep-0543-backend Creating
Container keep-0543-websocket Created
Container keep-0543-backend Created
Container keep-0543-frontend Creating
Container keep-0543-frontend Created
Container keep-0543-websocket Starting
Container keep-0543-backend Starting
Container keep-0543-websocket Started
Container keep-0543-backend Started
Container keep-0543-frontend Starting
Container keep-0543-frontend Started
4.5 验证部署
容器状态(docker compose ps 实测):
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
keep-0543-backend us-central1-docker.pkg.dev/keephq/keep/keep-api "/venv/lib/python3.1…" keep-backend 13 minutes ago Up 13 minutes 0.0.0.0:8148->8080/tcp, [::]:8148->8080/tcp
keep-0543-frontend us-central1-docker.pkg.dev/keephq/keep/keep-ui "/app/entrypoint.sh" keep-frontend 28 minutes ago Up 28 minutes 0.0.0.0:8150->3000/tcp, [::]:8150->3000/tcp
keep-0543-websocket quay.io/soketi/soketi:1.4-16-debian "node /app/bin/serve…" keep-websocket-server 32 minutes ago Up 32 minutes 0.0.0.0:8146->6001/tcp, [::]:8146->6001/tcp
后端健康检查(/healthcheck 实测,返回空 JSON 即正常):
curl -s http://localhost:8148/healthcheck
{}
API Key 与租户验证(带预置 Key 访问 /whoami 实测):
curl -s -H "x-api-key: q1w2e3r4-keep-demo-key" http://localhost:8148/whoami
{"tenant_id":"keep"}
OpenAPI 文档:浏览器打开 http://<服务器IP>:8148/docs 可见 FastAPI 自动生成的接口文档(实测 200)。
Web 控制台:浏览器打开 http://<服务器IP>:8150。实测 HTTP 层表现为 307 重定向链(/ → /incidents → /signin?callbackUrl=... → 200),进入 Keep 登录页;NO_AUTH 模式下无需输入凭据即可进入控制台(页面标题实测为 Keep)。
注入一条真实告警完成端到端验证(异步接口,返回任务名即代表受理成功,实测回显):
curl -s -X POST http://localhost:8148/alerts/event \
-H "Content-Type: application/json" \
-H "x-api-key: q1w2e3r4-keep-demo-key" \
-d '{"id":"demo-alert-001","name":"disk usage on web-prod-01 above 90%","severity":"critical","status":"firing","source":["demo"],"message":"Disk usage on /var of web-prod-01 is 93%","fingerprint":"disk-web-prod-01"}'
{"task_name":"131606376315024"}
数秒后在 UI 告警台(Alerts 页)可见该条告警;CLI 侧 keep alert list 亦可见(CLI 用法见《Keep 0.54.3 常用 CLI 命令与工具详解》)。
五、数据持久化说明
实测栈将宿主 stack/state/ 目录 bind mount 到两个容器的 /state,Keep 的全部落盘数据集中在这一处(docker inspect keep-0543-backend --format '{{json .Mounts}}' 实测):
[
{
"Type": "bind",
"Source": "/opt/data/quzuo/tmp/keep-alerts/stack/state",
"Destination": "/state",
"Mode": "rw",
"RW": true,
"Propagation": "rprivate"
}
]
运行一段时间后 state/ 的实测内容与用途:
-rw-r--r-- 1 yahui yahui 794624 10月 23 09:34 db.sqlite3 # SQLite 数据库(告警/工作流/用户/凭据)
-rw-r--r-- 1 yahui yahui 44 10月 23 09:32 keep_bash_f92d7d3a4d754024b3c289db4b1eb43d # SECRET_MANAGER=FILE 落盘的密钥文件
-rw-r--r-- 1 yahui yahui 22 10月 23 09:19 keep-cli-demo # 预置 API Key 文件
-rw-r--r-- 1 yahui yahui 51 10月 23 09:32 keep_console_03092072a8ab409ba41974670f4e7040 # console provider 连接凭据文件
-rw-r--r-- 1 yahui yahui 46 10月 23 09:24 keep_console_09f66d0f96634ec8b9bd3c575d427ce4
drwxr-xr-x 2 yahui yahui 4096 10月 23 09:32 workflows/ # 预置 workflow(disk-critical-handler.yml)
持久化要点:
- 备份就是备份
state/目录:停栈docker compose down后整目录打包即可,恢复时原位解包再chown -R 1000:1000后up -d。 - 权限必须保持 uid/gid 1000:任何在宿主上以 root 手工改写该目录的操作之后,都要重新
chown -R 1000:1000,否则下次启动失败。 - 换数据库后
db.sqlite3不迁移:从 SQLite 切到 MySQL/PostgreSQL 是「从零开始的新库」,历史告警不会自动搬迁;切换前先keep alert export或调 REST API 导出需要留存的数据。
六、环境变量表
6.1 前端 keep-ui
| 变量 | 实测值 | 作用 |
|---|---|---|
| AUTH_TYPE | NO_AUTH | 认证模式,与后端保持一致(NO_AUTH 免登录/DB 用户名密码,详见第七节) |
| API_URL | http://keep-backend:8080 | 前端服务端向Compose 网络内后端转发请求的地址(容器间用服务名) |
| NEXT_PUBLIC_API_URL | http://localhost:8148 | 浏览器直连后端的地址(要用宿主能访问的地址,故填映射端口) |
| NEXTAUTH_URL | http://localhost:8150 | NextAuth 回调基准地址,浏览器实际访问前端的地址 |
| NEXTAUTH_SECRET | 任意字符串 | NextAuth 会话签名密钥 |
| PUSHER_HOST / PUSHER_PORT | localhost / 8146 | 浏览器建立实时推送 WebSocket 的地址(宿主侧映射端口) |
| PUSHER_APP_KEY | keepappkey | 推送应用 Key,与 Soketi 的 SOKETI_DEFAULT_APP_KEY 一致 |
| POSTHOG_KEY / POSTHOG_HOST | 官方默认值 | 官方产品分析埋点;内网环境可留空(为空时仅失去匿名统计功能,不影响功能) |
| NEXT_PUBLIC_SENTRY_DSN | 官方默认值 | 前端错误上报 Sentry 地址;内网环境可留空 |
6.2 后端 keep-api
| 变量 | 实测值 | 作用 |
|---|---|---|
| PORT | 8080 | 后端监听端口 |
| AUTH_TYPE | NO_AUTH | 认证模式(见第七节) |
| KEEP_DEFAULT_API_KEYS | cli-demo:admin:q1w2e3r4-keep-demo-key | 启动时预置 API Key,格式 名称:角色:密钥,多个用分号分隔;不预置则 NO_AUTH 下也无 Key 可用(实测坑,见 11.3) |
| KEEP_JWT_SECRET | keep-demo-jwt-secret | JWT 签名密钥,生产环境务必换强随机值 |
| DATABASE_CONNECTION_STRING | sqlite:////state/db.sqlite3?check_same_thread=False | SQLAlchemy 连接串,可换 MySQL/PostgreSQL(见第七节) |
| SECRET_MANAGER_TYPE | FILE | 密钥管理后端:FILE(落盘 /state)/ DB / AWS Secrets Manager 等 |
| SECRET_MANAGER_DIRECTORY | /state | FILE 模式的落盘目录(实测 keep-cli-demo 等文件即在此生成) |
| KEEP_PROVIDERS | {"bash-local":{"type":"bash",...},...} | 启动时预置的 provider 连接(JSON),免去手工在 UI 上连接;完整说明见《Keep 0.54.3 配置参数详解》 |
| KEEP_WORKFLOWS_DIRECTORY | /state/workflows | 启动时批量加载该目录下的 workflow YAML |
| PUSHER_APP_ID / APP_KEY / APP_SECRET | 1 / keepappkey / keepappsecret | 后端作为推送客户端连 Soketi 的三元组,与 SOKETI_* 完全一致 |
| PUSHER_HOST / PUSHER_PORT | keep-websocket-server / 6001 | 后端连 Soketi 的容器网络地址(注意:与前端 PUSHER_HOST=localhost 含义不同,前端是给浏览器用的) |
| KEEP_METRICS | true | 开启 Prometheus 指标端点(/metrics) |
| PROMETHEUS_MULTIPROC_DIR | /tmp/prometheus | 多进程模式下 Prometheus 指标共享目录 |
| OPENAI_API_KEY | (留空) | AI 功能的 OpenAI Key;不配置不影响核心功能(实测零 AI Key 跑通全链路) |
| USE_NGROK | false | 官方 compose 的快速演示开关,保持 false |
6.3 实时推送 keep-websocket-server(Soketi)
| 变量 | 实测值 | 作用 |
|---|---|---|
| SOKETI_DEFAULT_APP_ID | 1 | 应用 ID,与后端 PUSHER_APP_ID 一致 |
| SOKETI_DEFAULT_APP_KEY | keepappkey | 与前端/后端的 PUSHER_APP_KEY 一致 |
| SOKETI_DEFAULT_APP_SECRET | keepappsecret | 与后端 PUSHER_APP_SECRET 一致 |
| SOKETI_USER_AUTHENTICATION_TIMEOUT | 3000 | 用户认证超时(毫秒) |
| SOKETI_DEBUG | 1 | 调试日志开关 |
七、配置参数说明
三个关键配置块的展开说明(完整环境变量清单与 providers/workflow 配置详见《Keep 0.54.3 配置参数详解》):
认证模式 AUTH_TYPE:NO_AUTH(默认,免登录,但调用 API 仍需 API Key)、DB(用户名密码入库,内置 RBAC 预定义角色)、OAUTH2PROXY(反代层统一认证)、Okta/OneLogin(开源版可用);Keycloak/Auth0/AzureAD 属企业目录功能。前后端必须配置同一 AUTH_TYPE。
数据库切换 DATABASE_CONNECTION_STRING:默认 SQLite 适合单机与评估;多人团队换成 MySQL/PostgreSQL,例如 mysql+pymysql://keep:密码@mysql-host:3306/keep。应用层由 SQLAlchemy 屏蔽差异,Compose 里只需改这一行并为栈增加数据库服务。
推送三元组(PUSHER_APP_ID/KEY/SECRET):这是前端、后端、Soketi 三方对齐的「钥匙串」。排查实时推送故障时,用同一组值在三处比对:前端 PUSHER_APP_KEY、后端 PUSHER_APP_KEY/APP_SECRET/APP_ID、Soketi SOKETI_DEFAULT_APP_*。任一不一致,浏览器控制台会看到 WebSocket 连接 401。
八、配置文件挂载
实测栈只挂载一个 bind mount:宿主 ./state → 两个容器的 /state。它同时承担四种角色:
- SQLite 数据库文件:
/state/db.sqlite3(由 DATABASE_CONNECTION_STRING 指定)。 - 密钥落盘目录:
/state(SECRET_MANAGER_TYPE=FILE + SECRET_MANAGER_DIRECTORY=/state),provider 凭据以keep_<名称>文件存放。 - 预置 workflow 目录:
/state/workflows(KEEP_WORKFLOWS_DIRECTORY),放入的 YAML 会在后端启动时批量注册,实测disk-critical-handler.yml在 UI Workflow 页可见且来源标记为系统预置。 - 官方默认行为:镜像内 VOLUME 声明的就是
/state,即使不写 volumes 也会生成匿名卷——但匿名卷不利于备份与查看,务必显式 bind mount 或命名卷。
workflow YAML 编辑流程:宿主上直接改 state/workflows/*.yml,docker compose restart keep-backend 后生效;或在 UI Workflow 编辑器内改(保存后入库 SQLite)。两种方式不要对同一 workflow 混用,避免覆盖。
九、等价 docker run
不用 Compose 时,以下三条命令与上述 compose 文件等价(先建网络,注意按依赖顺序启动;变量值与 compose 一致):
# 1. 创建网络
docker network create --driver bridge --subnet 10.89.71.0/24 keep-0543-net
# 2. 实时推送(Soketi)
docker run -d --name keep-0543-websocket \
--network keep-0543-net \
-p 8146:6001 \
-e SOKETI_USER_AUTHENTICATION_TIMEOUT=3000 \
-e SOKETI_DEBUG=1 \
-e SOKETI_DEFAULT_APP_ID=1 \
-e SOKETI_DEFAULT_APP_KEY=keepappkey \
-e SOKETI_DEFAULT_APP_SECRET=keepappsecret \
quay.io/soketi/soketi:1.4-16-debian
# 3. 后端 API(注意先 chown 1000:1000 /opt/data/quzuo/tmp/keep-alerts/stack/state)
docker run -d --name keep-0543-backend \
--network keep-0543-net \
-p 8148:8080 \
-v /opt/data/quzuo/tmp/keep-alerts/stack/state:/state \
-e PORT=8080 -e AUTH_TYPE=NO_AUTH \
-e KEEP_DEFAULT_API_KEYS=cli-demo:admin:q1w2e3r4-keep-demo-key \
-e KEEP_JWT_SECRET=keep-demo-jwt-secret \
-e 'KEEP_PROVIDERS={"console-yaml-prov":{"type":"console","authentication":{}},"bash-local":{"type":"bash","authentication":{}}}' \
-e KEEP_WORKFLOWS_DIRECTORY=/state/workflows \
-e SECRET_MANAGER_TYPE=FILE -e SECRET_MANAGER_DIRECTORY=/state \
-e 'DATABASE_CONNECTION_STRING=sqlite:////state/db.sqlite3?check_same_thread=False' \
-e PROMETHEUS_MULTIPROC_DIR=/tmp/prometheus -e KEEP_METRICS=true \
-e PUSHER_APP_ID=1 -e PUSHER_APP_KEY=keepappkey -e PUSHER_APP_SECRET=keepappsecret \
-e PUSHER_HOST=keep-websocket-server -e PUSHER_PORT=6001 \
-e USE_NGROK=false \
us-central1-docker.pkg.dev/keephq/keep/keep-api
# 4. 前端控制台
docker run -d --name keep-0543-frontend \
--network keep-0543-net \
-p 8150:3000 \
-v /opt/data/quzuo/tmp/keep-alerts/stack/state:/state \
-e AUTH_TYPE=NO_AUTH \
-e API_URL=http://keep-backend:8080 \
-e NEXTAUTH_SECRET=secret \
-e NEXTAUTH_URL=http://localhost:8150 \
-e NEXT_PUBLIC_API_URL=http://localhost:8148 \
-e PUSHER_HOST=localhost -e PUSHER_PORT=8146 -e PUSHER_APP_KEY=keepappkey \
us-central1-docker.pkg.dev/keephq/keep/keep-ui
生产建议仍用 Compose 管理:环境变量集中、依赖顺序由 depends_on 保证、down/up 一条命令完成。
十、常用运维命令
以下均在实测栈上执行(工作目录 stack/):
# 服务状态
docker compose ps
# 查看后端日志(JSON 结构化日志,追踪 HTTP 请求与 workflow 执行)
docker compose logs --tail 2 keep-backend
实测日志回显(一行 JSON + 一行访问日志,可看到请求路径与状态码):
keep-0543-backend | {"worker_type": "uvicorn", "asctime": "2026-10-23 01:46:56,387", "message": "Request finished: GET /whoami 200 in 0.00s", "levelname": "INFO", "name": "keep.api.middlewares", ..., "tenant_id": "keep", "status_code": 200}
keep-0543-backend | 2026-10-23 01:46:56,387 - 7df515622c0158b2f5847eaf279b7306 - MainThread - 10.89.71.1:58484 - "GET /whoami HTTP/1.1" 200
# 资源占用(实测空载水平:后端约 500MB、前端约 190MB、推送 41MB)
docker stats --no-stream --format 'table {{.Name}}\t{{.MemUsage}}\t{{.CPUPerc}}' | grep keep
# 重启单个服务(修改环境变量或 workflow YAML 后)
docker compose restart keep-backend
# 停栈(实测回显:逐容器 Stopping/Stopped/Removing/Removed,最后移除网络;state/ 数据保留)
docker compose down
# 再启动(保留数据的重复部署)
docker compose up -d
docker compose down 实测回显:
Container keep-0543-websocket Stopping
Container keep-0543-frontend Stopping
Container keep-0543-frontend Stopped
Container keep-0543-frontend Removing
Container keep-0543-frontend Removed
Container keep-0543-backend Stopping
Container keep-0543-backend Stopped
Container keep-0543-backend Removing
Container keep-0543-backend Removed
Container keep-0543-websocket Stopped
Container keep-0543-websocket Removing
Container keep-0543-websocket Removed
Network keep-0543-net Removing
Network keep-0543-net Removed
升级流程:docker compose pull && docker compose up -d(Compose 会仅重建镜像变化的服务);回滚则把 image 固定到旧摘要后重新 up -d。
十一、常见问题(实测排障实录)
11.1 后端启动即退出:unable to open database file
现象:up -d 后后端容器反复退出,docker compose logs keep-backend 中出现:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError): unable to open database file
根因:官方镜像以非 root 用户 keep(uid/gid 1000)运行,bind mount 的 state/ 目录归宿主 root 所有,SQLite 无权在该目录创建 db.sqlite3。
解决:chown -R 1000:1000 state 后 docker compose up -d。实测一次通过。判定技巧:只要换宿主目录/迁移数据后出现同类报错,先查属主:ls -ln state | head 看第三、四列是否为 1000。
11.2 端口冲突:Bind for 0.0.0.0:xxxx failed
现象:up -d 报 Error starting userland proxy: listen tcp4 0.0.0.0:8147: bind: address already in use 之类。
根因:共享服务器上高位端口同样可能被其他栈占用。实测部署过程中连续三次换端口(3000/8080/6001 及 8128、8144、8147 均被同机其他服务占用),最终落位 8150/8148/8146。
解决:ss -ltnp | grep ':<端口>\b' 找到占用者;或干脆选更冷门的端口。注意三处联动:compose 端口映射、前端 NEXTAUTH_URL/NEXT_PUBLIC_API_URL/PUSHER_PORT 中的端口都要同步改,浏览器才能正确连通。
11.3 NO_AUTH 模式下调用 API 仍返回 401 Missing API Key
现象:NO_AUTH 部署后,注入告警 curl -X POST .../alerts/event 返回 401:
{"detail":"Missing API Key"}
根因:AUTH_TYPE=NO_AUTH 只是不要求「用户登录」,但 API 调用(含告警上报)仍然必须有 API Key;而数据库里默认没有任何 Key 可用。
解决:用 KEEP_DEFAULT_API_KEYS=名称:角色:密钥 在启动时预置(如本栈的 cli-demo:admin:q1w2e3r4-keep-demo-key),随后所有 API/CLI 调用带 x-api-key: q1w2e3r4-keep-demo-key 即可。实测验证通过(/whoami 返回 {"tenant_id":"keep"})。
11.4 拉起时提示 OPENAI_API_KEY 变量未设置
现象:每次执行 docker compose up -d/ps/down,第一行都出现:
time="..." level=warning msg="The \"OPENAI_API_KEY\" variable is not set. Defaulting to a blank string."
根因:compose 文件里 - OPENAI_API_KEY=$OPENAI_API_KEY 会从宿主 shell 环境取值,未设置时 Compose 发 warning 并置空。
影响与处理:无功能影响(实测零 AI Key 全链路可用)。不想看到 warning 可删掉该行;需要 AI 功能时在宿主 export OPENAI_API_KEY=sk-... 或写入 .env 文件。
11.5 CLI 镜像直接跑报 exec not found
现象:docker run --rm us-central1-docker.pkg.dev/keephq/keep/keep-cli version 报 exec: "version": executable file not found。
根因:keep-cli 镜像的启动命令是裸 python3,没有把 CLI 设为 entrypoint。
解决:命令需带上 keep 前缀,如 docker run --rm keep-cli keep version(实测通过)。CLI 完整用法见《Keep 0.54.3 常用 CLI 命令与工具详解》。
11.6 浏览器打开前端一直跳 /signin
现象:curl -sIL http://localhost:8150/ 实测为 307 链:/ → /incidents → /signin?callbackUrl=... → 200。
说明:这是正常行为而非故障——NextAuth 框架下即便 NO_AUTH 模式,首次进入也会先渲染登录页;在登录页点击 Sign in(无需输入凭据)即可进入控制台。若希望完全跳过该页,需改用 DB 认证模式并创建用户。
十二、参考链接
- 官方部署文档:https://docs.keephq.dev/deployment/overview
- 官方 docker-compose.yml:https://github.com/keephq/keep/blob/main/docker-compose.yml
- 官方 docker-compose.common.yml:https://github.com/keephq/keep/blob/main/docker-compose.common.yml
- 配置参数文档:https://docs.keephq.dev/deployment/configuration
- 认证方式文档:https://docs.keephq.dev/deployment/authentication
- Keep 镜像仓库(Google Artifact Registry):https://us-central1-docker.pkg.dev/keephq/keep
- 相关篇目:《Keep 介绍与选型指南》、《Keep 0.54.3 配置参数详解》、《Keep 0.54.3 常用 CLI 命令与工具详解》