
上个星期我在内网一台“吃灰”的 8 核服务器上把讯飞 Astron Agent 掘金版完整跑了起来。前后折腾了差不多两个晚上踩的坑基本都集中在 Docker Compose 安装这一层——端口、环境变量、数据库初始化还有启动顺序。今天我就把整套安装过程包括踩坑记录一次性整理出来。这篇教程不是那种“你只要复制粘贴就能跑”的标题党而是基于我自己实际操作沉淀下来的完整流程。适合三类人看一是公司内部想搭一套私有化 AI Agent 平台、又不想直接用 SaaS 服务的团队二是想在自己实验室里把 Astron Agent 掘金版跑起来研究原理的开发者三是已经被 Docker Compose 折磨过、想找一份带解释的参考配置的同学。下面所有步骤我尽量把“为什么这样做”也讲清楚。1. 为什么要用 Docker Compose 私有化跑 Astron Agent 掘金版1.1 私有化部署不是“炫技”是刚需先说结论如果你只是个人学习其实直接调云端的 API 就够用了。但只要牵扯到团队协作、内部数据或者你想在 Agent 里挂载自己的知识库、数据库、业务系统那私有化部署几乎是唯一路径。Astron Agent 掘金版这个形态我个人理解是面向开发者社区的一个定制版本重点在于把 Agent 的调度、工具调用、知识检索等核心组件全部打成一个可自助部署的软件包。和公有云版本相比掘金版的优势在于数据完全留在内网请求不经过外部队列适合有数据合规要求的场景可以在自己的服务器上调整资源配额想给 Agent 分配多少上下文、多少并发都由自己说了算方便和内部系统做深度集成比如让它调用公司已有的 API、读取内网数据库这种场景下私有化部署比硬走公网安全得多。Docker Compose 在这个当口就是最合适的交付方式。你不用理解整个服务内部是怎么拆微服务的只要按照编排文件把容器一个个拉起来再设置好环境变量整个平台就能工作。1.2 Compose 相比裸机安装到底省了什么我见过很多团队在裸机上装这类系统过程大概是装 Python 环境、装数据库、装 Redis、配 Nginx、调 systemd 服务一套操作下来少说半天。而且最头疼的是版本依赖——有时候系统自带的 OpenSSL 版本不对编译某个 Python 包就直接卡死。Compose 把这些问题全部收口到镜像和编排文件里依赖跟着镜像走启动顺序用depends_on控制数据目录通过卷映射到宿主机。你不需要知道 Agent 后端用的是哪个 Web 框架也不需要关心它依赖的某个底层库在 Ubuntu 22.04 上能不能编译。只要宿主机的 Docker 能跑Compose 就能跑。这就是我强烈推荐用 Compose 做私有化部署的根本原因。2. 部署前要确认的三件事硬件、系统与网络策略2.1 硬件资源怎么规划这一步最容易被人忽略。Astron Agent 掘金版虽然不像大模型训练那么吃资源但它的运行时依然要承担模型推理调度、向量检索、对话上下文管理这些活资源给少了启动都能漏出各种诡异问题。我自己的测试环境是 8 核 CPU、16GB 内存、200GB 磁盘。如果你的服务器配置低一些比如 4 核 8GB也能跑但建议只开一个 Agent 实例并且不要开太多并行任务。下面是供参考的最低配置和推荐配置配置项最低要求推荐配置多人团队CPU4 核8 核及以上内存8 GB16 GB 及以上磁盘50 GB200 GB SSD网络内网可达千兆内网磁盘这块要特别说一句。别只看数字实际使用中日志和向量数据库都会疯狂涨尤其是知识库导入量大、对话轮次多的时候。我建议把数据目录单独挂到一块数据盘上别和系统盘混在一起否则运行两三个月后很容易出现/分区被撑满的情况。2.2 操作系统与 Docker 环境系统方面Ubuntu 22.04 LTS 是我这边测试过最省心的选择。CentOS 7 的问题在于默认的 iptables 版本和 Docker 新版的兼容性偶尔会出幺蛾子如果你还在用老 CentOS建议先升级或者改用其他更主流的发行版。Docker 和 Compose 插件按官方推荐安装即可。需要注意新版 Docker 的 Compose 命令是docker compose中间有空格而不是老的docker-compose。安装完后用下面几条命令确认一下环境docker --version docker compose version docker infodocker info的输出里重点关注 Storage Driver 是不是overlay2如果显示的是vfs或其他类型说明存储驱动没有优化这会直接影响容器读写性能。2.3 网络端口与防火墙策略Astron Agent 掘金版默认需要开放两个端口一个是 HTTP 服务端口假设是8080用来访问 Agent 的 Web 界面和 API另一个是 Agent 内核服务端口假设是9090用于运行时任务调度。如果你的防火墙默认拒绝所有入站流量务必提前放行。放行端口前先想清楚一个原则8080如果只是给内网同事用就不要暴露到公网如果确实需要从外部访问建议在前面加一层反向代理并且用 HTTPS 加密流量。我见过不少直接把端口映射到公网的例子结果过两天日志里全是扫描器在探测路径相当烦人。放行端口示例Ubuntu 使用 ufwsudo ufw allow 8080/tcp sudo ufw allow 9090/tcp sudo ufw reload3. 从零到一目录规划、环境文件与 Compose 编排3.1 推荐目录结构部署前先规划目录这一步能省掉后面很多维护麻烦。我习惯把所有相关文件放在/opt/astron-agent-jj下整个结构长这样/opt/astron-agent-jj/ ├── .env ├── docker-compose.yml ├── data/ │ ├── postgres/ │ ├── redis/ │ └── astron-agent/ ├── logs/ └── backups/data和logs目录要提前创建好并且确保当前用户有读写权限。Compose 在映射宿主机目录到容器时如果目录不存在会自动创建但创建出来的属主往往是 root后续操作日志、备份数据会比较麻烦。所以宁可手动创建并设置好属主mkdir -p /opt/astron-agent-jj/data/{postgres,redis,astron-agent} mkdir -p /opt/astron-agent-jj/logs mkdir -p /opt/astron-agent-jj/backups chown -R 1000:1000 /opt/astron-agent-jj/data如果你登录服务器的用户不是 root用sudo创建之后记得把目录属主改成当前用户或者改成容器内默认用户的 UID这里假设是 1000具体要看镜像说明我后面会讲怎么看。3.2 环境变量文件 .env环境变量文件是 Compose 部署的核心。先看示例# /opt/astron-agent-jj/.env # 基础配置 ASTRON_AGENT_VERSIONjianjin-latest TZAsia/Shanghai # 数据目录 DATA_DIR/opt/astron-agent-jj/data LOG_DIR/opt/astron-agent-jj/logs # 服务端口 HTTP_PORT8080 CORE_PORT9090 # 数据库配置 POSTGRES_DBastron_db POSTGRES_USERastron_user POSTGRES_PASSWORDchange_this_password POSTGRES_PORT5432 # Redis 配置 REDIS_PASSWORDchange_this_redis_password REDIS_PORT6379 # 模型服务配置视你自己的网关地址而定 LLM_API_BASEhttp://your-gateway:8000/v1 LLM_API_KEYsk-your-key LLM_MODELdefault-chat-model每个变量背后都有含义。LLM_API_BASE是模型服务的入口地址Astron Agent 本身不是一个模型而是一个 Agent 框架它需要对接一个大模型接口才能完成对话、规划、工具调用。你可以对接星火 API 的 OpenAI 兼容端点也可以对接内网自己部署的模型服务。很多人第一次部署失败就是以为这个平台自带模型结果发现没有模型地址Agent 一直显示“不可用”。数据库密码和 Redis 密码务必改掉不要用默认值。我见过直接沿用网上的示例密码数据库端口又暴露在公网结果被勒索脚本加密了所有表结构的真实案例这不夸张。3.3 docker-compose.yml 的完整解读Compose 文件是整个部署的“施工图纸”。以我实际使用的版本为基础关键内容如下# /opt/astron-agent-jj/docker-compose.yml services: postgres: image: postgres:15-alpine container_name: astron-postgres restart: unless-stopped environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - ${DATA_DIR}/postgres:/var/lib/postgresql/data networks: - astron-net healthcheck: test: [CMD-SHELL, pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}] interval: 10s timeout: 5s retries: 5 redis: image: redis:7-alpine container_name: astron-redis restart: unless-stopped command: [redis-server, --requirepass, ${REDIS_PASSWORD}, --appendonly, yes] volumes: - ${DATA_DIR}/redis:/data networks: - astron-net healthcheck: test: [CMD, redis-cli, -a, ${REDIS_PASSWORD}, ping] interval: 10s timeout: 5s retries: 5 astron-agent: image: astron-agent-jj:${ASTRON_AGENT_VERSION} container_name: astron-agent restart: unless-stopped depends_on: postgres: condition: service_healthy redis: condition: service_healthy environment: TZ: ${TZ} DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}postgres:5432/${POSTGRES_DB} REDIS_URL: redis://:${REDIS_PASSWORD}redis:6379/0 LLM_API_BASE: ${LLM_API_BASE} LLM_API_KEY: ${LLM_API_KEY} LLM_MODEL: ${LLM_MODEL} ASTRON_HTTP_PORT: 8080 ASTRON_CORE_PORT: 9090 ports: - ${HTTP_PORT}:8080 - ${CORE_PORT}:9090 volumes: - ${DATA_DIR}/astron-agent:/app/data - ${LOG_DIR}:/app/logs networks: - astron-net healthcheck: test: [CMD, curl, -f, http://localhost:8080/health] interval: 30s timeout: 10s retries: 3 networks: astron-net: driver: bridge逐个解释核心点depends_on加上condition: service_healthy确保 Agent 服务只会在数据库和 Redis 健康检查通过之后才启动。这个顺序非常关键。如果你用老旧的depends_on不带条件数据库还没初始化完成Agent 就开始建表大概率会报连接超时然后整条启动链路进入失败循环。restart: unless-stopped保证服务器重启后容器能自动拉起。部署这类服务别用restart: no除非你乐意半夜爬起来手动docker start。卷映射${DATA_DIR}/astron-agent:/app/data是把 Agent 运行产生的数据持久化到宿主机。这里尤其注意不要以为容器里写进去就万事大吉容器一删数据全没。所有需要持久化的数据必须通过 volume 映射出来。3.4 镜像来源本地构建还是直接拉取掘金版的镜像名称我写的是astron-agent-jj:jianjin-latest这个版本的镜像一般有两种获取方式。第一种是从你的私有仓库拉取已经打好包的镜像这种最省事docker compose pull直接搞定。第二种是获取源代码后在服务器本地构建docker build -t astron-agent-jj:jianjin-latest .。本地构建的好处是可以按照自己的需求改配置、加插件缺点是构建时间动辄十几分钟而且如果网络不稳定中间层缓存容易出问题。我个人建议先直接用官方打包好的镜像跑通全部流程确认整个平台符合你的预期之后再考虑自己构建、二次开发。不要一上来就自己编译那样出了问题很难判断是环境问题还是代码问题。4. 启动时序与健康检查别急着进 UI4.1 第一次启动完整命令序列配置文件都准备好之后在/opt/astron-agent-jj目录下先做一次配置解析docker compose config这个命令会检查.env和docker-compose.yml的语法是否正确并把最终生效的配置打印出来。我建议每次修改配置后都先跑一遍能少踩很多低级错误。如果这一步输出显示services.astron-agent.image等字段缺失或者变量没替换说明.env文件没有正确加载优先检查.env文件所在位置和命名。确认配置没有报错后开始拉取镜像并启动docker compose pull docker compose up -d启动之后用docker compose ps查看容器状态。刚刚启动的三秒内看到astron-agent显示running不代表启动成功它可能在启动过程中崩了之后又被 healthcheck 判定失败。正确做法是等三十秒左右再查看状态docker compose ps我的实际经验里三个容器最终的状态都应该是running (healthy)。其中 postgres 和 redis 的 healthy 一般比较快十几秒内就能看到astron-agent 可能要等二十秒到一分钟因为它要连接数据库、初始化表结构、加载 Agent 运行时整个过程稍微慢一点。4.2 通过日志判断启动进度docker compose ps只能告诉我们容器活没活要知道“跑到哪一步了”必须看日志。Astron Agent 的启动日志我这边分成几个阶段第一阶段是「config loading」日志里会打印读取到的模型地址、数据库地址这个阶段通常几十行第二阶段是「database migration」日志里会出现applying migration、migrate succeeded这类字样说明数据库表结构在初始化第三阶段是「core service started」看到core server listening on 0.0.0.0:9090时说明 Agent 内核已经起来了最后阶段是「http service started」出现http server started或web ui ready时说明 Web 界面可以访问了。看日志的命令docker compose logs -f astron-agent如果你发现日志一直卡在数据库连接的部分反复出现connection refused先不要急着怀疑镜像大概率是数据库还没健康或者.env里面的DATABASE_URL写错了。注意Compose 服务之间互联postgres这个主机名是服务名不是localhost这是新手最容易搞混的地方。在容器内部localhost是容器自己不是宿主机也不是别的容器。4.3 健康检查接口验证等容器状态变成 healthy 以后可以直接在宿主机上用curl验证 Agent 的 HTTP 健康检查接口curl -i http://127.0.0.1:8080/health如果返回的是200 OK并且 body 里的状态字段是ok或ready说明整个平台的主链路已经通了。到这里最艰难的安装阶段已经过去接下来才是真正需要花心思的配置阶段。5. 配置调优与内网访问把 Agent 真正交给团队5.1 首次登录与默认管理员账号Web 界面地址就是http://你的服务器IP:8080。第一次登录需要用到初始化管理员账号。这个账号怎么拿不同版本不一样有些版本会在 Agent 容器启动日志里直接打印初始密码有些版本需要执行一个账号初始化命令。最稳妥的办法是看容器日志docker compose logs astron-agent | grep -i admin我在测试的版本里日志会出现类似create admin user: admin / password ********的提示。如果你看完日志没有找到可以尝试进入容器执行初始化脚本docker compose exec astron-agent python cli.py create-admin --username admin --password your-password注意这只是一种常用的排查思路具体命令要以你拿到的镜像内部结构为准。实在找不到就先看容器的/app/README.md文件通常源码包或镜像里会有说明。登录成功后第一件事是修改默认密码然后进入“系统设置”页面把模型服务重新做一次连通性测试。很多人在浏览器里输入账号密码却发现一直转圈原因就是 Agent 服务和模型服务之间的网络不通登录本身虽然成功但后续初始化会话需要模型参与。5.2 模型服务对接不一定要走公网Astron Agent 掘金版需要对接一个大语言模型。这里有两条路如果你已经有内网部署的模型服务比如基于 vLLM、TGI 或者其他推理框架启动的服务直接把LLM_API_BASE指向内网地址如果你没有内网模型也可以选择走讯飞星火的 API。很多朋友之前写过 Python 调用星火 API 的小脚本其实核心就是拿 API Key 换 token然后按 OpenAI 兼容格式发请求。掘金版的LLM_API_BASE完全可以指向这类兼容端点。我特别建议在正式把平台交给团队使用之前先用一条最简单的文本对话测试模型通道。你可以在 Web 界面里新建一个标准 Agent然后发一句“你好”看看 Agent 能否正常回复。如果模型通道没通后续所有涉及工具调用、知识库检索的功能都会表现为“Agent 思考了很久然后报错”这种问题排查起来特别费劲根源可能在模型服务、网络、API Key 三个环节里来回跳。5.3 数据卷备份与定时策略部署完成不是终点数据运维才是长久的事。Astron Agent 的数据主要存在三个地方PostgreSQL 里的业务数据、Redis 里的缓存与任务队列、以及/opt/astron-agent-jj/data/astron-agent里的文件型数据比如上传的知识库文件、Agent 日志快照。我建议从第一天就养成备份习惯。最简版的备份思路cd /opt/astron-agent-jj docker compose exec postgres pg_dump -U astron_user astron_db backups/astron_db_$(date %Y%m%d).sql tar -czf backups/astron_files_$(date %Y%m%d).tar.gz data/astron-agent然后设置一个 crontab 定时任务每天凌晨执行一次0 2 * * * cd /opt/astron-agent-jj docker compose exec -T postgres pg_dump -U astron_user astron_db backups/astron_db_$(date \%Y\%m\%d).sql find backups -name *.sql -mtime 7 -delete备份这事用不到的时候觉得多余真出事的时候才知道命是备份给的。我吃过亏所以宁可多写一行脚本。5.4 资源限制与容器卫生如果是多人共用的服务器建议在 compose 文件里给每个服务加上资源限制阻止某个容器吃光宿主机内存导致 SSH 都连不上deploy: resources: limits: memory: 4g cpus: 2.0这个配置放在astron-agent服务下含义是该容器最多用 4GB 内存、2 个 CPU 核心。注意deploy配置在非 Swarm 模式下也会生效Compose 插件支持但有些老版本的docker-compose会忽略它所以还是那句话用新版 Docker。Redis 的持久化策略我开启了--appendonly yes也就是 AOF 持久化。相比 RDB 快照AOF 恢复粒度更细不容易丢数据。代价是会多占用一点磁盘对 Agent 这种需要保存会话任务状态的场景来说这点代价是值得的。6. 常见故障与排查思路含日志与容器状态6.1 端口占用导致启动失败docker compose up -d之后如果发现astron-agent容器反复重启先看端口有没有被占sudo ss -lntp | grep -E 8080|9090如果发现有其他进程占用了8080那就把.env里的HTTP_PORT改成8081这类不冲突的端口再重新docker compose up -d。注意改完端口后访问地址也要跟着变别傻傻地还在原端口访问。6.2 数据库连不上分清主机名与端口这是一个非常典型的问题。现象是 Agent 启动日志里反复出现Error: could not connect to server: Connection refused Is the server running on host postgres (172.x.x.x) and accepting TCP/IP connections on port 5432?大部分原因就是DATABASE_URL里的主机名写成了localhost。在 Compose 网络里容器访问其他服务必须使用服务名postgres、redis不能使用localhost。如果你在宿主机上测试postgres这个主机名肯定是解析不了的这不妨碍容器内联。修改.env里的DATABASE_URL后需要重新创建容器才能生效docker compose up -d --force-recreate astron-agent6.3 模型服务不可用导致的 UI 异常这种问题最容易让人误判。现象是 Agent 管理页面能打开但创建 Agent 后对话一直显示“正在思考”或者直接报错。这时候去查容器日志经常能看到类似LLM request timeout或者connection to LLM backend failed。处理思路分三步确认LLM_API_BASE在 Agent 容器里能访问docker compose exec astron-agent curl -s http://your-llm-address/v1/models确认 API Key 是否正确有些兼容端点返回 401 没有任何详情容易让人一头雾水确认网络策略如果模型服务部署在宿主机上Agent 容器内不能直接用localhost访问宿主机应该用host.docker.internal或者在 compose 文件里开启extra_hosts: - host.docker.internal:host-gateway。这个extra_hosts是很多新手的盲区我单独拿出来强调一下。6.4 健康检查一直不通过如果docker compose ps里 postgres 和 redis 都正常唯独astron-agent一直处于starting或者unhealthy先手动进容器查一下内部原因docker compose exec astron-agent sh # 进入容器后查看进程 ps aux # 查看端口是否监听 netstat -tlnp 2/dev/null || ss -tlnp如果发现容器内根本没有curl命令那问题可能出在镜像本身不带 curlhealthcheck 因为找不到命令而一直失败。这种情况可以改用 wget或者直接用 Python 写个健康检查。比如把 healthcheck 改成healthcheck: test: [CMD, python, -c, import urllib.request; urllib.request.urlopen(http://localhost:8080/health)] interval: 30s timeout: 10s retries: 3镜像的底层是什么不一定但curl不在镜像是常有的事别在一棵树上吊死。6.5 清理与重新初始化如果部署过程搞乱了最彻底的恢复方式是把所有容器和数据全部删掉重新来一遍docker compose down -v rm -rf /opt/astron-agent-jj/data/postgres/* rm -rf /opt/astron-agent-jj/data/redis/*down -v会删除 compose 文件里定义的卷但因为我们用的是宿主机目录映射-v删除的是未命名的卷不一定把宿主机目录清掉所以要手动清理数据目录。清理之后重新docker compose up -d就能得到一个全新的环境。这个操作只适合在确认数据不要了的情况下执行别手滑。7. 后续维护与一点经验之谈7.1 升级镜像的正确姿势Astron Agent 掘金版迭代速度不慢过一段时间可能会有新版镜像。升级时不要直接docker compose pull docker compose up -d先看一眼版本更新说明确认有没有破坏性的配置变更。我的升级流程是cd /opt/astron-agent-jj # 先备份 docker compose exec postgres pg_dump -U astron_user astron_db backups/pre_upgrade_$(date %Y%m%d%H%M).sql # 拉新镜像 docker compose pull astron-agent # 重新创建容器 docker compose up -d --force-recreate astron-agent升级后如果发现新版本日志里有结构变更可能需要手动执行迁移命令。不同镜像处理方式不同最简单的方法还是看日志缺什么补什么。7.2 日志轮转避免磁盘被写满容器如果长时间运行日志文件会越来越大。配置 Docker 的日志轮转可以让单容器日志文件超过大小后自动切割。在/etc/docker/daemon.json里加入{ log-driver: json-file, log-opts: { max-size: 50m, max-file: 3 } }然后重启 Docker 生效sudo systemctl restart docker这个配置对宿主机上所有容器生效。已经运行的容器需要重新创建后才会使用新配置所以配合升级操作一起做效率最高。7.3 我踩过几次坑之后的核心体会部署这套系统整体难度不高但有一个核心心态问题不要以为docker compose up -d之后万事大吉启动成功不等于服务可用服务可用不等于功能正常。我每次部署完毕都会老老实实过一遍“登录 Web UI - 新建 Agent - 发起对话 - 调用一个工具 - 查一次数据库落库情况”这五步全部走通才算部署完成。另外就是环境变量修改的问题。很多朋友改了.env之后不重新创建容器以为重启就行事实是docker compose restart并不会重新读取.env里的变量必须用docker compose up -d --force-recreate让容器重新生成。这个细节浪费了我至少半小时写下这篇教程时我特意放在这里希望你能少走这一步弯路。最后再分享一个小技巧部署完成后把整套 compose 文件和配置示例提交到一个内部 Git 仓库。这样如果有同事需要再部署一套或者需要回归测试直接git clone下来改几个环境变量就能跑。把所有部署知识沉淀成代码而不是留在某一个人的脑子里这才是私有化部署最值得投入的部分。