资讯动态

OpenClaw v2026.3.12离线部署全流程:Docker镜像构建与内网交付实践

发布时间:2026/9/29 15:22:23 来源:尧图企业网站定制
前段时间朋友托我搞定一件事把 OpenClaw v2026.3.12 完整部署到一台物理隔离的内网服务器上要求源码可追溯、镜像可离线交付、后续升级不靠外网。折腾了整整两天踩了不少坑也攒下一套能直接复用的流程。趁周末整理出来给正在搞 OpenClaw 离线部署、或者被 Docker 离线构建折磨过的同学当个参考。先说结论OpenClaw 这种依赖链极多的 AI Agent 项目离线构建的核心不是把源码拷进去编译而是提前在联网环境把源码、语言依赖、基础镜像全部固化成一等一干净的交付物到内网只用做加载编排配置三件事。整个过程的关键词就三个离线源码构建、Docker 镜像导出、容器化部署。这篇教程会从方案设计、物料准备、镜像构建、离线导入、容器编排一路讲到报错排查每一步都会解释为什么这么做以及我实测下来哪些坑必须提前避开。1. 整体设计思路与方案选型1.1 为什么必须走离线构建这条路接触过 OpenClaw 的都知道这项目功能模块很重核心 agent 引擎、会话管理、数据库迁移、外部渠道接入Webhook、Teams、Obsidian 这类、还有一堆 Web 端静态资源。直接拿源码到内网服务器上npm install go build基本是死路因为构建过程会访问几十个外网源随便一个包拉不下来就卡死。离线构建的本质是把构建期和运行期分开。构建期放在有网环境目的是把源码、依赖、二进制、静态资源全部锁死到镜像里运行期放在内网环境只做两件事加载镜像、跑容器。这样内网服务器根本不需要外网也不需要完整的编译工具链只要 Docker 环境可用就行。提示如果内网机器连 Docker 都没有那就要再准备一套 Docker 离线安装包deb/rpm这部分我也会在部署环节提到。1.2 版本锁定与交付物设计我锁定的版本是v2026.3.12。很多人习惯拉最新代码但在离线交付场景版本锁定是底线。源码在变、依赖在变、基础镜像 tag 也在变今天能构建成功不代表下周还能构建。锁定版本之后所有物料的校验值sha256固定到内网出问题能快速定位是环境问题还是物料问题。最终交付物清单建议这样设计交付物格式说明源码包openclaw-v2026.3.12.tar.gz带版本号包含完整 git 记录依赖清单go.sumpackage-lock.json锁定传递依赖应用镜像openclaw-server-v2026.3.12.tardocker save产物附属镜像postgres:16-alpine、redis:7-alpine运行时中间件编排文件docker-compose.yml.env.example环境变量模板安装脚本install.sh镜像加载启动一体化脚本这是一个最小可交付集缺了任何一个在内网都可能卡住。我第一版就漏了附属镜像结果到现场才发现 postgres 镜像拉不下来只能又跑回去导了一次非常耽误时间。1.3 Docker Compose 与裸机部署的取舍OpenClaw 运行起来至少要两个进程服务主进程和数据库加上 Redis 做会话缓存的话就是三个。裸机部署要手动管进程、管环境变量、管开机自启且 OpenClaw 的会话状态是强依赖外部存储的一旦进程挂了状态就乱。用 Docker Compose 编排的好处是服务依赖关系、网络通信、数据卷、重启策略全部声明在一个文件里到内网docker compose up -d一行搞定。我这次选的是 Docker Compose v2 语法兼容性好docker-compose 插件和独立二进制都能跑。镜像仓库没有用 registry因为内网规模小、镜像就两三个docker save/load比搭 registry 轻量得多。如果后续需要多台服务器分发再考虑搭个 harbor 或者 registry:2。2. 构建环境与物料准备2.1 构建机环境清单离线构建的前提是有一台能上外网的构建机。我用的是一台 Ubuntu 22.04 虚拟机配置如下CPU 8 核内存 16GB磁盘 200GBOpenClaw 构建过程对磁盘不狠但 Docker 镜像和缓存会占不少空间Docker 24.0.7装了 docker-compose 插件Go 1.22、Node.js 20 LTS、Python 3.11Git 2.39这里有一个容易忽略的细节构建机上需要预装的语言版本必须和 OpenClaw 项目要求一致。我吃过一次亏拿 Go 1.18 去构建新版 OpenClaw一堆标准库 API 编译不过后来看go.mod才发现要求的 Go 是 1.22。所以开始之前一定先看项目文档或者源码里的 go.mod / package.json 声明。2.2 源码获取与校验源码获取用 git 拉取对应 tag这一步不要省略校验git clone https://github.com/your-path/openclaw.git cd openclaw git checkout v2026.3.12 git submodule update --init --recursive如果项目有 submodule这一步必须执行否则源码不完整构建到一半才发现缺目录是很崩溃的。拉取完成后生成校验文件tar czf openclaw-v2026.3.12.tar.gz --exclude.git openclaw/ sha256sum openclaw-v2026.3.12.tar.gz openclaw-v2026.3.12.sha256exclude.git是为了缩小交付包体积。git 历史在内网场景没用但如果你希望内网还能看提交记录就保留 .git 目录代价是包体积大不少。我个人建议排除真要看代码用源码目录就够了。注意源码包、镜像 tar、sha256 文件要放在同一级目录别分层放。给内网交付时文件越少越不容易漏亲测分层放必漏东西。2.3 语言依赖预下载与私有仓库切换OpenClaw 的依赖主要分三块Go modules、npm 包、Python 依赖如果有插件。联网环境下先把依赖全部下载下来构建时用本地缓存# Go 依赖 go mod download # npm 依赖 npm ci # Python如有 pip download -r requirements.txt -d ./pip-cache但更稳妥的做法是直接用镜像构建把依赖都烤进镜像里内网就不需要这些缓存包了。这就是下一节要说的构建思路。3. 离线镜像构建与导出3.1 编写多阶段 DockerfileOpenClaw 官方 Dockerfile 我没直接用因为官方镜像构建完贼大而且很多构建缓存图层会跟着走。我改写成多阶段构建最终产物只保留运行所需的最小集合。# 阶段一构建 FROM golang:1.22-bookworm AS builder ARG VERSIONv2026.3.12 WORKDIR /src COPY openclaw-v2026.3.12.tar.gz . RUN tar xzf openclaw-v2026.3.12.tar.gz --strip-components1 RUN go mod download RUN go build -trimpath -ldflags-s -w -o /out/openclaw-server ./cmd/server # 阶段二前端资源如有 FROM node:20-bookworm AS frontend WORKDIR /src COPY --frombuilder /src /src RUN cd /src/web npm ci npm run build # 阶段三运行镜像 FROM debian:bookworm-slim RUN apt-get update apt-get install -y --no-install-recommends ca-certificates tzdata rm -rf /var/lib/apt/lists/* WORKDIR /app COPY --frombuilder /out/openclaw-server /app/openclaw-server COPY --fromfrontend /src/web/dist /app/web/dist COPY --frombuilder /src/configs /app/configs EXPOSE 8080 ENTRYPOINT [/app/openclaw-server]熟悉 Docker 的应该能看出来最终镜像只有三样东西二进制、前端静态资源、配置文件。-trimpath和-ldflags-s -w是 Go 构建的常规瘦身操作能省不少体积。3.2 构建参数与资源限制构建时我建议限制一下资源避免 OOMdocker build \ --build-arg VERSIONv2026.3.12 \ --memory8g \ --shm-size2g \ -f Dockerfile \ -t openclaw-server:v2026.3.12 .--shm-size是给 npm 构建用的npm 在高并发写入时 /dev/shm 不够会报错这个坑我踩过。构建完成后把镜像和附属镜像都导出成 tar 文件docker save openclaw-server:v2026.3.12 postgres:16-alpine redis:7-alpine \ -o openclaw-images-v2026.3.12.tar提示导出前先用docker image ls确认所有镜像 tag 都在本地。我遇到过 save 时报错找不到镜像折腾半天发现附属镜像只 pull 了一半根本没拉全。3.3 镜像体积分析与优化记录我构建完的 openclaw-server 镜像体积大约 180MB附属的 postgres 和 redis 各自在 100MB 左右总交付镜像约 380MB。对比官方镜像动辄 1GB这个体积在内网拷贝场景非常友好。如果还想压可以试试用distroless作为运行基础镜像但调试不方便我建议还是保留 slim 版本。4. Docker 离线部署全流程4.1 内网环境检查与 Docker 安装内网机器的 OS 我用的是 Ubuntu 22.04 Server。先检查环境docker version docker compose version如果没装 Docker用离线 deb 包安装。在联网机器下载# 下载 docker 及相关组件版本以实际为准 apt-get download docker-ce docker-ce-cli containerd.io docker-compose-plugin这里有一个很关键的操作要连带下载所有依赖apt-get download只会下载指定包不会自动下载依赖。正确做法用apt-get install --download-only配合--print-uris手工整理或者干脆用apt-rdepends。注意Docker 离线安装包版本要与内网 CPU 架构匹配。x86 的和 arm64 的内网机器不通用这个一定要先确认否则到现场直接抓瞎。4.2 离线镜像加载把交付物拷贝到内网服务器后docker load -i openclaw-images-v2026.3.12.tar加载完验证一下镜像列表docker images | grep openclaw这里有讲究必须使用交付 tar 里确定的镜像 tag不要后面重新打 tag。Compose 文件里写什么 tag镜像就必须是什么 tag不一致会报no such image或manifest unknown。4.3 docker-compose.yml 核心配置这是我部署用的 Compose 配置其中环境变量较多我统一用.env文件管理version: 3.8 services: db: image: postgres:16-alpine container_name: openclaw-db restart: always environment: POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_DB: openclaw volumes: - db_data:/var/lib/postgresql/data healthcheck: test: [CMD-SHELL, pg_isready -U ${DB_USER} -d openclaw] interval: 10s timeout: 5s retries: 5 redis: image: redis:7-alpine container_name: openclaw-redis restart: always command: [redis-server, --appendonly, yes] volumes: - redis_data:/data openclaw: image: openclaw-server:v2026.3.12 container_name: openclaw-server restart: always depends_on: db: condition: service_healthy redis: condition: service_started ports: - 8080:8080 env_file: - .env volumes: - openclaw_data:/data - ./configs:/app/configs:ro volumes: db_data: redis_data: openclaw_data:这套编排解决了一个核心问题容器启动顺序。OpenClaw 启动时会初始化数据库 schema如果 postgres 还没就绪就启动会报数据库连接失败重启几次也一样。用 healthcheck 的condition: service_healthy能保证数据库完全就绪后才拉起应用容器。4.4 环境变量与密钥管理.env文件是我部署中踩坑最多的地方重点说一下# 数据库配置 DB_USERopenclaw DB_PASSWORD你的强密码 DB_HOSTdb DB_PORT5432 # 会话与锁配置 SESSION_LOCK_TIMEOUT120000 SESSION_STORAGEredis # 服务端配置 APP_PORT8080 APP_BASE_URLhttps://your-domain.example.comSESSION_LOCK_TIMEOUT这个变量是我特别要强调的。OpenClaw 的会话文件锁机制默认超时是 60000ms但我在多请求并发时会频繁看到session file locked (timeout 60000ms)错误。用 Redis 做会话存储之后把超时调到 120000ms这个报错基本消失了。如果你在日志里看到这个报错优先检查这两件事会话存储是不是 Redis、超时时间是不是够用。密钥管理记得不要把明文密码写死在 Compose 文件里。内网环境虽然没有公网暴露风险但日志、备份、多人协作时密码还是会流转建议至少使用.env文件并加入.gitignore有条件就搞个简单的 in-memory secret 管理脚本。4.5 启动与验证部署完成后执行docker compose up -d docker compose ps看到三个容器都是 Up 状态之后再看日志docker compose logs -f openclaw正常启动后日志会出现类似server started on :8080的提示。然后访问http://服务器IP:8080能加载出 Web 界面就基本成功了。我习惯再加一步接口验证curl -I http://localhost:8080/api/health返回200 OK说明服务正常对外提供能力。如果内网有防火墙记得放行 8080 端口。有的内网环境默认禁 ping 和非标准端口排查时要想到这层。5. 常见问题与排查技巧实录5.1 session file locked (timeout 60000ms) 的根因与对策这个报错是热词里出现过的高频问题我再展开讲一下。它本质是 OpenClaw 并发处理同一个会话时文件锁无法在 60 秒内获取到。常见原因有三个多实例同时访问同一会话如果部署了多个副本又没有共享会话存储就会出现锁竞争。解决办法是单实例运行或者把会话存储切到 Redis。默认超时太短在会话处理逻辑复杂、数据库慢的情况下60 秒不够用。把SESSION_LOCK_TIMEOUT调大实测调到 120000ms 能解决大部分场景。锁文件残留进程被 kill 后锁文件没有自动清理后续一直拿不到锁。可以到容器里手动清除锁文件目录一般就在/data/sessions下再重启容器。5.2 Docker Desktop 虚拟化未启用的 Windows 部署问题热词里virtualization support not detected docker desktop failed to start也很有代表性很多同事是在 Windows 上装了 Docker Desktop结果起不来。这个报错几乎都是 Windows 虚拟化没开。检查顺序任务管理器-性能-CPU看虚拟化是否显示已启用如果没启用进 BIOS 开启 Intel VT-x 或 AMD-V确保 Windows 功能里勾选了适用于 Linux 的 Windows 子系统和虚拟机平台重启后再开 Docker Desktop还有一个隐藏坑装了第三方杀毒软件可能会占用 Hyper-V 组件导致 Docker Desktop 起不来。可以临时禁用再试确认后配置白名单。5.3 容器网络不通与端口不通内网部署最容易出问题是容器网络。有一次我起完服务在宿主机curl localhost:8080是通的但从其他机器访问就是不通。最后发现内网服务器开了防火墙但只放行了 22 端口。排查网络问题我有一套固定顺序先确认容器之间通信docker exec openclaw-server ping db再确认宿主机到容器curl localhost:8080最后确认外部到宿主机从另一台机器telnet 服务器IP 8080哪一步断了就查哪一层不要上来就怀疑 Docker 网络不行。Docker 默认 bridge 网络在单机场景是很稳的跨主机才需要额外配置。5.4 时区与证书问题容器默认时区是 UTC日志时间和内网服务器本地时间会差 8 小时。如果你希望日志时间对得上在 Compose 预加时区配置environment: TZ: Asia/Shanghai证书问题也很常见如果内网要启 HTTPS容器里自签证书是缺外网 CA 的要确保ca-certificates包在构建时已经装进镜像否则后续接入 Microsoft Teams 或 Obsidian 这类外部服务时TLS 握手会失败。5.5 数据库迁移失败与 schema 版本错乱OpenClaw 启动时会自动跑数据库迁移。离线部署时如果之前用旧版本初始化过数据库新版本 schema 迁移可能会冲突。我遇到过一次migration failed的情况解决方案是备份旧库后重建再让 OpenClaw 重新跑迁移。如果你保留了交付包的版本号迁移版本和源码版本保持一致就不会出这个问题。6. 最后的几点实践建议前面废话不多说直接收尾给建议。第一离线构建交付不是一锤子买卖每次升级版本都要重新走一遍物料准备、镜像构建、内网导入的流程。建议在构建机上写一个自动化脚本把源码下载、依赖缓存、镜像构建、save 导出全部串起来版本号做参数这样下次升级就是改一个版本号的事。第二交付物里一定要带一个 README写明部署步骤、环境变量说明、已知问题和联系方式别高估内网同事第一次接触这套东西的上手速度。第三内网部署前先在构建机上完整跑一遍 Docker Compose保证镜像没问题再导出否则现场崩了是真的一点外网都没得救。我在实际交付过程中最后又发现一个特别实用的细节导出的镜像 tar 包如果太大可以分片压缩再拷贝比如用split -b 500M openclaw-images.tar openclaw-images.tar.part内网再cat合并。U 盘拷贝大文件经常失败分片能很大程度避免这个问题。这个操作我每次都会用省了不少来回跑的时间。OpenClaw 这套 Offline 流程走到今天我是彻底理解了为什么大厂内部平台都要求构建与运行分离。只要你把物料锁死、把镜像固化、把编排声明清楚离线部署其实比在线部署还省心——没了随机性没有外网波动出了问题只管按清单排查就行。祝兄弟们一次成功。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑