Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .devcontainer/playground/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
FROM mcr.microsoft.com/devcontainers/typescript-node:20
# Node.js version (should match .nvmrc)
ARG NODE_VERSION=24
FROM mcr.microsoft.com/devcontainers/typescript-node:${NODE_VERSION}

# Install system dependencies
RUN apt-get update && apt-get install -y \
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/build-devcontainer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4

- name: Read Node.js version from .nvmrc
id: node-version
run: echo "version=$(cat .nvmrc)" >> $GITHUB_OUTPUT

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
Expand Down Expand Up @@ -53,5 +57,7 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
NODE_VERSION=${{ steps.node-version.outputs.version }}
cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/agor-playground:latest
cache-to: type=inline
72 changes: 72 additions & 0 deletions .github/workflows/build-production.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: Build Production Docker Image

on:
# Manual trigger
workflow_dispatch:

push:
# Trigger on pushes to main branch
branches:
- main
# Trigger on new release tags
tags:
- 'v*.*.*'

# Cancel previous runs of this workflow
concurrency:
group: production-build-${{ github.ref }}
cancel-in-progress: true

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Read Node.js version from .nvmrc
id: node-version
run: echo "version=$(cat .nvmrc)" >> $GITHUB_OUTPUT

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository_owner }}/agor
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=sha,prefix=sha-
type=ref,event=tag
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
NODE_VERSION=${{ steps.node-version.outputs.version }}
cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/agor:latest
cache-to: type=inline
platforms: linux/amd64,linux/arm64

- name: Image digest
run: echo "Image pushed with digest ${{ steps.build.outputs.digest }}"
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20
24
130 changes: 130 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Production Dockerfile for Agor
# Multi-stage build optimized for Kubernetes deployment

# Node.js version (should match .nvmrc)
# Override at build time: docker build --build-arg NODE_VERSION=24 .
ARG NODE_VERSION=24

# ==========================================
# Stage 1: Base with pnpm
# ==========================================
FROM node:${NODE_VERSION}-slim AS base

# Install pnpm globally
RUN npm install -g [email protected]

# ==========================================
# Stage 2: Dependencies
# ==========================================
FROM base AS deps

WORKDIR /app

# Copy workspace configuration
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./

# Copy all package.json files for workspace
COPY apps/agor-daemon/package.json ./apps/agor-daemon/
COPY apps/agor-cli/package.json ./apps/agor-cli/
COPY apps/agor-ui/package.json ./apps/agor-ui/
COPY packages/core/package.json ./packages/core/

# Install all dependencies (including devDependencies for build)
RUN pnpm install --frozen-lockfile

# ==========================================
# Stage 3: Builder
# ==========================================
FROM base AS builder

WORKDIR /app

# Copy dependencies from deps stage
COPY --from=deps /app/node_modules ./node_modules
COPY --from=deps /app/apps/agor-daemon/node_modules ./apps/agor-daemon/node_modules
COPY --from=deps /app/apps/agor-cli/node_modules ./apps/agor-cli/node_modules
COPY --from=deps /app/apps/agor-ui/node_modules ./apps/agor-ui/node_modules
COPY --from=deps /app/packages/core/node_modules ./packages/core/node_modules

# Copy source code
COPY . .

# Build only production packages (exclude docs)
RUN pnpm --filter @agor/core build && \
pnpm --filter @agor/daemon build && \
pnpm --filter @agor/cli build && \
pnpm --filter agor-ui build

# ==========================================
# Stage 4: Production runtime
# ==========================================
ARG NODE_VERSION=24
FROM node:${NODE_VERSION}-slim AS runtime

# Install system dependencies
RUN apt-get update && apt-get install -y \
sqlite3 \
git \
curl \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*

# Install GitHub CLI (gh) for git operations
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && \
chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null && \
apt-get update && \
apt-get install -y gh && \
rm -rf /var/lib/apt/lists/*

# Install pnpm
RUN npm install -g [email protected]

# Create non-root user
RUN useradd -m -s /bin/bash agor && \
mkdir -p /home/agor/.agor && \
chown -R agor:agor /home/agor

WORKDIR /app

# Copy workspace configuration
COPY package.json pnpm-workspace.yaml ./

# Copy production dependencies only
# Re-install with --prod flag to get only production dependencies
COPY apps/agor-daemon/package.json ./apps/agor-daemon/
COPY apps/agor-cli/package.json ./apps/agor-cli/
COPY apps/agor-ui/package.json ./apps/agor-ui/
COPY packages/core/package.json ./packages/core/

RUN pnpm install --prod --ignore-scripts

# Copy built artifacts from builder stage
COPY --from=builder /app/packages/core/dist ./packages/core/dist
COPY --from=builder /app/apps/agor-daemon/dist ./apps/agor-daemon/dist
COPY --from=builder /app/apps/agor-cli/dist ./apps/agor-cli/dist
COPY --from=builder /app/apps/agor-ui/dist ./apps/agor-ui/dist

# Copy CLI bin directory
COPY --from=builder /app/apps/agor-cli/bin ./apps/agor-cli/bin

# Copy necessary source files for runtime
COPY packages/core/package.json ./packages/core/

# Copy scripts that may be needed at runtime
COPY scripts ./scripts

# Copy production entrypoint script
COPY docker-entrypoint-prod.sh /app/docker-entrypoint-prod.sh

# Set proper ownership and permissions
RUN chown -R agor:agor /app

# Switch to non-root user
USER agor

WORKDIR /app/apps/agor-daemon

# Expose daemon port (serves both API and UI)
EXPOSE 3030
CMD ["pnpm", "start"]
5 changes: 4 additions & 1 deletion Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Development Dockerfile for Agor
# Supports hot-reload for both daemon and UI
FROM node:20-slim

# Node.js version (should match .nvmrc)
ARG NODE_VERSION=24
FROM node:${NODE_VERSION}-slim

# Install system dependencies (including git for repo cloning)
RUN apt-get update && apt-get install -y \
Expand Down
15 changes: 15 additions & 0 deletions docker-entrypoint-prod.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/sh
set -e

echo "🚀 Starting Agor in production mode..."

# Initialize database if it doesn't exist
if [ ! -f "/home/agor/.agor/agor.db" ]; then
echo "📦 Initializing Agor database..."
pnpm --filter @agor/cli exec node bin/run.js init
fi

# Start daemon (which serves both API and static UI)
echo "🚀 Starting Agor daemon on port ${PORT:-3030}..."
cd /app/apps/agor-daemon
exec pnpm start