ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Docker Compose私有化部署Astron Agent:中小企业避坑指南

Docker Compose私有化部署Astron Agent:中小企业避坑指南 1. 为什么我用 Docker Compose 而不是 K8s 来跑 Astron Agent先说结论如果你的团队在 50 人以内、没有专职的 Kubernetes 运维、业务场景是内部知识库问答和 Agent 实验性落地那么用 Docker Compose 私有化部署讯飞 Astron Agent 掘金版是性价比最高的选择。我接手这个项目时团队里对部署方案有过一轮争论。有人坚持要上 K8s理由是以后肯定要扩容也有人觉得直接裸机跑二进制最简单。最后我拍板用 Docker Compose核心原因有三条。第一Astron Agent 掘金版的服务拓扑复杂度恰好落在 Compose 的舒适区。它的核心组件包括网关服务、Agent 运行时、固定依赖的中间件PostgreSQL、Redis、MinIO、向量库满打满算七八个容器。这个规模用 Compose 管理刚刚好——代码仓库里放一份 docker-compose.yml任何一台干净的主机上docker compose up -d就能拉起全套环境不需要引入额外的编排层。第二私有化部署最大的痛点是可控而不是弹性。大多数私有化场景用户规模是确定的流量峰值是可预期的。K8s 的自动扩缩容、滚动更新这些特性在内部环境里往往一年都用不上几次。反而 K8s 本身的维护成本——证书轮换、节点升级、网络插件排错——会成为团队的新负担。第三Compose 的排错链路最短。容器起不来docker compose logs直接看端口冲突docker compose ps一眼扫完配置改错了改完docker compose up -d增量重建。整个排查过程不需要层层穿透 Pod、Service、Ingress 这些抽象层。对于中小团队来说这节省的时间非常可观。当然Compose 方案也有明确的边界。如果你们的场景是面向公网的大规模 SaaS 服务或者需要跨多台物理机做资源隔离和配额管理那确实该上 K8s。单机 Docker Compose 的容灾能力有限宿主机挂了整套服务就断了。所以我的建议是先 Compose 跑起来等业务量真正起来了再谈迁移 K8s 的事。不要为了将来未必会发生的事牺牲当下的落地效率。1.1 先搞清 Astron Agent 私有化部署要解决什么问题在动键盘之前得先想明白一件事为什么需要私有化部署一个 Agent 平台说白了几个原因。数据合规——内部知识库的文档、对话记录、用户信息都涉及企业敏感数据不能直接传到公有云定制化需求——每个企业的业务流程、工具链、知识体系都不一样托管的 SaaS 版本很难深度适配成本控制——按调用量计费的公有云 API 在规模化使用后费用会直线上升私有化部署之后边际成本趋近于零。Astron Agent 掘金版解决的是如何把大模型能力封装成企业内部可用的 Agent 服务这件事。它提供了可视化的 Agent 编排界面、知识库管理、工具调用接入能力底层可以对接讯飞星火大模型。开发人员不需要从零写 Prompt 工程和 RAG 流程运维人员也不需要分别维护一堆散落的服务——一个 Compose 文件就能把整个平台跑起来。我在实际部署过程中发现这套系统设计得比较克制核心依赖只有 PostgreSQL元数据、Redis缓存/会话、MinIO对象存储、向量库知识库检索这四个中间件加上网关和 Agent 运行时两个应用服务。相比动辄十几个微服务的开源项目这种小而全的架构对私有化部署非常友好。1.2 单机 Docker Compose 方案的适用边界与优势我见过很多团队一上来就想搞高可用三台机器起步每台机器都部署一套前面再挂个 LB。但实际上单机 Compose 方案在很长一段时间内都是够用的。适用边界取决于三个因素并发用户数、数据量、可用性要求。我给的参考值是如果同时在线用户数在 100 以下知识库文档总量在 50GB 以内允许分钟级的故障恢复窗口那么单机 Compose 完全能扛住。Astron Agent 掘金版的 Agent 运行时本身就是无状态设计后面想扩容加副本只需要改 docker-compose.yml 里的 replicas 参数——这一点我后面会详细讲。Compose 方案还有个隐形优势环境一致性。开发环境、测试环境、生产环境用同一套编排文件容器镜像完全一致从根本上消除了在我机器上是好的这类问题。有次我们在测试环境排查一个知识库检索异常的问题最后发现是环境变量配置差异导致的——不同的环境用了不同的配置行为自然不一样。有了统一的 Compose 文件之后这类问题基本绝迹。2. 部署前的环境准备版本、资源与镜像获取这一步看似简单但很多部署失败都栽在这里。我在部署前专门列了一份检查清单比对着逐项确认省了后面很多麻烦。2.1 Docker 与 Compose 版本的前置检查先看 Docker 版本。Astron Agent 掘金版的镜像用到了 Compose 规范里比较新的特性比如 healthcheck 的start_period参数、depends_on的condition条件依赖所以对 Docker 引擎和 Compose 插件都有版本要求。我建议的最低版本组件最低版本推荐版本说明Docker Engine24.026.x / 27.x版本太低会导致 healthcheck 行为异常Docker Composev2.20v2.24老版本对 condition 依赖支持不完整Linux Kernel5.106.x影响容器网络和存储性能CPU 架构amd64 / arm64amd64掘金版镜像对两种架构都做了适配检查命令docker --version docker compose version uname -a有个坑得提前说如果你是通过apt install docker-compose安装的老版本 Compose它和 docker-compose.yml 里的新语法可能不兼容。建议直接用 Docker 官方提供的 Compose 插件mkdir -p ~/.docker/cli-plugins/ curl -SL https://github.com/docker/compose/releases/latest/download/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose chmod x ~/.docker/cli-plugins/docker-compose docker compose version确认输出的是 v2.x 版本就对了。2.2 资源规划CPU、内存与存储怎么给才不卡资源给多了浪费给少了跑不动。我实测下来的资源占用参考是这样的服务CPU核内存GB存储GB说明网关111静态资源请求转发内存占用低Agent 运行时242核心服务承载 Agent 推理和工具调用PostgreSQL1220元数据和会话数据随数据量增长Redis111缓存和会话AOF 持久化MinIO1230存放上传的文档和向量化中间文件向量库1310知识库向量索引文档多时增长明显监控/日志可选0.515建议加排错时救命合计建议8 核 CPU、16GB 内存、100GB 存储。这是最低配置。如果知识库文档超过 10GB 或者同时在线用户超过 50 人建议内存加到 32GB、存储按需扩容。说到存储要特别提醒向量库对磁盘的 IOPS 比较敏感尤其是知识库文档全量重建索引的时候。建议宿主机用 SSD哪怕是 SATA 接口的 SSD 也比机械盘强得多。我在测试环境吃过亏用 HDD 跑全量知识库索引三千份 PDF 跑了快两个小时换成 SSD 后十分钟出头就完成了。2.3 私有化镜像的获取方式与离线导入技巧讯飞 Astron Agent 掘金版的镜像是通过官方私有镜像仓库分发的。在你获得开通资格后官方会给一个 registry 地址和一组临时凭证。镜像拉取的步骤# 1. 登录私有镜像仓库 docker login registry.example.com -u your-username -p your-password # 2. 拉取核心镜像 docker pull registry.example.com/astron/gateway:latest docker pull registry.example.com/astron/agent-runtime:latest docker pull registry.example.com/astron/web:latest # 3. 拉取依赖镜像如果官方没有在 compose 里指定 docker pull postgres:15-alpine docker pull redis:7-alpine docker pull minio/minio:latest docker pull qdrant/qdrant:latest如果你所在的网络环境访问不了外网或者镜像仓库不稳定提前做好离线导入方案# 在一台能上网的机器上导出镜像 docker save -o astron-images.tar registry.example.com/astron/gateway:latest registry.example.com/astron/agent-runtime:latest # 拷贝到目标服务器后导入 docker load -i astron-images.tar离线导入这里有个小经验docker save尽量一次性把多个镜像打包成一个 tar 包别一个镜像一个包。这样不管是拷贝还是导入都省时间也不容易漏。我一般会把所有镜像打包成astron-all-images.tar传到服务器上一次性docker load搞定。3. docker-compose.yml 核心编排逻辑拆解编排文件是整个部署的核心。我会逐段讲清楚每个服务的作用和关键配置以及它们之间是怎么协作的。3.1 服务拓扑一次讲清楚谁依赖谁先看整体拓扑。Astron Agent 掘金版跑起来之后容器之间的调用关系是这样的Web 控制台前端静态资源 --请求-- 网关服务 网关服务 --转发-- Agent 运行时 Agent 运行时 --读写-- PostgreSQL元数据/会话 Agent 运行时 --读写-- Redis缓存/会话状态 Agent 运行时 --读写-- MinIO文档对象存储 Agent 运行时 --读写-- 向量库知识库检索 Agent 运行时 --调用-- 星火大模型 API外部网关是所有请求的入口负责身份认证、流量转发、静态资源托管。Agent 运行时是业务核心承接 Agent 的编排、推理、工具调用所有中间件都由它访问。中间件之间没有相互调用这是非常清晰的分层。3.2 关键配置逐项解读网络、卷、健康检查与依赖顺序我这份 docker-compose.yml 是经过几轮调整后定型的。下面把关键配置逐项拆开讲。services: gateway: image: registry.example.com/astron/gateway:latest container_name: astron-gateway ports: - 8080:8080 # 对外暴露的控制台和 API 入口 - 8443:8443 # HTTPS 端口生产环境建议启用 environment: TZ: Asia/Shanghai ASTRON_API_BASE_URL: http://agent-runtime:8000 volumes: - ./data/gateway/logs:/app/logs - ./data/gateway/certs:/app/certs:ro depends_on: agent-runtime: condition: service_healthy restart: unless-stopped这里有两个关键设计。第一服务间通过容器名agent-runtime访问而不是 IP。Docker Compose 会自动创建了一个默认的 bridge 网络所有在同一个 compose 文件里的服务都能通过服务名互相解析。这样即使容器的 IP 因为重启发生了变化服务之间的调用也不会断。第二depends_on配合condition: service_healthy控制启动顺序。这里我踩过一个坑刚开始写的是没有condition的普通depends_on结果网关先起了然后它去连接 Agent 运行时发现连接被拒直接抛异常退出了。虽然重启策略能自动拉起但总是会有一段空窗期。后来给 agent-runtime 加了健康检查告诉 Compose 这个服务真正可用之后再去启动网关agent-runtime: image: registry.example.com/astron/agent-runtime:latest container_name: astron-agent-runtime volumes: - ./data/agent-runtime:/app/data - ./data/knowledge-base:/app/knowledge-base environment: TZ: Asia/Shanghai DATABASE_URL: postgresql://astron:astron_passwordpostgres:5432/astron REDIS_URL: redis://redis:6379/0 MINIO_ENDPOINT: minio:9000 MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY} MINIO_SECRET_KEY: ${MINIO_SECRET_KEY} VECTOR_STORE_URL: http://qdrant:6333 SPARK_API_KEY: ${SPARK_API_KEY} SPARK_API_SECRET: ${SPARK_API_SECRET} depends_on: postgres: condition: service_healthy redis: condition: service_healthy minio: condition: service_healthy qdrant: condition: service_healthy healthcheck: test: [CMD, curl, -f, http://localhost:8000/healthz] interval: 15s timeout: 5s retries: 3 start_period: 40s restart: unless-stopped中间件的健康检查是关键。以 PostgreSQL 为例postgres: image: postgres:15-alpine container_name: astron-postgres environment: POSTGRES_USER: astron POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: astron volumes: - ./data/postgres:/var/lib/postgresql/data healthcheck: test: [CMD-SHELL, pg_isready -U astron] interval: 10s timeout: 5s retries: 5 restart: unless-stoppedpg_isready是 PostgreSQL 官方自带的探活命令比用curl探测 TCP 端口要准确得多——它不仅能确认端口通不通还能确认 PostgreSQL 是否已经完成了启动过程、可以接受查询了。数据持久化的核心在卷配置。所有有状态的数据都必须挂载到宿主机目录。我这边约定把所有数据放在部署目录下的data/子目录里这样备份的时候只需要把整个data/目录带走就行逻辑清晰数据目录归属服务内容说明data/postgres/PostgreSQL元数据、用户、Agent 配置、会话记录data/minio/MinIO知识库原始文档、中间文件data/qdrant/向量库向量索引数据data/redis/RedisAOF 持久化文件data/gateway/网关访问日志、证书3.3 环境变量与密钥管理星火 API Key 的注入方式星火 API 的鉴权密钥肯定不能直接写死在 docker-compose.yml 里。我的做法是用.env文件统一管理所有敏感配置docker-compose.yml 里通过${VARIABLE_NAME}引用。创建.env文件# 数据库密码生产环境请使用强密码 POSTGRES_PASSWORD这里填一个足够复杂的密码 # MinIO 访问密钥 MINIO_ACCESS_KEYastron-minio-admin MINIO_SECRET_KEY这里也填一个足够复杂的密码 # 讯飞星火 API 凭证 SPARK_API_KEY你的星火APIKey SPARK_API_SECRET你的星火APISecret注意几点.env 文件不要提交到 Git 仓库在 .gitignore 里必须加一行.env。我在团队里见过不止一次有人把 .env 一起推上去了整个公司的星火 API Key 就裸奔在 Git 历史里。PostgreSQL 的密码强度要足够因为 Agent 元数据库里存了知识库索引的配置信息、用户账号体系的加密哈希如果密码太弱导致数据库被攻破整个私有化部署的隔离就没有意义了。MinIO 的 Access Key 和 Secret Key 长度有要求Secret Key 至少 8 位并且不能是纯数字。我在测试环境吃过这种亏——部署好了之后发现上传文件一直报签名错误排查了半天最后发现是 Secret Key 不符合 MinIO 的规范。4. 从初始化到跑通完整部署流程配置全部就位后实际的部署操作反而很快。我习惯把整个过程分成三步初始化目录、启动编排、验证功能。4.1 第一步先初始化配置目录与密钥文件在目标服务器上创建部署目录并准备好所有必须的配置文件# 1. 创建部署目录 mkdir -p /opt/astron cd /opt/astron # 2. 创建数据子目录避免容器以 root 创建导致权限问题 mkdir -p data/{postgres,minio,qdrant,redis,gateway/logs,gateway/certs,agent-runtime,knowledge-base} # 3. 创建 .env 文件并编辑 vi .env我建议在首次启动前先手动创建好这些目录比让容器自动创建更稳妥。容器在自动创建目录时往往以 root 身份运行之后你再想以普通用户挂载卷访问这些目录就会遇到权限问题。如果你有 HTTPS 证书放到data/gateway/certs/目录下。没有的话可以先用 HTTP 模式跑起来等准备号证书再加。掘金版支持在网关的环境变量里切换 HTTP/HTTPS 模式这点后面再说。4.2 第二步编排文件就位后的启动与日志观察把 docker-compose.yml 放到/opt/astron/目录下然后执行# 先拉取所有镜像 docker compose pull # 再启动全部服务-d 表示后台运行 docker compose up -d # 查看服务启动状态 docker compose ps第一次启动时不要加-d直接用docker compose up前台运行这样能实时看到所有容器的启动日志。确认一切正常之后再按CtrlC改用docker compose up -d后台运行。我正常启动后的日志是这样的astron-postgres | LOG: database system is ready to accept connections astron-redis | Ready to accept connections tcp astron-minio | API: http://minio:9000 astron-qdrant | Qdrant 1.x.x is ready astron-agent-runtime | INFO: Application startup complete. astron-gateway | INFO: Server listening on port 8080如果某个服务卡在启动中用docker compose logs -f 服务名单独看它的日志。比如docker compose logs -f agent-runtime日志里有几个关键词要重点关注ERROR/FATAL直接的错误信息Connection refused说明依赖的中间件还没就绪检查depends_on配置permission denied说明数据目录的权限有问题检查宿主机目录归属4.3 第三步验证控制台、Agent 调用与数据持久化服务全部起来了不要急着说部署完成。按我下面的清单逐项验证验证控制台浏览器访问http://服务器IP:8080如果能出现讯飞 Astron Agent 的登录页说明网关正常。默认的管理员账号和密码一般在部署文档里有说明第一次登录之后建议立刻改掉。验证 Agent 对话在控制台创建一个简单的 Agent输入一个测试问题。如果智能体能正常回复说明从网关到 Agent 运行时再到星火大模型的整条链路是通的。这一步最关键如果卡住先排查环境变量里的星火 API Key 是否正确。验证知识库上传在控制台上传一份 PDF 文档到知识库看是否出现上传成功的提示。这背后是 MinIO 的写入、文档解析、向量化和向量库索引的完整流程。上传后立刻发起一次针对该文档内容的提问确认 RAG 检索链路也是通的。验证数据持久化执行docker compose restart重启所有容器确认之前创建的 Agent、上传的文档、聊天记录都还在。这是判断数据卷是否挂载正确的最终手段。如果重启后数据没了九成是卷配置写错了。5. 接入星火大模型 API让 Agent 真正张嘴说话Astron Agent 掘金版默认可以对接讯飞星火大模型。这一步我单独拿出来讲是因为它涉及两个层面的配置平台层的鉴权对接和应用层的调用验证。5.1 星火 API 的鉴权方式与链路配置接入星火大模型 API 需要三样东西API Key、API Secret、服务地址。这些可以在讯飞开放平台的控制台里申请。在 Astron Agent 的管理后台里找到模型配置或者模型服务页面填入配置项示例值说明模型服务地址wss://spark-api.xf-yun.com/v3.5/chatWebSocket 协议地址API Key一串英文字符和数字你的星火 API KeyAPI Secret一串英文字符和数字你的星火 API Secret保存之后平台内部会自动完成鉴权握手。每次 Agent 对话时后端会从本地环境变量也就是 .env 里注入的SPARK_API_KEY和SPARK_API_SECRET读取密钥拼接签名后建立 WebSocket 连接。5.2 知识库文档挂载与向量化流程知识库是私有化部署的核心价值之一。Astron Agent 掘金版支持把内部文档上传到平台自动完成切片、向量化、索引构建之后就可以基于这些文档进行问答。知识库文档的流转链路是这样的上传文档 - MinIO 存储 - 文档解析PDF/Word/Markdown - 纯文本 - 文本切片 - 调用 Embedding 模型做向量化 - 存入向量库 - 用户提问时将问题向量化后去向量库做相似度检索 - 将命中的文本片段拼进 Prompt - 交给星火大模型生成回答这个链路每一环都可能出问题。最常遇到的问题有三个文档解析失败扫描版 PDF其实是图片无法直接提取文字需要先做 OCR。后台上传时如果提示解析失败可以先把 PDF 转成 Word 再传。切片长度设置不当切片太长上下文窗口不够用切片太短语义完整性被破坏。官方推荐的切片大小是 512 个字符、重叠 128 个字符我实测这个参数在大多数场景下效果都还不错。向量库存储空间不足知识库文档量大之后向量化索引占用的磁盘空间会明显增长。我在部署时给data/qdrant/预留了 10GB 空间结果两个月不到就用了一半。5.3 用 Python 快速写一个调用验证脚本配置完后台之后强烈建议用脚本直接验证一次星火 API 的连通性。这一步能帮你把平台问题和模型服务问题分开——如果 Python 脚本直连星火 API 正常说明问题出在 Astron Agent 平台侧的配置反之如果脚本都调用不通那就要回到星火开放平台检查你的账号额度或密钥是否有效。下面是一个最简的 Python 调用脚本基于星火 API 的 WebSocket 接口import os import json import _thread as thread import time import base64 import hmac import hashlib from datetime import datetime from wsgiref.handlers import format_date_time from urllib.parse import urlencode import websocket # 配置区域改成你自己的密钥 APPID 你的APPID API_KEY 你的APIKey API_SECRET 你的APISecret # 星火 API v3.5 的 WebSocket 地址 host spark-api.xf-yun.com path /v3.5/chat url fwss://{host}{path} def generate_auth_url(): now datetime.now() date format_date_time(time.mktime(now.timetuple())) signature_origin fhost: {host}\ndate: {date}\nGET {path} HTTP/1.1 signature_sha hmac.new(API_SECRET.encode(), signature_origin.encode(), digestmodhashlib.sha256).digest() signature base64.b64encode(signature_sha).decode() authorization_origin fapi_key{API_KEY}, algorithmhmac-sha256, headershost date request-line, signature{signature} authorization base64.b64encode(authorization_origin.encode()).decode() v {authorization: authorization, date: date, host: host} return url ? urlencode(v) def on_message(ws, message): data json.loads(message) code data[header][code] if code ! 0: print(f错误{code}, {data[header][message]}) ws.close() return choices data.get(payload, {}).get(choices, {}) if choices: text choices[text][0][content] print(text, end) status choices[status] if status 2: ws.close() def on_error(ws, error): print(fWebSocket错误: {error}) def on_open(ws): def run(): question 什么是私有化部署 payload { header: {app_id: APPID, uid: test-user}, parameter: { chat: { domain: generalv3.5, temperature: 0.5, max_tokens: 1024, } }, payload: { message: { text: [{role: user, content: question}] } } } ws.send(json.dumps(payload)) thread.start_new_thread(run, ()) if __name__ __main__: ws websocket.WebSocketApp( generate_auth_url(), on_messageon_message, on_erroron_error, on_openon_open ) ws.run_forever()跑一下这个脚本如果能看到正常的回答说明星火 API 的密钥和网络链路完全没问题。这时候回到 Astron Agent 平台侧排查才是正确方向。6. 部署之后踩过的坑完整排查链路实录部署文档里不会教你排错。我把自己在真实环境里踩过的三个坑完整写出来包括现象、排查思路和最终根因希望能帮你避开同样的弯路。6.1 坑一Redis 内存碎片导致 Agent 响应越来越慢现象部署完运行了一周左右发现 Agent 的响应时间从原来的一两秒慢慢涨到了十几秒甚至偶尔超时。控制台里看 CPU 和内存Agent 运行时的负载都不高。排查过程第一步用docker stats看所有容器的资源占用。发现 Redis 容器的内存使用率一直在涨从最初的几百 MB 涨到了接近 2GB但没达到容器内存限制。第二步进入 Redis 容器用redis-cli info memory查看详细的内存统计docker exec -it astron-redis redis-cli info memory重点关注两个指标used_memory_rssRedis 实际占用的物理内存used_memoryRedis 存储数据实际使用的内存发现used_memory只有 500MB 左右但used_memory_rss已经接近 2GB。这两个值差距巨大说明 Redis 内部出现了严重的内存碎片。第三步查看mem_fragmentation_ratio内存碎片率数值已经到 4.0 左右远超正常的 1.5。根因Astron Agent 在运行时会频繁往 Redis 写入短期缓存和会话状态产生大量创建和删除操作。Redis 默认的内存分配策略是jemalloc在这种高频率的小对象增删场景下内存碎片会不断积累。当碎片率过高时Redis 的读写性能会明显下降因为每次分配内存都需要在碎片化的堆里寻找合适空间。解决在 Redis 配置中加上command: redis-server --maxmemory 1gb --maxmemory-policy allkeys-lru --activedefrag yesmaxmemory设置上限allkeys-lru让 Redis 在内存满时优先淘汰最早未使用的键activedefrag开启主动碎片整理。改完之后Agent 的响应时间恢复到了正常水平。经验Redis 的性能问题不一定是内存不够先看碎片率再看淘汰策略。碎片率过高实际上是更常见的问题。6.2 坑二MinIO 存储桶权限引发的上传失败现象控制台上传文档到知识库时一直转圈然后报上传失败。平台日志里没有任何显眼的异常看起来像是前端请求超时。排查过程第一步看 Agent 运行时的日志docker compose logs agent-runtime | grep -i error发现日志里出现过AccessDenied和PutObject相关的错误指向 MinIO 权限问题。第二步进入 MinIO 容器检查存储桶权限docker exec -it astron-minio sh # 先配置别名 mc alias set local http://localhost:9000 ${MINIO_ACCESS_KEY} ${MINIO_SECRET_KEY} # 查看存储桶策略 mc policy get local/astron-knowledge发现astron-knowledge存储桶的策略是none也就是没有任何访问策略。根因MinIO 创建存储桶后默认的访问策略是私有的。Astron Agent 运行时使用的服务账号虽然有 MinIO 的 Access Key 和 Secret Key但如果没有在存储桶层面给这个账号授权写权限上传操作就会被拒绝。很多开源软件在初始化时会自动创建存储桶并设置好策略但 Astron Agent 掘金版把这步留给了运维人员。解决给存储桶设置合适的访问策略mc policy set download local/astron-knowledgedownload策略表示允许公开读取、但写入需要合法凭证。如果需要更细粒度的 ACL也可以用mc admin policy创建自定义策略再绑定到指定用户。经验遇到上传失败但应用日志不报错的情况优先检查对象存储的权限配置。MinIO 的权限体系本身就比 S3 简单不少但也正因为简单很多部署者容易忽略存储桶级别的权限设置。6.3 坑三HTTP 代理环境变量污染导致内部调用超时现象部署在公司的内网服务器上所有服务都正常启动了但 Agent 调用星火 API 时总是超时。奇怪的是在服务器上用 Python 脚本直接调用星火 API 是完全正常的。排查过程第一步在宿主机上测试curl -k https://spark-api.xf-yun.com能正常响应说明服务器到星火 API 的网络是通的。第二步进入 Agent 运行时容器测试docker exec -it astron-agent-runtime sh curl -k https://spark-api.xf-yun.com发现超时但在宿主机上没问题问题出在容器内部。第三步检查容器的环境变量docker exec -it astron-agent-runtime env | grep -i proxy发现容器内存在HTTP_PROXYhttp://192.168.1.100:3128和HTTPS_PROXY这两个环境变量。根因公司的服务器上配置了全局 HTTP 代理环境变量写在/etc/environment里docker-compose 在解析容器环境变量时会把宿主机的一部分环境变量透传给容器。Agent 运行时内部在调用星火 API 时这些请求都被强制走代理而代理服务器没法访问外网的星火 API 地址所以就超时了。解决在 docker-compose.yml 的每个服务里显式清除代理变量或者设置NO_PROXYenvironment: HTTP_PROXY: HTTPS_PROXY: NO_PROXY: localhost,127.0.0.1,postgres,redis,minio,qdrant,agent-runtime,gateway经验生产环境服务器的全局代理变量是容器化部署的头号隐形杀手。凡是遇到宿主机正常、容器内不正常的问题第一件事检查容器的代理相关环境变量。这个问题我见过太多次了。7. 跑顺之后的收尾备份、升级和横向扩展部署跑通了Agent 也能对话了这才算完成了 70%。剩下 30% 是运维层面的工作——如果不把这些收尾做好后面迟早要还债。7.1 数据备份清单哪些目录是绝对不能丢的先明确哪些数据必须备份。我列了一个优先级清单优先级数据位置说明P0data/postgres/Agent 的元数据、用户账号、配置全部在这里丢了等于全部重来P0data/minio/上传的原始知识库文档很多是内部独有资料丢失不可恢复P0data/qdrant/向量索引虽然可以重建但重建非常耗时P1data/redis/缓存和会话状态丢了影响不大用户重新登录即可P1docker-compose.yml.env部署配置建议直接进 Git 仓库管理.env 加密存储最简单的备份策略就是一条 cron0 2 * * * tar -czf /backup/astron-$(date %Y%m%d).tar.gz -C /opt/astron data docker-compose.yml .env这个策略的粒度是天级。如果对数据完整性要求更高建议把 PostgreSQL 的备份单独做用pg_dump做逻辑备份做到小时级甚至更细的粒度。7.2 组件升级时的依赖版本联动策略Astron Agent 掘金版会不定期发布新版本。升级时最容易踩的坑是只升级应用服务不升级中间件结果新版本代码用了旧版本中间件不支持的特性导致功能异常。我建议的升级策略是先备份docker compose down之前先把data/目录完整备份一次。看官方升级文档确认新版本的docker-compose.yml里中间件的版本是否有变化。如果从postgres:15升到了postgres:16必须先做数据迁移不能直接替换镜像啟動。逐次升级先升级中间件确认启动正常、数据无损后再升级应用服务。验证升级完跑一遍我前面提的三步验证——控制台、Agent 对话、知识库问答。全部通了才算升级成功。有段时间我以为版本升级是小事直接改镜像 tag 然后docker compose up -d结果新版本的 Agent 运行时需要 Qdrant 的某个新特性而我的 Qdrant 还是旧版本导致知识库检索完全不可用。教训就是升级应用前先确认依赖组件的兼容性不要盲目追新。7.3 负载跑高之后的横向扩展思路如果单机 Compose 跑了一段时间后出现了 CPU 长期打满、Agent 响应时间拉长的情况那就该考虑横向扩展了。Astron Agent 掘金版的扩展思路相对清晰Agent 运行时是无状态的可以多副本。docker-compose.yml 里直接写agent-runtime: deploy: replicas: 3网关可以多副本前面挂一个负载均衡器或 Nginx。网关本身也是无状态的。PostgreSQL 和 Redis 是状态服务单机方案下先扛着。如果这两个是瓶颈说明你的用户量已经超出了掘金版单机部署的定位该考虑迁移到云数据库或 K8s 了。注意如果你只是在单机内增加副本容器端口映射会冲突需要配合负载均衡。比如 3 个 agent-runtime 副本容器内部都在 8000 端口监听但宿主机上只能映射一个 8000 端口其他副本就不能再映射 8000 了。这时候直接让网关通过容器网络内部访问即可——gateway 用http://agent-runtime:8000访问的是当前这个服务在 compose 网络里的负载均衡地址Compose 会自动在多个副本之间做 DNS 轮询。这个机制一开始也让我困惑了一阵实际验证过确实有效。最后说一点个人经验。这套 Compose 部署方案我已经跑了将近半年最大的体会是私有化部署的成败七分在配置管理三分在环境准备。把 .env、docker-compose.yml、数据目录的备份策略从一开始就规范起来后面运维会非常省心。不要图省事把所有配置一股脑塞进 docker-compose.yml 里——留一份干净、可复现、有版本记录的编排文件比任何运维工具都管用。如果后面有机会我再写一篇关于 Astron Agent 掘金版做二次开发的实践——在 Agent 运行时里接入自定义工具链、扩展知识库解析器这套平台在这方面的可玩性其实挺高的。
返回列表