Files
goclaw/scripts/setup-docker.sh
T
Goon 9429a7c844 ci: publish Docker images to GHCR and Docker Hub (#237)
* feat(ci): add node/python/full runtime variants to Docker publish

Add runtime image variants alongside existing build-tag variants:
- :node (pre-installed Node.js)
- :python (pre-installed Python)
- :full (Node.js + Python + all skill deps)

* feat(ci): add install scripts, release binaries, and Discord notifications

- scripts/install.sh: one-liner binary installer from GitHub Releases
- scripts/setup-docker.sh: interactive Docker setup with variant selection
  (alpine/node/python/full), auto-generates .env + docker-compose.yaml
  with persistent volumes for data, skills, workspace, storage
- release.yaml: build cross-platform binaries (linux/darwin × amd64/arm64)
  and attach to GitHub Release, notify Discord on new releases
- .gitignore: ignore Apple Double (._*) files from external volumes

* docs(docker): add pre-built image references and update docker-compose workflows

- Add `image:` directives to docker-compose.yml, docker-compose.selfservice.yml, and docker-compose.upgrade.yml pointing to ghcr.io/nextlevelbuilder/goclaw pre-built images
- Add Docker Hub mirror references (digitop/goclaw) for public access
- Document available image tags (latest, node, python, full, otel, tsnet, redis) with descriptions
- Update README with pre-built image pull instructions and semver tag examples
- Clarify deployment workflows: use pre-built images by default (no --build), add --build only when building from source
- Update upgrade workflow to pull pre-built images instead of rebuild
- Add note about build args requirement for otel/tsnet/redis overlays
- Update .dockerignore to exclude macOS temp files (._*)

* fix(ci): use claude_code_oauth_token instead of anthropic_api_key
2026-03-17 12:44:18 +07:00

255 lines
7.3 KiB
Bash

#!/usr/bin/env bash
# GoClaw Docker setup — generates .env and docker-compose command for your chosen variant.
#
# Usage:
# ./scripts/setup-docker.sh # Interactive mode
# ./scripts/setup-docker.sh --variant full --with-ui
# ./scripts/setup-docker.sh --variant alpine --dev
#
# Variants:
# alpine — Base image (~50 MB), no runtimes
# node — Alpine + Node.js pre-installed
# python — Alpine + Python pre-installed
# full — Alpine + Node.js + Python + all skill dependencies
#
# Flags:
# --dev Mount local source for development (live reload)
# --with-ui Include web dashboard
# --port N Gateway port (default: 18790)
# --ui-port N Dashboard port (default: 3000)
# --pg-port N PostgreSQL port (default: 5432)
set -euo pipefail
# ── Defaults ──
VARIANT=""
DEV_MODE=false
WITH_UI=false
PORT="${GOCLAW_PORT:-18790}"
UI_PORT="${GOCLAW_UI_PORT:-3000}"
PG_PORT="${POSTGRES_PORT:-5432}"
DATA_DIR="${GOCLAW_DATA_DIR:-./goclaw-data}"
# ── Parse args ──
while [[ $# -gt 0 ]]; do
case "$1" in
--variant) VARIANT="$2"; shift 2 ;;
--dev) DEV_MODE=true; shift ;;
--with-ui) WITH_UI=true; shift ;;
--port) PORT="$2"; shift 2 ;;
--ui-port) UI_PORT="$2"; shift 2 ;;
--pg-port) PG_PORT="$2"; shift 2 ;;
--data-dir) DATA_DIR="$2"; shift 2 ;;
--help|-h)
head -20 "$0" | grep '^#' | sed 's/^# \?//'
exit 0
;;
*) echo "Unknown option: $1"; exit 1 ;;
esac
done
# ── Interactive variant selection ──
if [ -z "$VARIANT" ]; then
echo "Select GoClaw Docker variant:"
echo ""
echo " 1) alpine — Base image (~50 MB), no runtimes"
echo " 2) node — + Node.js (for JS/TS skills)"
echo " 3) python — + Python (for Python skills)"
echo " 4) full — + Node.js + Python + all skill deps"
echo ""
read -rp "Choice [1-4, default=1]: " choice
case "${choice:-1}" in
1|alpine) VARIANT="alpine" ;;
2|node) VARIANT="node" ;;
3|python) VARIANT="python" ;;
4|full) VARIANT="full" ;;
*) echo "Invalid choice"; exit 1 ;;
esac
fi
# ── Resolve Docker image tag ──
DOCKER_IMAGE="digitop/goclaw"
case "$VARIANT" in
alpine) IMAGE_TAG="latest" ;;
node) IMAGE_TAG="node" ;;
python) IMAGE_TAG="python" ;;
full) IMAGE_TAG="full" ;;
*) echo "Unknown variant: $VARIANT"; exit 1 ;;
esac
echo ""
echo "Setting up GoClaw (${VARIANT})..."
# ── Create data directories ──
mkdir -p "${DATA_DIR}"/{config,data,workspace,skills,storage}
# ── Generate secrets if not present ──
ENV_FILE="${DATA_DIR}/.env"
if [ ! -f "$ENV_FILE" ]; then
GATEWAY_TOKEN="$(openssl rand -hex 32 2>/dev/null || head -c 64 /dev/urandom | od -An -tx1 | tr -d ' \n')"
ENCRYPTION_KEY="$(openssl rand -hex 16 2>/dev/null || head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n')"
PG_PASSWORD="$(openssl rand -hex 12 2>/dev/null || head -c 24 /dev/urandom | od -An -tx1 | tr -d ' \n')"
cat > "$ENV_FILE" <<EOF
# GoClaw environment — generated by setup-docker.sh
# Variant: ${VARIANT}
# Gateway
GOCLAW_GATEWAY_TOKEN=${GATEWAY_TOKEN}
GOCLAW_ENCRYPTION_KEY=${ENCRYPTION_KEY}
# Ports
GOCLAW_PORT=${PORT}
GOCLAW_UI_PORT=${UI_PORT}
POSTGRES_PORT=${PG_PORT}
# PostgreSQL
POSTGRES_USER=goclaw
POSTGRES_PASSWORD=${PG_PASSWORD}
POSTGRES_DB=goclaw
EOF
echo "Generated ${ENV_FILE} with random secrets."
else
echo "Using existing ${ENV_FILE}"
fi
# ── Generate docker-compose.yaml ──
COMPOSE_FILE="${DATA_DIR}/docker-compose.yaml"
cat > "$COMPOSE_FILE" <<YAML
# GoClaw Docker Compose — variant: ${VARIANT}
# Generated by setup-docker.sh. Edit as needed.
services:
postgres:
image: pgvector/pgvector:pg18
ports:
- "\${POSTGRES_PORT:-5432}:5432"
environment:
POSTGRES_USER: \${POSTGRES_USER:-goclaw}
POSTGRES_PASSWORD: \${POSTGRES_PASSWORD:-goclaw}
POSTGRES_DB: \${POSTGRES_DB:-goclaw}
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U \${POSTGRES_USER:-goclaw}"]
interval: 5s
timeout: 5s
retries: 10
restart: unless-stopped
goclaw:
YAML
# Dev mode: build from source; Production: use pre-built image
if [ "$DEV_MODE" = true ]; then
cat >> "$COMPOSE_FILE" <<YAML
build:
context: $(pwd)
dockerfile: Dockerfile
args:
ENABLE_PYTHON: "$([ "$VARIANT" = "python" ] || [ "$VARIANT" = "full" ] && echo true || echo false)"
ENABLE_NODE: "$([ "$VARIANT" = "node" ] || [ "$VARIANT" = "full" ] && echo true || echo false)"
ENABLE_FULL_SKILLS: "$([ "$VARIANT" = "full" ] && echo true || echo false)"
YAML
else
cat >> "$COMPOSE_FILE" <<YAML
image: ${DOCKER_IMAGE}:${IMAGE_TAG}
YAML
fi
cat >> "$COMPOSE_FILE" <<YAML
ports:
- "\${GOCLAW_PORT:-18790}:18790"
env_file:
- .env
environment:
- GOCLAW_HOST=0.0.0.0
- GOCLAW_PORT=18790
- GOCLAW_CONFIG=/app/data/config.json
- GOCLAW_SKILLS_DIR=/app/data/skills
- GOCLAW_WORKSPACE=/app/workspace
- GOCLAW_POSTGRES_DSN=postgres://\${POSTGRES_USER:-goclaw}:\${POSTGRES_PASSWORD:-goclaw}@postgres:5432/\${POSTGRES_DB:-goclaw}?sslmode=disable
volumes:
# Persistent data: config, agent files, runtime packages (pip/npm)
- goclaw-data:/app/data
# Workspace: agent working directory for file operations
- goclaw-workspace:/app/workspace
# Custom skills: user-installed skills persist across restarts
- goclaw-skills:/app/skills
# Storage: uploaded media, documents
- goclaw-storage:/app/storage
depends_on:
postgres:
condition: service_healthy
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
read_only: true
tmpfs:
- /tmp:rw,noexec,nosuid,size=256m
deploy:
resources:
limits:
memory: 1G
cpus: "2.0"
pids: 200
restart: unless-stopped
YAML
# Add web UI service if requested
if [ "$WITH_UI" = true ]; then
cat >> "$COMPOSE_FILE" <<YAML
goclaw-ui:
image: ${DOCKER_IMAGE}-web:latest
ports:
- "\${GOCLAW_UI_PORT:-3000}:80"
depends_on:
- goclaw
restart: unless-stopped
YAML
fi
cat >> "$COMPOSE_FILE" <<YAML
volumes:
postgres-data:
goclaw-data:
goclaw-workspace:
goclaw-skills:
goclaw-storage:
YAML
echo ""
echo "Generated ${COMPOSE_FILE}"
echo ""
echo "── Quick start ──"
echo ""
echo " cd ${DATA_DIR}"
echo " docker compose up -d"
echo ""
if [ "$WITH_UI" = true ]; then
echo " Gateway: http://localhost:${PORT}"
echo " Dashboard: http://localhost:${UI_PORT}"
else
echo " Gateway: http://localhost:${PORT}"
echo " Add --with-ui flag to include the web dashboard."
fi
echo ""
echo "── Volumes ──"
echo ""
echo " goclaw-data → /app/data Config, runtime packages (pip/npm cache)"
echo " goclaw-workspace → /app/workspace Agent file operations"
echo " goclaw-skills → /app/skills Custom installed skills"
echo " goclaw-storage → /app/storage Uploaded media & documents"
echo " postgres-data → PostgreSQL data"
echo ""
echo "── Useful commands ──"
echo ""
echo " docker compose logs -f goclaw # View logs"
echo " docker compose exec goclaw goclaw version # Check version"
echo " docker compose down # Stop"
echo " docker compose down -v # Stop + delete all data"