Ephemeral Environment Integration
This skill provides guidance for integrating projects with the ephemeral environment system, which automatically creates preview deployments for GitHub pull requests.
Overview
The ephemeral environment system automatically:
- •Detects when a PR is opened or updated
- •Spins up an EC2 instance with the PR's code
- •Runs the application via docker-compose
- •Exposes it publicly through a Cloudflare tunnel
- •Posts the preview URL as a PR comment
- •Cleans up when the PR closes
Integration Requirements
To integrate a project, two things are needed:
1. Compatible docker-compose.yml
The project must have a docker-compose.yml file in the repository root that:
- •Exposes the application on port 80
- •Uses standard Docker Compose syntax
- •Contains all services needed to run the application
Minimal example:
services:
app:
build: .
ports:
- "80:3000" # Map internal port to 80
With database:
services:
app:
build: .
ports:
- "80:8080"
environment:
- DATABASE_URL=postgres://postgres:postgres@db:5432/app
depends_on:
- db
db:
image: postgres:15
environment:
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=app
2. GitHub App Installation
The ephemeral-environments GitHub App must be installed on the repository:
- •Navigate to the GitHub App settings page
- •Install on the target repository
- •Grant necessary permissions (repository contents, pull requests, commit statuses)
Port Configuration
The system expects the application to be accessible on port 80. Common patterns:
| Framework | Internal Port | docker-compose mapping |
|---|---|---|
| Node/Express | 3000 | "80:3000" |
| Python/Flask | 5000 | "80:5000" |
| Python/Django | 8000 | "80:8000" |
| Go | 8080 | "80:8080" |
| Ruby/Rails | 3000 | "80:3000" |
| Java/Spring | 8080 | "80:8080" |
docker-compose.yml Patterns
Single Service Application
For simple applications with just the main service:
services:
app:
build: .
ports:
- "80:3000"
environment:
- NODE_ENV=production
Application with Database
For applications requiring a database:
services:
app:
build: .
ports:
- "80:3000"
environment:
- DATABASE_URL=postgres://postgres:postgres@db:5432/app
depends_on:
db:
condition: service_healthy
db:
image: postgres:15
environment:
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=app
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
Application with Redis
For applications using Redis for caching or sessions:
services:
app:
build: .
ports:
- "80:8000"
environment:
- REDIS_URL=redis://redis:6379
depends_on:
- redis
redis:
image: redis:7-alpine
Full Stack Application
For applications with frontend, backend, and database:
services:
frontend:
build: ./frontend
ports:
- "80:80"
depends_on:
- backend
backend:
build: ./backend
expose:
- "8080"
environment:
- DATABASE_URL=postgres://postgres:postgres@db:5432/app
depends_on:
- db
db:
image: postgres:15
environment:
- POSTGRES_PASSWORD=postgres
Environment Variables
For sensitive configuration, use environment variables in docker-compose:
services:
app:
build: .
ports:
- "80:3000"
environment:
- API_KEY=${API_KEY}
- SECRET_KEY=${SECRET_KEY}
Note: Environment variables must be configured in the ephemeral environment system's secrets management to be available during deployment.
Dockerfile Requirements
Ensure the Dockerfile:
- •Builds successfully without external dependencies
- •Includes all runtime dependencies
- •Exposes the correct port
- •Has a proper CMD or ENTRYPOINT
Example Node.js Dockerfile:
FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . EXPOSE 3000 CMD ["node", "server.js"]
Example Python Dockerfile:
FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]
Verification Checklist
Before opening a PR, verify:
- •
docker-compose.ymlexists in repository root - • Port 80 is exposed in docker-compose.yml
- •
docker-compose upruns successfully locally - • Application is accessible at
http://localhostafter startup - • GitHub App is installed on the repository
- • All required services (db, redis, etc.) are defined
How It Works
When a PR is opened:
- •Webhook: GitHub sends a webhook to the Cloudflare Worker
- •Queue: Worker validates and sends message to AWS SQS
- •Deploy: Lambda function launches EC2 instance from AMI
- •Clone: Instance clones the PR branch via SSM commands
- •Start: docker-compose starts all services
- •Tunnel: Cloudflare Quick Tunnel exposes port 80
- •Notify: Preview URL posted as PR comment and commit status
When a PR closes:
- •Webhook: GitHub sends closed event
- •Cleanup: Lambda terminates the EC2 instance
- •State: DynamoDB record updated to "destroyed"
Scheduled maintenance ensures orphaned environments are cleaned up.
Using the /integrate Command
Run the /integrate command in this repository for interactive setup assistance. The command will:
- •Check for existing docker-compose.yml
- •Analyze port configuration
- •Validate Dockerfile if present
- •Offer to generate compatible configuration
- •Provide next steps for GitHub App installation
Common Issues
Application not accessible
- •Verify port 80 is exposed in docker-compose.yml
- •Check the internal port matches what the application listens on
- •Ensure the application binds to
0.0.0.0, not127.0.0.1
Container fails to start
- •Test locally with
docker-compose up --build - •Check for missing environment variables
- •Verify all dependencies are available
Preview URL not posted
- •Confirm GitHub App is installed
- •Check PR is from a branch in the same repository (not a fork)
- •Verify webhook is configured correctly