Add Docker Compose quickstart

This commit is contained in:
2026-06-15 14:34:17 +08:00
parent d884fdda0a
commit d4ef996f49
6 changed files with 292 additions and 36 deletions
+2 -1
View File
@@ -49,9 +49,10 @@ WORKDIR /app
COPY --from=builder /gochat /app/gochat
COPY --from=builder /gochat-worker /app/gochat-worker
COPY configs/ /app/configs/
COPY migrations/ /app/migrations/
# Set ownership to non-root user
RUN chown -R gochat:gochat /app
RUN mkdir -p /app/storage/uploads && chown -R gochat:gochat /app
# Switch to non-root user for security
USER gochat
+9 -5
View File
@@ -79,13 +79,17 @@ go test -v ./tests/e2e/...
### Docker 部署
```bash
# 构建镜像
docker build -t gochat/gochat:latest .
# 本地/UAT 快速启动:GoChat + PostgreSQL/pgvector + Redis + Meilisearch + Mailhog
cd deploy/quickstart
cp .env.example .env
docker compose up -d --build
# 使用 docker-compose
docker compose up -d
# 可选:初始化演示账号和业务数据
docker compose --profile seed run --rm seed
```
详见 [deploy/quickstart/README.md](deploy/quickstart/README.md)。
## 环境配置
GoChat 使用 **Viper 多环境叠加**机制:
@@ -188,4 +192,4 @@ GitHub Actions 5阶段流水线:
## License
MIT
MIT
+35
View File
@@ -0,0 +1,35 @@
# GoChat Docker Compose quickstart env
# Copy to .env and change secrets before sharing the stack.
COMPOSE_PROJECT_NAME=gochat-quickstart
# Published ports on the host
GOCHAT_PORT=3000
MEILI_PORT=7700
MAILHOG_SMTP_PORT=1025
MAILHOG_WEB_PORT=8025
# Database
POSTGRES_DB=gochat_dev
POSTGRES_USER=gochat
POSTGRES_PASSWORD=gochat_dev
# Redis
REDIS_PASSWORD=
# GoChat runtime
GOCHAT_ENV=development
GOCHAT_SERVER_MODE=debug
GOCHAT_JWT_SECRET=gochat_quickstart_change_me_minimum_32_chars
GOCHAT_CAPTAIN_ENABLED=false
# Search
MEILI_MASTER_KEY=gochat_dev
GOCHAT_SEARCH_API_KEY=gochat_dev
# Optional deterministic seed user
GOCHAT_SEED_ADMIN_EMAIL=admin@gochat.local
GOCHAT_SEED_ADMIN_PASSWORD=changeme
GOCHAT_SEED_ADMIN_NAME=Super Admin
GOCHAT_SEED_ACCOUNT_NAME=Quickstart Account
GOCHAT_SEED_INBOX_NAME=Quickstart Website Inbox
+71
View File
@@ -0,0 +1,71 @@
# GoChat Docker Compose Quickstart
This directory starts a local GoChat stack for manual business validation:
- GoChat API on `http://127.0.0.1:3000`
- PostgreSQL + pgvector
- Redis
- Meilisearch
- Mailhog SMTP/Web UI
- Optional deterministic seed data
It is intended for local/UAT quickstart, not hardened production deployment.
## Prerequisites
- Docker Engine with Compose v2 (`docker compose version`)
- Free local ports: `3000`, `5432`, `6379`, `7700`, `1025`, `8025`
If those ports conflict, edit `.env` after copying `.env.example`.
## Start
```bash
cd deploy/quickstart
cp .env.example .env
docker compose up -d --build
```
Wait until GoChat is healthy:
```bash
docker compose ps
docker compose logs -f gochat
curl -fsS http://127.0.0.1:3000/health
```
## Seed Demo Data
```bash
docker compose --profile seed run --rm seed
```
Default login after seeding:
- Email: `admin@gochat.local`
- Password: `changeme`
Change these values in `.env` before running the seed command if needed.
## Useful Commands
```bash
# Follow all logs
docker compose logs -f
# Restart GoChat only
docker compose restart gochat
# Stop without deleting data
docker compose down
# Reset all local data
docker compose down -v
```
## Notes
- GoChat runs migrations automatically on startup with `GOCHAT_DATABASE_RUN_MIGRATIONS=true`.
- The production image includes `/app/migrations`; GoChat runs them automatically on startup in this quickstart stack.
- Meilisearch uses the quickstart key from `.env`; change it before sharing this stack.
- Mailhog Web UI is available at `http://127.0.0.1:8025`.
+140
View File
@@ -0,0 +1,140 @@
name: gochat-quickstart
services:
postgres:
image: pgvector/pgvector:pg16
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB:-gochat_dev}
POSTGRES_USER: ${POSTGRES_USER:-gochat}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-gochat_dev}
ports:
- "127.0.0.1:${POSTGRES_PORT:-5432}:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 20
redis:
image: redis:7-alpine
restart: unless-stopped
command: >-
sh -c 'if [ -n "$${REDIS_PASSWORD}" ]; then
exec redis-server --appendonly yes --requirepass "$${REDIS_PASSWORD}";
else
exec redis-server --appendonly yes;
fi'
environment:
REDIS_PASSWORD: ${REDIS_PASSWORD:-}
ports:
- "127.0.0.1:${REDIS_PORT:-6379}:6379"
volumes:
- redis-data:/data
healthcheck:
test: ["CMD-SHELL", "if [ -n \"$${REDIS_PASSWORD}\" ]; then redis-cli -a \"$${REDIS_PASSWORD}\" ping; else redis-cli ping; fi"]
interval: 5s
timeout: 5s
retries: 20
meilisearch:
image: getmeili/meilisearch:v1.13
restart: unless-stopped
environment:
MEILI_ENV: development
MEILI_MASTER_KEY: ${MEILI_MASTER_KEY:-gochat_dev}
MEILI_NO_ANALYTICS: "true"
ports:
- "127.0.0.1:${MEILI_PORT:-7700}:7700"
volumes:
- meili-data:/meili_data
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--spider", "http://127.0.0.1:7700/health"]
interval: 5s
timeout: 5s
retries: 30
mailhog:
image: mailhog/mailhog:v1.0.1
restart: unless-stopped
ports:
- "127.0.0.1:${MAILHOG_SMTP_PORT:-1025}:1025"
- "127.0.0.1:${MAILHOG_WEB_PORT:-8025}:8025"
gochat:
build:
context: ../..
dockerfile: Dockerfile
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
meilisearch:
condition: service_healthy
environment: &gochat-env
GOCHAT_ENV: ${GOCHAT_ENV:-development}
GOCHAT_SERVER_HOST: 0.0.0.0
GOCHAT_SERVER_PORT: 3000
GOCHAT_SERVER_MODE: ${GOCHAT_SERVER_MODE:-debug}
GOCHAT_DATABASE_HOST: postgres
GOCHAT_DATABASE_PORT: 5432
GOCHAT_DATABASE_USER: ${POSTGRES_USER:-gochat}
GOCHAT_DATABASE_PASSWORD: ${POSTGRES_PASSWORD:-gochat_dev}
GOCHAT_DATABASE_DBNAME: ${POSTGRES_DB:-gochat_dev}
GOCHAT_DATABASE_SSLMODE: disable
GOCHAT_DATABASE_RUN_MIGRATIONS: "true"
GOCHAT_DATABASE_MIGRATIONS_PATH: /app/migrations
GOCHAT_REDIS_HOST: redis
GOCHAT_REDIS_PORT: 6379
GOCHAT_REDIS_PASSWORD: ${REDIS_PASSWORD:-}
GOCHAT_REDIS_POOL_SIZE: 50
GOCHAT_SEARCH_ENGINE: meilisearch
GOCHAT_SEARCH_HOST: http://meilisearch:7700
GOCHAT_SEARCH_API_KEY: ${GOCHAT_SEARCH_API_KEY:-gochat_dev}
GOCHAT_JWT_SECRET: ${GOCHAT_JWT_SECRET:-gochat_quickstart_change_me_minimum_32_chars}
GOCHAT_LOG_LEVEL: info
GOCHAT_LOG_FORMAT: json
GOCHAT_CAPTAIN_ENABLED: ${GOCHAT_CAPTAIN_ENABLED:-false}
GOCHAT_STORAGE_PROVIDER: local
GOCHAT_STORAGE_LOCAL_PATH: /app/storage/uploads
SMTP_HOST: mailhog
SMTP_PORT: 1025
ports:
- "127.0.0.1:${GOCHAT_PORT:-3000}:3000"
volumes:
- gochat-storage:/app/storage
healthcheck:
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:3000/health"]
interval: 10s
timeout: 5s
retries: 30
seed:
build:
context: ../..
dockerfile: Dockerfile
profiles: ["seed"]
depends_on:
gochat:
condition: service_healthy
environment:
<<: *gochat-env
GOCHAT_SEED_ADMIN_EMAIL: ${GOCHAT_SEED_ADMIN_EMAIL:-admin@gochat.local}
GOCHAT_SEED_ADMIN_PASSWORD: ${GOCHAT_SEED_ADMIN_PASSWORD:-changeme}
GOCHAT_SEED_ADMIN_NAME: ${GOCHAT_SEED_ADMIN_NAME:-Super Admin}
GOCHAT_SEED_ACCOUNT_NAME: ${GOCHAT_SEED_ACCOUNT_NAME:-Quickstart Account}
GOCHAT_SEED_INBOX_NAME: ${GOCHAT_SEED_INBOX_NAME:-Quickstart Website Inbox}
volumes:
- gochat-storage:/app/storage
command: ["seed"]
restart: "no"
volumes:
postgres-data:
redis-data:
meili-data:
gochat-storage:
+35 -30
View File
@@ -618,36 +618,41 @@ func LoadWithEnv(env string) (*Config, error) {
// Bind specific env keys that viper can't auto-infer for nested structs
// These are common overrides that users set via environment variables
envBindings := map[string]string{
"GOCHAT_SERVER_HOST": "server.host",
"GOCHAT_SERVER_PORT": "server.port",
"GOCHAT_SERVER_MODE": "server.mode",
"GOCHAT_DATABASE_HOST": "database.host",
"GOCHAT_DATABASE_PORT": "database.port",
"GOCHAT_DATABASE_USER": "database.user",
"GOCHAT_DATABASE_PASSWORD": "database.password",
"GOCHAT_DATABASE_NAME": "database.name",
"GOCHAT_DATABASE_DBNAME": "database.dbname",
"GOCHAT_DATABASE_SSLMODE": "database.sslmode",
"GOCHAT_REDIS_URL": "redis.url",
"GOCHAT_REDIS_HOST": "redis.host",
"GOCHAT_REDIS_PORT": "redis.port",
"GOCHAT_REDIS_PASSWORD": "redis.password",
"GOCHAT_REDIS_POOL_SIZE": "redis.pool_size",
"GOCHAT_JWT_SECRET": "jwt.secret",
"JWT_SECRET": "jwt.secret", // Alias for compatibility (no prefix)
"GOCHAT_JWT_EXPIRY_HOURS": "jwt.expiry_hours",
"GOCHAT_LOG_LEVEL": "log.level",
"GOCHAT_LOG_FORMAT": "log.format",
"GOCHAT_CAPTAIN_ENABLED": "captain.enabled",
"GOCHAT_CAPTAIN_LLM_PROVIDER": "captain.llm_provider",
"GOCHAT_CAPTAIN_LLM_MODEL": "captain.llm_model",
"GOCHAT_CAPTAIN_LLM_API_KEY": "captain.llm_api_key",
"GOCHAT_WORKER_CONCURRENCY": "worker.concurrency",
"GOCHAT_SEARCH_ENGINE": "search.engine",
"GOCHAT_SEARCH_HOST": "search.host",
"GOCHAT_SEARCH_API_KEY": "search.api_key",
"GOCHAT_SEARCH_INDEX_PREFIX": "search.index_prefix",
"GOCHAT_SEARCH_TIMEOUT_SECONDS": "search.timeout_seconds",
"GOCHAT_SERVER_HOST": "server.host",
"GOCHAT_SERVER_PORT": "server.port",
"GOCHAT_SERVER_MODE": "server.mode",
"GOCHAT_DATABASE_HOST": "database.host",
"GOCHAT_DATABASE_PORT": "database.port",
"GOCHAT_DATABASE_USER": "database.user",
"GOCHAT_DATABASE_PASSWORD": "database.password",
"GOCHAT_DATABASE_NAME": "database.name",
"GOCHAT_DATABASE_DBNAME": "database.dbname",
"GOCHAT_DATABASE_SSLMODE": "database.sslmode",
"GOCHAT_DATABASE_RUN_MIGRATIONS": "database.run_migrations",
"GOCHAT_DATABASE_MIGRATIONS_PATH": "database.migrations_path",
"GOCHAT_REDIS_URL": "redis.url",
"GOCHAT_REDIS_HOST": "redis.host",
"GOCHAT_REDIS_PORT": "redis.port",
"GOCHAT_REDIS_PASSWORD": "redis.password",
"GOCHAT_REDIS_POOL_SIZE": "redis.pool_size",
"GOCHAT_JWT_SECRET": "jwt.secret",
"JWT_SECRET": "jwt.secret", // Alias for compatibility (no prefix)
"GOCHAT_JWT_EXPIRY_HOURS": "jwt.expiry_hours",
"GOCHAT_LOG_LEVEL": "log.level",
"GOCHAT_LOG_FORMAT": "log.format",
"GOCHAT_CAPTAIN_ENABLED": "captain.enabled",
"GOCHAT_CAPTAIN_LLM_PROVIDER": "captain.llm_provider",
"GOCHAT_CAPTAIN_LLM_MODEL": "captain.llm_model",
"GOCHAT_CAPTAIN_LLM_API_KEY": "captain.llm_api_key",
"GOCHAT_WORKER_CONCURRENCY": "worker.concurrency",
"GOCHAT_SEARCH_ENGINE": "search.engine",
"GOCHAT_SEARCH_HOST": "search.host",
"GOCHAT_SEARCH_API_KEY": "search.api_key",
"GOCHAT_SEARCH_INDEX_PREFIX": "search.index_prefix",
"GOCHAT_SEARCH_TIMEOUT_SECONDS": "search.timeout_seconds",
"GOCHAT_STORAGE_PROVIDER": "storage.provider",
"GOCHAT_STORAGE_LOCAL_PATH": "storage.local_path",
"GOCHAT_STORAGE_MAX_FILE_SIZE": "storage.max_file_size",
// G10: OAuth config for new channel integrations (Twitter, Microsoft, Google)
"GOCHAT_OAUTH_TWITTER_CLIENT_ID": "oauth.twitter.client_id",
"GOCHAT_OAUTH_TWITTER_CLIENT_SECRET": "oauth.twitter.client_secret",