mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-08 22:48:14 -05:00
feat(ci): socket realtime image for hosting (#565)
* feat: socket server for self/local deployment * ci: memory limit and redundant dependency install * chore: update readme, devcontainer, cli package * chore: add new dev scripts and update README for full development setup
This commit is contained in:
@@ -38,4 +38,5 @@ WORKDIR /workspace
|
||||
|
||||
# Expose the ports we're interested in
|
||||
EXPOSE 3000
|
||||
EXPOSE 3001
|
||||
EXPOSE 3001
|
||||
EXPOSE 3002
|
||||
@@ -17,6 +17,8 @@ services:
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
realtime:
|
||||
condition: service_healthy
|
||||
migrations:
|
||||
condition: service_completed_successfully
|
||||
ports:
|
||||
@@ -30,6 +32,29 @@ services:
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
realtime:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: .devcontainer/Dockerfile
|
||||
command: sleep infinity
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- DATABASE_URL=postgresql://postgres:postgres@db:5432/simstudio
|
||||
- BETTER_AUTH_URL=http://localhost:3000
|
||||
- NEXT_PUBLIC_APP_URL=http://localhost:3000
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "3002:3002"
|
||||
working_dir: /workspace
|
||||
healthcheck:
|
||||
test: ['CMD', 'wget', '--spider', '--quiet', 'http://127.0.0.1:3002']
|
||||
interval: 90s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
migrations:
|
||||
build:
|
||||
context: ..
|
||||
|
||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -16,6 +16,8 @@ jobs:
|
||||
image: ghcr.io/simstudioai/simstudio
|
||||
- dockerfile: ./docker/db.Dockerfile
|
||||
image: ghcr.io/simstudioai/migrations
|
||||
- dockerfile: ./docker/realtime.Dockerfile
|
||||
image: ghcr.io/simstudioai/realtime
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
19
README.md
19
README.md
@@ -86,7 +86,7 @@ docker compose -f docker-compose.prod.yml up -d
|
||||
|
||||
1. Open VS Code with the [Remote - Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
|
||||
2. Open the project and click "Reopen in Container" when prompted
|
||||
3. Run `bun run dev` in the terminal or use the `sim-start` alias
|
||||
3. Run `bun run dev:full` in the terminal or use the `sim-start` alias
|
||||
|
||||
### Option 4: Manual Setup
|
||||
|
||||
@@ -111,12 +111,26 @@ cp .env.example .env # Configure with required variables (DATABASE_URL, BETTER_
|
||||
bunx drizzle-kit push
|
||||
```
|
||||
|
||||
4. Start the development server:
|
||||
4. Start the development servers:
|
||||
|
||||
Next.js app:
|
||||
|
||||
```bash
|
||||
bun run dev
|
||||
```
|
||||
|
||||
Start the realtime server:
|
||||
|
||||
```bash
|
||||
bun run dev:sockets
|
||||
```
|
||||
|
||||
Run both together (recommended):
|
||||
|
||||
```bash
|
||||
bun run dev:full
|
||||
```
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- **Framework**: [Next.js](https://nextjs.org/) (App Router)
|
||||
@@ -128,6 +142,7 @@ bun run dev
|
||||
- **Flow Editor**: [ReactFlow](https://reactflow.dev/)
|
||||
- **Docs**: [Fumadocs](https://fumadocs.vercel.app/)
|
||||
- **Monorepo**: [Turborepo](https://turborepo.org/)
|
||||
- **Realtime**: [Socket.io](https://socket.io/)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"dev": "next dev --turbo --port 3000",
|
||||
"dev:classic": "next dev",
|
||||
"dev:sockets": "bun run socket-server/index.ts",
|
||||
"dev:full": "concurrently \"bun run dev\" \"bun run dev:sockets\"",
|
||||
"dev:full": "concurrently -n \"NextJS,Realtime\" -c \"cyan,magenta\" \"bun run dev\" \"bun run dev:sockets\"",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"prepare": "cd ../.. && bun husky",
|
||||
|
||||
@@ -22,11 +22,14 @@ services:
|
||||
- GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET:-placeholder}
|
||||
- RESEND_API_KEY=${RESEND_API_KEY:-placeholder}
|
||||
- OLLAMA_URL=${OLLAMA_URL:-http://localhost:11434}
|
||||
- SOCKET_SERVER_URL=${SOCKET_SERVER_URL:-http://localhost:3002}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
migrations:
|
||||
condition: service_completed_successfully
|
||||
realtime:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ['CMD', 'wget', '--spider', '--quiet', 'http://127.0.0.1:3000']
|
||||
interval: 90s
|
||||
@@ -34,6 +37,32 @@ services:
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
realtime:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/realtime.Dockerfile
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-simstudio}
|
||||
- NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
|
||||
- BETTER_AUTH_URL=${BETTER_AUTH_URL:-http://localhost:3000}
|
||||
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:-your_auth_secret_here}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '3002:3002'
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 8G
|
||||
healthcheck:
|
||||
test: ['CMD', 'wget', '--spider', '--quiet', 'http://127.0.0.1:3002']
|
||||
interval: 90s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
migrations:
|
||||
build:
|
||||
context: .
|
||||
|
||||
@@ -21,11 +21,14 @@ services:
|
||||
- GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET:-placeholder}
|
||||
- RESEND_API_KEY=${RESEND_API_KEY:-placeholder}
|
||||
- OLLAMA_URL=${OLLAMA_URL:-http://localhost:11434}
|
||||
- SOCKET_SERVER_URL=${SOCKET_SERVER_URL:-http://localhost:3002}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
migrations:
|
||||
condition: service_completed_successfully
|
||||
realtime:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ['CMD', 'wget', '--spider', '--quiet', 'http://127.0.0.1:3000']
|
||||
interval: 90s
|
||||
@@ -33,6 +36,30 @@ services:
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
realtime:
|
||||
image: ghcr.io/simstudioai/realtime:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '3002:3002'
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 4G
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-simstudio}
|
||||
- NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
|
||||
- BETTER_AUTH_URL=${BETTER_AUTH_URL:-http://localhost:3000}
|
||||
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:-your_auth_secret_here}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ['CMD', 'wget', '--spider', '--quiet', 'http://127.0.0.1:3002']
|
||||
interval: 90s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
migrations:
|
||||
image: ghcr.io/simstudioai/migrations:latest
|
||||
environment:
|
||||
|
||||
51
docker/realtime.Dockerfile
Normal file
51
docker/realtime.Dockerfile
Normal file
@@ -0,0 +1,51 @@
|
||||
# ========================================
|
||||
# Base Stage: Alpine Linux with Bun
|
||||
# ========================================
|
||||
FROM oven/bun:alpine AS base
|
||||
|
||||
# ========================================
|
||||
# Dependencies Stage: Install Dependencies
|
||||
# ========================================
|
||||
FROM base AS deps
|
||||
RUN apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
|
||||
# Install turbo globally
|
||||
RUN bun install -g turbo
|
||||
|
||||
COPY package.json bun.lock ./
|
||||
RUN mkdir -p apps
|
||||
COPY apps/sim/package.json ./apps/sim/package.json
|
||||
|
||||
RUN bun install --omit dev --ignore-scripts
|
||||
|
||||
# ========================================
|
||||
# Builder Stage: Build the Application
|
||||
# ========================================
|
||||
FROM base AS builder
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
# ========================================
|
||||
# Runner Stage: Run the Socket Server
|
||||
# ========================================
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
# Copy the entire sim app since socket-server has dependencies on other modules
|
||||
COPY --from=builder /app/apps/sim ./apps/sim
|
||||
COPY --from=builder /app/node_modules ./node_modules
|
||||
COPY --from=builder /app/package.json ./package.json
|
||||
|
||||
# Expose socket server port (default 3002, but configurable via PORT env var)
|
||||
EXPOSE 3002
|
||||
ENV PORT=3002 \
|
||||
SOCKET_PORT=3002 \
|
||||
HOSTNAME="0.0.0.0"
|
||||
|
||||
# Run the socket server directly
|
||||
CMD ["bun", "apps/sim/socket-server/index.ts"]
|
||||
@@ -11,6 +11,8 @@
|
||||
"scripts": {
|
||||
"build": "turbo run build",
|
||||
"dev": "turbo run dev",
|
||||
"dev:sockets": "cd apps/sim && bun run dev:sockets",
|
||||
"dev:full": "cd apps/sim && bun run dev:full",
|
||||
"test": "turbo run test",
|
||||
"format": "bunx biome format --write .",
|
||||
"format:check": "bunx biome format .",
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Command } from 'commander'
|
||||
const NETWORK_NAME = 'simstudio-network'
|
||||
const DB_CONTAINER = 'simstudio-db'
|
||||
const MIGRATIONS_CONTAINER = 'simstudio-migrations'
|
||||
const REALTIME_CONTAINER = 'simstudio-realtime'
|
||||
const APP_CONTAINER = 'simstudio-app'
|
||||
const DEFAULT_PORT = '3000'
|
||||
|
||||
@@ -78,6 +79,7 @@ async function cleanupExistingContainers(): Promise<void> {
|
||||
await stopAndRemoveContainer(APP_CONTAINER)
|
||||
await stopAndRemoveContainer(DB_CONTAINER)
|
||||
await stopAndRemoveContainer(MIGRATIONS_CONTAINER)
|
||||
await stopAndRemoveContainer(REALTIME_CONTAINER)
|
||||
}
|
||||
|
||||
async function main() {
|
||||
@@ -101,6 +103,7 @@ async function main() {
|
||||
if (options.pull) {
|
||||
await pullImage('ghcr.io/simstudioai/simstudio:latest')
|
||||
await pullImage('ghcr.io/simstudioai/migrations:latest')
|
||||
await pullImage('ghcr.io/simstudioai/realtime:latest')
|
||||
await pullImage('pgvector/pgvector:pg17')
|
||||
}
|
||||
|
||||
@@ -193,6 +196,34 @@ async function main() {
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Start the realtime server
|
||||
console.log(chalk.blue('🔄 Starting Realtime Server...'))
|
||||
const realtimeSuccess = await runCommand([
|
||||
'docker',
|
||||
'run',
|
||||
'-d',
|
||||
'--name',
|
||||
REALTIME_CONTAINER,
|
||||
'--network',
|
||||
NETWORK_NAME,
|
||||
'-p',
|
||||
'3002:3002',
|
||||
'-e',
|
||||
`DATABASE_URL=postgresql://postgres:postgres@${DB_CONTAINER}:5432/simstudio`,
|
||||
'-e',
|
||||
`BETTER_AUTH_URL=http://localhost:${port}`,
|
||||
'-e',
|
||||
`NEXT_PUBLIC_APP_URL=http://localhost:${port}`,
|
||||
'-e',
|
||||
'BETTER_AUTH_SECRET=your_auth_secret_here',
|
||||
'ghcr.io/simstudioai/realtime:latest',
|
||||
])
|
||||
|
||||
if (!realtimeSuccess) {
|
||||
console.error(chalk.red('❌ Failed to start Realtime Server'))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Start the main application
|
||||
console.log(chalk.blue('🔄 Starting Sim Studio...'))
|
||||
const appSuccess = await runCommand([
|
||||
|
||||
Reference in New Issue
Block a user