Add Docker Compose quickstart
This commit is contained in:
+2
-1
@@ -49,9 +49,10 @@ WORKDIR /app
|
|||||||
COPY --from=builder /gochat /app/gochat
|
COPY --from=builder /gochat /app/gochat
|
||||||
COPY --from=builder /gochat-worker /app/gochat-worker
|
COPY --from=builder /gochat-worker /app/gochat-worker
|
||||||
COPY configs/ /app/configs/
|
COPY configs/ /app/configs/
|
||||||
|
COPY migrations/ /app/migrations/
|
||||||
|
|
||||||
# Set ownership to non-root user
|
# 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
|
# Switch to non-root user for security
|
||||||
USER gochat
|
USER gochat
|
||||||
|
|||||||
@@ -79,13 +79,17 @@ go test -v ./tests/e2e/...
|
|||||||
### Docker 部署
|
### Docker 部署
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 构建镜像
|
# 本地/UAT 快速启动:GoChat + PostgreSQL/pgvector + Redis + Meilisearch + Mailhog
|
||||||
docker build -t gochat/gochat:latest .
|
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 多环境叠加**机制:
|
GoChat 使用 **Viper 多环境叠加**机制:
|
||||||
@@ -188,4 +192,4 @@ GitHub Actions 5阶段流水线:
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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`.
|
||||||
@@ -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
@@ -618,36 +618,41 @@ func LoadWithEnv(env string) (*Config, error) {
|
|||||||
// Bind specific env keys that viper can't auto-infer for nested structs
|
// Bind specific env keys that viper can't auto-infer for nested structs
|
||||||
// These are common overrides that users set via environment variables
|
// These are common overrides that users set via environment variables
|
||||||
envBindings := map[string]string{
|
envBindings := map[string]string{
|
||||||
"GOCHAT_SERVER_HOST": "server.host",
|
"GOCHAT_SERVER_HOST": "server.host",
|
||||||
"GOCHAT_SERVER_PORT": "server.port",
|
"GOCHAT_SERVER_PORT": "server.port",
|
||||||
"GOCHAT_SERVER_MODE": "server.mode",
|
"GOCHAT_SERVER_MODE": "server.mode",
|
||||||
"GOCHAT_DATABASE_HOST": "database.host",
|
"GOCHAT_DATABASE_HOST": "database.host",
|
||||||
"GOCHAT_DATABASE_PORT": "database.port",
|
"GOCHAT_DATABASE_PORT": "database.port",
|
||||||
"GOCHAT_DATABASE_USER": "database.user",
|
"GOCHAT_DATABASE_USER": "database.user",
|
||||||
"GOCHAT_DATABASE_PASSWORD": "database.password",
|
"GOCHAT_DATABASE_PASSWORD": "database.password",
|
||||||
"GOCHAT_DATABASE_NAME": "database.name",
|
"GOCHAT_DATABASE_NAME": "database.name",
|
||||||
"GOCHAT_DATABASE_DBNAME": "database.dbname",
|
"GOCHAT_DATABASE_DBNAME": "database.dbname",
|
||||||
"GOCHAT_DATABASE_SSLMODE": "database.sslmode",
|
"GOCHAT_DATABASE_SSLMODE": "database.sslmode",
|
||||||
"GOCHAT_REDIS_URL": "redis.url",
|
"GOCHAT_DATABASE_RUN_MIGRATIONS": "database.run_migrations",
|
||||||
"GOCHAT_REDIS_HOST": "redis.host",
|
"GOCHAT_DATABASE_MIGRATIONS_PATH": "database.migrations_path",
|
||||||
"GOCHAT_REDIS_PORT": "redis.port",
|
"GOCHAT_REDIS_URL": "redis.url",
|
||||||
"GOCHAT_REDIS_PASSWORD": "redis.password",
|
"GOCHAT_REDIS_HOST": "redis.host",
|
||||||
"GOCHAT_REDIS_POOL_SIZE": "redis.pool_size",
|
"GOCHAT_REDIS_PORT": "redis.port",
|
||||||
"GOCHAT_JWT_SECRET": "jwt.secret",
|
"GOCHAT_REDIS_PASSWORD": "redis.password",
|
||||||
"JWT_SECRET": "jwt.secret", // Alias for compatibility (no prefix)
|
"GOCHAT_REDIS_POOL_SIZE": "redis.pool_size",
|
||||||
"GOCHAT_JWT_EXPIRY_HOURS": "jwt.expiry_hours",
|
"GOCHAT_JWT_SECRET": "jwt.secret",
|
||||||
"GOCHAT_LOG_LEVEL": "log.level",
|
"JWT_SECRET": "jwt.secret", // Alias for compatibility (no prefix)
|
||||||
"GOCHAT_LOG_FORMAT": "log.format",
|
"GOCHAT_JWT_EXPIRY_HOURS": "jwt.expiry_hours",
|
||||||
"GOCHAT_CAPTAIN_ENABLED": "captain.enabled",
|
"GOCHAT_LOG_LEVEL": "log.level",
|
||||||
"GOCHAT_CAPTAIN_LLM_PROVIDER": "captain.llm_provider",
|
"GOCHAT_LOG_FORMAT": "log.format",
|
||||||
"GOCHAT_CAPTAIN_LLM_MODEL": "captain.llm_model",
|
"GOCHAT_CAPTAIN_ENABLED": "captain.enabled",
|
||||||
"GOCHAT_CAPTAIN_LLM_API_KEY": "captain.llm_api_key",
|
"GOCHAT_CAPTAIN_LLM_PROVIDER": "captain.llm_provider",
|
||||||
"GOCHAT_WORKER_CONCURRENCY": "worker.concurrency",
|
"GOCHAT_CAPTAIN_LLM_MODEL": "captain.llm_model",
|
||||||
"GOCHAT_SEARCH_ENGINE": "search.engine",
|
"GOCHAT_CAPTAIN_LLM_API_KEY": "captain.llm_api_key",
|
||||||
"GOCHAT_SEARCH_HOST": "search.host",
|
"GOCHAT_WORKER_CONCURRENCY": "worker.concurrency",
|
||||||
"GOCHAT_SEARCH_API_KEY": "search.api_key",
|
"GOCHAT_SEARCH_ENGINE": "search.engine",
|
||||||
"GOCHAT_SEARCH_INDEX_PREFIX": "search.index_prefix",
|
"GOCHAT_SEARCH_HOST": "search.host",
|
||||||
"GOCHAT_SEARCH_TIMEOUT_SECONDS": "search.timeout_seconds",
|
"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)
|
// G10: OAuth config for new channel integrations (Twitter, Microsoft, Google)
|
||||||
"GOCHAT_OAUTH_TWITTER_CLIENT_ID": "oauth.twitter.client_id",
|
"GOCHAT_OAUTH_TWITTER_CLIENT_ID": "oauth.twitter.client_id",
|
||||||
"GOCHAT_OAUTH_TWITTER_CLIENT_SECRET": "oauth.twitter.client_secret",
|
"GOCHAT_OAUTH_TWITTER_CLIENT_SECRET": "oauth.twitter.client_secret",
|
||||||
|
|||||||
Reference in New Issue
Block a user