笔记 | OpenClaw Docker 部署:从开发到生产的容器化实战

这两天一直在研究这个话题,踩了几个坑,把遇到的东西整理成文,供有需要的朋友参考。

目录

2. Docker 基础概念速览 3. OpenClaw Docker 镜像构建 4. docker-compose 多服务编排 5. 实战:从零容器化你的 OpenClaw 6. 常用问题与排错 7. 总结参考资料

摘要

Docker 部署是 OpenClaw 从开发环境走向生产环境的关键一步。本文从 Docker 基础概念出发,深入讲解 OpenClaw 的 Docker 镜像构建、多阶段优化、环境变量注入、数据持久化、健康检查配置,以及 docker-compose 多服务编排。通过一个完整的实战案例——将本地 OpenClaw 项目容器化并部署到服务器,你将掌握从 Dockerfile 编写到生产运行的全流程。读完你会注意到:容器化不是"加一层 Docker",而是让部署变得可重复、可移植、可扩展。


1. 引言:为什么你的 OpenClaw 需要 Docker

1.1 从"我机器上能跑"到"服务器上也能跑"

你一定遇到过这种场景:

  • 本地开发环境一切正常,部署到服务器后各种报错
  • “Python 版本不对”、“Node.js 版本太旧”、“系统依赖缺失”
  • 换个服务器又要重新配一遍环境
  • 团队新成员入职,光搭环境就要半天
Docker 解决的就是这个问题——把应用和它的所有依赖打包成一个镜像,在任何安装了 Docker 的机器上都能跑

1.2 容器化 vs 裸机部署

✅ Docker 部署

服务器1
Docker Engine

OpenClaw 容器
Python 3.11 + Node 20
+ 所有依赖

服务器2
Docker Engine

OpenClaw 容器
Python 3.11 + Node 20
+ 所有依赖

服务器3
Docker Engine

OpenClaw 容器
Python 3.11 + Node 20
+ 所有依赖

❌ 裸机部署

服务器1
Python 3.10
Node 18
Ubuntu 22.04

服务器2
Python 3.11
Node 20
CentOS 8

服务器3
Python 3.9
Node 16
Debian 11

维度裸机部署Docker 部署环境一致性❌ 每台机器不同✅ 镜像保证一致部署速度分钟级(安装依赖)秒级(拉镜像+启动)回滚手动恢复文件docker run 上一版本镜像资源隔离❌ 进程级✅ 容器级(CPU/内存限制)可移植性❌ 绑定操作系统✅ 任何支持 Docker 的系统扩展性手动配置多实例docker-compose / K8s 编排


2. Docker 基础概念速览

2.1 核心概念

在写 Dockerfile 之前,先厘清三个核心概念:

概念说明类比镜像(Image)应用的只读模板,包含代码+运行时+依赖安装包 ISO容器(Container)镜像的运行实例,有独立的文件系统和网络安装后的运行程序仓库(Registry)存储和分发镜像的地方App Store

docker build

docker push

docker pull

docker run

📄 Dockerfile

📦 镜像
openclaw:v1.0

🏪 Registry
Docker Hub

🖥️ 服务器

🚀 容器
运行中的OpenClaw

2.2 Dockerfile 基础指令

指令作用示例FROM指定基础镜像FROM node:20-alpineWORKDIR设置工作目录WORKDIR /appCOPY复制文件到镜像COPY . /appRUN在构建时执行命令RUN npm installENV设置环境变量ENV NODE_ENV=productionEXPOSE声明容器端口EXPOSE 18789CMD容器启动时的默认命令CMD ["node", "server.js"]


3. OpenClaw Docker 镜像构建

3.1 基础 Dockerfile

# ============================================
# OpenClaw Dockerfile - 基础版本
# 适用于开发环境和快速验证
# ============================================

FROM node:20-alpine

# 设置工作目录
WORKDIR /app

# 安装系统依赖
RUN apk add --no-cache \
    python3 \
    py3-pip \
    git \
    curl \
    bash

# 安装 OpenClaw
RUN npm install -g openclaw

# 创建数据目录
RUN mkdir -p /data/openclaw /etc/openclaw

# 复制配置文件
COPY openclaw.yaml /etc/openclaw/openclaw.yaml

# 声明端口
EXPOSE 18789

# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
    CMD curl -f http://localhost:18789/health || exit 1

# 启动 Gateway
CMD ["openclaw", "gateway", "start"]

构建和运行

# 构建镜像
docker build -t openclaw:latest .

# 运行容器
docker run -d \
  --name openclaw-gateway \
  -p 18789:18789 \
  -v /data/openclaw:/data/openclaw \
  -v /etc/openclaw:/etc/openclaw \
  -e OPENAI_API_KEY="sk-xxx" \
  openclaw:latest

# 查看日志
docker logs -f openclaw-gateway

# 查看状态
docker ps | grep openclaw

💡 这个基础版本适合快速验证。但生产环境还需要考虑镜像体积、安全性、多阶段构建等问题。

3.2 多阶段构建优化

# ============================================
# OpenClaw Dockerfile - 多阶段构建(生产级)
# 优化点:减小镜像体积、分离构建和运行环境
# ============================================

# ===== 阶段1:构建阶段 =====
FROM node:20-alpine AS builder

WORKDIR /build

# 安装构建工具
RUN apk add --no-cache python3 py3-pip git make g++

# 安装 OpenClaw(含编译依赖)
RUN npm install -g openclaw@latest

# 安装 Python 依赖
RUN pip3 install --no-cache-dir \
    requests \
    aiohttp \
    websockets

# ===== 阶段2:运行阶段 =====
FROM node:20-alpine AS runner

# 安装运行时依赖(不含编译工具)
RUN apk add --no-cache \
    python3 \
    py3-pip \
    curl \
    tini \
    su-exec

# 创建非 root 用户
RUN addgroup -g 1000 openclaw && \
    adduser -u 1000 -G openclaw -s /bin/sh -D openclaw

# 从构建阶段复制 OpenClaw
COPY --from=builder /usr/local/lib/node_modules /usr/local/lib/node_modules
COPY --from=builder /usr/local/bin/openclaw /usr/local/bin/openclaw

# 复制 Python 包
COPY --from=builder /usr/lib/python3* /usr/lib/python3*
COPY --from=builder /usr/local/lib/python3* /usr/local/lib/python3*

# 创建工作目录
WORKDIR /app
RUN mkdir -p /data/openclaw /etc/openclaw /app/workspace && \
    chown -R openclaw:openclaw /data/openclaw /app/workspace

# 复制配置
COPY --chown=openclaw:openclaw openclaw.yaml /etc/openclaw/openclaw.yaml

# 切换到非 root 用户
USER openclaw

# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
    CMD curl -sf http://localhost:18789/health || exit 1

# 暴露端口
EXPOSE 18789

# 使用 tini 作为 init 进程(处理僵尸进程和信号转发)
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["openclaw", "gateway", "start"]

多阶段构建的优势

指标基础版本多阶段版本优化幅度镜像大小~800MB~350MB-56%构建时间120s90s-25%安全root 运行非 root 用户更安全攻击面含编译工具仅运行时更小

3.3 环境变量注入策略

# openclaw.yaml - 使用环境变量占位符
gateway:
  port: ${GATEWAY_PORT:-18789}
  auth_token: ${GATEWAY_AUTH_TOKEN}

model:
  default: ${DEFAULT_MODEL:-gpt-4o-mini}
  providers:
    openai:
      api_key: ${OPENAI_API_KEY}
      base_url: ${OPENAI_BASE_URL:-https://api.openai.com/v1}

channels:
  feishu:
    app_id: ${FEISHU_APP_ID}
    app_secret: ${FEISHU_APP_SECRET}
  telegram:
    bot_token: ${TELEGRAM_BOT_TOKEN}

logging:
  level: ${LOG_LEVEL:-info}
  file: /data/openclaw/logs/gateway.log

# 使用 env 文件启动
docker run -d \
  --name openclaw-prod \
  --env-file .env.production \
  -p 18789:18789 \
  -v openclaw-data:/data/openclaw \
  openclaw:latest

# .env.production 示例
GATEWAY_PORT=18789
GATEWAY_AUTH_TOKEN=your-secure-token-here
DEFAULT_MODEL=gpt-4o
OPENAI_API_KEY=sk-prod-xxx
FEISHU_APP_ID=cli_xxx
FEISHU_APP_SECRET=xxx
TELEGRAM_BOT_TOKEN=123:abc
LOG_LEVEL=warn


4. docker-compose 多服务编排

4.1 完整编排文件

# docker-compose.yml
# OpenClaw 生产环境多服务编排

version: "3.8"

services:
  # ===== OpenClaw Gateway =====
  gateway:
    build:
      context: .
      dockerfile: Dockerfile
    image: openclaw:latest
    container_name: openclaw-gateway
    restart: unless-stopped

    ports:
      - "${GATEWAY_PORT:-18789}:18789"

    volumes:
      # 数据持久化
      - openclaw_data:/data/openclaw
      # 配置文件
      - ./config/openclaw.yaml:/etc/openclaw/openclaw.yaml:ro
      # 工作空间(Skills、插件等)
      - ./workspace:/app/workspace
      # 日志目录
      - openclaw_logs:/data/openclaw/logs

    env_file:
      - .env.production

    environment:
      - NODE_ENV=production
      - TZ=Asia/Shanghai

    healthcheck:
      test: ["CMD", "curl", "-sf", "http://localhost:18789/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 20s

    networks:
      - openclaw-net

    # 资源限制
    deploy:
      resources:
        limits:
          cpus: "2"
          memory: "2G"
        reservations:
          cpus: "0.5"
          memory: "512M"

    logging:
      driver: "json-file"
      options:
        max-size: "50m"
        max-file: "5"

  # ===== Redis(可选:会话缓存) =====
  redis:
    image: redis:7-alpine
    container_name: openclaw-redis
    restart: unless-stopped

    volumes:
      - redis_data:/data

    command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru

    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 3

    networks:
      - openclaw-net

    deploy:
      resources:
        limits:
          cpus: "0.5"
          memory: "512M"

  # ===== Nginx(可选:反向代理) =====
  nginx:
    image: nginx:alpine
    container_name: openclaw-nginx
    restart: unless-stopped

    ports:
      - "80:80"
      - "443:443"

    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro

    depends_on:
      gateway:
        condition: service_healthy

    networks:
      - openclaw-net

    deploy:
      resources:
        limits:
          cpus: "0.5"
          memory: "256M"

volumes:
  openclaw_data:
    driver: local
  openclaw_logs:
    driver: local
  redis_data:
    driver: local

networks:
  openclaw-net:
    driver: bridge

4.2 Nginx 反向代理配置

# nginx/nginx.conf
upstream openclaw_gateway {
    server gateway:18789;
    keepalive 32;
}

server {
    listen 80;
    server_name your-domain.com;

    # 强制 HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name your-domain.com;

    ssl_certificate     /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    # 请求体大小限制
    client_max_body_size 50m;

    # WebSocket 支持
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # 超时配置
    proxy_connect_timeout 60s;
    proxy_send_timeout 120s;
    proxy_read_timeout 120s;

    location / {
        proxy_pass http://openclaw_gateway;
    }

    # 健康检查端点
    location /health {
        proxy_pass http://openclaw_gateway/health;
        access_log off;
    }
}

4.3 启动与运维命令

# 启动所有服务
docker-compose up -d

# 查看服务状态
docker-compose ps

# 查看 Gateway 日志
docker-compose logs -f gateway

# 重启 Gateway(不重启 Redis/Nginx)
docker-compose restart gateway

# 更新镜像并重新部署
docker-compose pull gateway
docker-compose up -d --no-deps gateway

# 停止所有服务
docker-compose down

# 停止并删除数据卷(⚠️ 危险操作)
docker-compose down -v


5. 实战:从零容器化你的 OpenClaw

5.1 完整项目结构

openclaw-docker/
├── Dockerfile                  # 镜像构建文件
├── docker-compose.yml          # 多服务编排
├── .env.production             # 生产环境变量
├── .dockerignore               # 构建排除文件
├── config/
│   └── openclaw.yaml           # Gateway 配置
├── workspace/                  # Skills、插件等
│   └── skills/
├── nginx/
│   ├── nginx.conf              # 反向代理配置
│   └── ssl/                    # SSL 证书
└── scripts/
    ├── deploy.sh               # 部署脚本
    └── backup.sh               # 备份脚本

5.2 部署脚本

#!/bin/bash
# scripts/deploy.sh
# OpenClaw Docker 一键部署脚本

set -e

echo "🚀 开始部署 OpenClaw..."

# 1. 检查 Docker 环境
if ! command -v docker &> /dev/null; then
    echo "❌ Docker 未安装,请先安装 Docker"
    exit 1
fi

if ! command -v docker-compose &> /dev/null; then
    echo "❌ docker-compose 未安装"
    exit 1
fi

# 2. 检查环境变量文件
if [ ! -f .env.production ]; then
    echo "❌ .env.production 文件不存在"
    echo "💡 请从 .env.example 复制并填写配置"
    exit 1
fi

# 3. 创建必要目录
mkdir -p workspace/skills nginx/ssl data/backups

# 4. 备份当前运行版本(如果存在)
if docker ps | grep -q openclaw-gateway; then
    echo "📦 备份当前版本..."
    docker commit openclaw-gateway openclaw:backup-$(date +%Y%m%d-%H%M%S)
fi

# 5. 拉取最新镜像并构建
echo "🔨 构建镜像..."
docker-compose build --pull gateway

# 6. 启动服务
echo "▶️ 启动服务..."
docker-compose up -d

# 7. 等待健康检查通过
echo "⏳ 等待服务就绪..."
for i in $(seq 1 30); do
    if curl -sf http://localhost:18789/health > /dev/null 2>&1; then
        echo "✅ OpenClaw Gateway 已就绪"
        break
    fi
    sleep 2
done

# 8. 显示状态
echo ""
echo "📊 服务状态:"
docker-compose ps

echo ""
echo "✅ 部署完成!"
echo "   Gateway: http://localhost:18789"
echo "   日志: docker-compose logs -f gateway"

5.3 备份脚本

#!/bin/bash
# scripts/backup.sh
# OpenClaw 数据备份脚本

BACKUP_DIR="./data/backups"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/openclaw-backup-${TIMESTAMP}.tar.gz"

mkdir -p "$BACKUP_DIR"

echo "📦 备份 OpenClaw 数据..."

# 备份数据卷
docker run --rm \
    -v openclaw_data:/data:ro \
    -v "$(pwd)/${BACKUP_DIR}":/backup \
    alpine tar czf "/backup/openclaw-data-${TIMESTAMP}.tar.gz" -C /data .

# 备份配置文件
tar czf "${BACKUP_DIR}/openclaw-config-${TIMESTAMP}.tar.gz" \
    config/ .env.production docker-compose.yml

# 清理 7 天前的备份
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +7 -delete

echo "✅ 备份完成: ${BACKUP_FILE}"
echo "   保留最近 7 天的备份"


6. 常用问题与排错

6.1 问题排查表

症状可能原因排查命令容器启动后立即退出配置文件错误docker logs openclaw-gateway端口无法访问端口映射未生效docker port openclaw-gateway健康检查失败服务未就绪docker exec openclaw-gateway curl localhost:18789/health数据丢失未挂载数据卷docker inspect openclaw-gateway | grep Mounts -A 10内存溢出资源限制过低docker stats openclaw-gateway权限错误文件 owner 不匹配docker exec openclaw-gateway ls -la /data/openclaw

6.2 进入容器调试

# 进入容器 Shell
docker exec -it openclaw-gateway sh

# 查看进程
docker exec openclaw-gateway ps aux

# 查看资源使用
docker stats openclaw-gateway --no-stream

# 查看容器详细信息
docker inspect openclaw-gateway


7. 总结

本文从零开始,完整走通了 OpenClaw 的 Docker 容器化部署全流程:

核心要点

1. 多阶段构建:分离构建和运行环境,镜像体积减少 56%,攻击面更小
2. 环境变量注入:所有敏感配置通过 .env 文件注入,不硬编码在配置文件中
3. docker-compose 编排:Gateway + Redis + Nginx 三服务协同,一键启动
4. 健康检查HEALTHCHECK 指令确保服务可用,配合 depends_on 控制启动顺序
5. 数据持久化:通过命名卷(named volume)持久化数据,容器删除数据不丢
6. 一键部署脚本deploy.sh 自动化检查、备份、构建、启动全流程

思考题

1. 你的 OpenClaw 需要支持 1000 个并发用户。单容器实例可能不够。你会如何设计多实例的负载均衡方案?
2. Docker 容器的日志默认输出到 stdout/stderr。如果日志量很大(每天 10GB),你会如何设计日志收集和轮转策略?
3. 你的 .env.production 包含了 API Key 等敏感信息。在团队协作中,如何安全地管理这些密钥(既要能分享给团队成员,又不能泄露到代码仓库)?


参考资料


今天的内容大概就这些,实际开发中大家还会遇到更多细节,欢迎留言分享自己的经验。

评论 (0)

暂无评论