# Container and Compute Infrastructure

## Compute Options Overview

### Decision Matrix

| Option | Best For | Cold Start | Cost Model | Scaling |
|--------|----------|------------|------------|---------|
| **Serverless Functions** | API endpoints, webhooks | 50-500ms | Per-invocation | Automatic |
| **Edge Functions** | Low-latency, global | <50ms | Per-invocation | Automatic |
| **Containers (Fargate)** | Long-running processes | 30-60s | Per-second | Manual/Auto |
| **Containers (ECS/K8s)** | Complex workloads | Minutes | Per-instance | Manual/Auto |
| **VMs** | Legacy, special requirements | Minutes | Per-hour | Manual |

### When to Use What

```
Quick API response needed?
├── Yes → Need global low-latency?
│         ├── Yes → Edge Functions (Cloudflare Workers)
│         └── No → Serverless Functions (Vercel, Lambda)
└── No → Long-running process?
          ├── Yes → Containers (Fargate, Cloud Run)
          └── No → Stateful/persistent?
                    ├── Yes → Containers or VMs
                    └── No → Serverless Functions
```

## Serverless Functions

### Vercel Functions

**Best for:** Next.js API routes, simple backends

```typescript
// pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'

export default function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  res.status(200).json({ message: 'Hello from Vercel!' })
}

// Configure runtime
export const config = {
  runtime: 'nodejs',  // or 'edge'
  maxDuration: 10,    // seconds (hobby: 10s, pro: 60s)
}
```

**Deployment with Pulumi:**

```python
import pulumi_vercel as vercel

project = vercel.Project(
    "api",
    name="my-api",
    framework="nextjs",
    serverless_function_region="iad1",  # us-east
    git_repository=vercel.ProjectGitRepositoryArgs(
        type="github",
        repo="org/my-api",
    ),
)
```

### Cloudflare Workers

**Best for:** Edge computing, global low-latency

```typescript
// workers/api.ts
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url)

    if (url.pathname === '/api/hello') {
      return new Response(JSON.stringify({ message: 'Hello from the edge!' }), {
        headers: { 'Content-Type': 'application/json' },
      })
    }

    return new Response('Not Found', { status: 404 })
  },
}
```

**Deployment:**

```bash
# wrangler.toml
name = "my-worker"
main = "src/index.ts"
compatibility_date = "2025-01-01"

# Deploy
wrangler deploy
```

### Supabase Edge Functions

**Best for:** Supabase ecosystem, Deno runtime

```typescript
// supabase/functions/hello/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'

serve(async (req) => {
  const { name } = await req.json()

  return new Response(
    JSON.stringify({ message: `Hello ${name}!` }),
    { headers: { 'Content-Type': 'application/json' } },
  )
})
```

**Deployment:**

```bash
supabase functions deploy hello
```

## Container Infrastructure

### AWS Fargate (Serverless Containers)

**Best for:** Long-running processes, background jobs, complex APIs

**Pulumi Example:**

```python
"""AWS Fargate service with Pulumi."""

import pulumi
import pulumi_aws as aws
import pulumi_awsx as awsx


# Create VPC
vpc = awsx.ec2.Vpc("main", nat_gateways=awsx.ec2.NatGatewayConfigurationArgs(strategy="Single"))

# Create ECS cluster
cluster = aws.ecs.Cluster("main")

# Create load balancer
alb = awsx.lb.ApplicationLoadBalancer("web", default_target_group_port=8080)

# Create Fargate service
service = awsx.ecs.FargateService(
    "web",
    cluster=cluster.arn,
    assign_public_ip=True,
    task_definition_args=awsx.ecs.FargateServiceTaskDefinitionArgs(
        container=awsx.ecs.TaskDefinitionContainerDefinitionArgs(
            name="web",
            image="my-registry/my-app:latest",
            cpu=256,
            memory=512,
            essential=True,
            port_mappings=[
                awsx.ecs.TaskDefinitionPortMappingArgs(
                    container_port=8080,
                    target_group=alb.default_target_group,
                )
            ],
            environment=[
                awsx.ecs.TaskDefinitionKeyValuePairArgs(
                    name="NODE_ENV",
                    value="production",
                ),
            ],
        ),
    ),
    desired_count=2,
)

pulumi.export("url", alb.load_balancer.dns_name)
```

### Docker Configuration

**Multi-stage Dockerfile:**

```dockerfile
# Build stage
FROM python:3.11-slim as builder

WORKDIR /app

# Install build dependencies
RUN pip install --no-cache-dir poetry

# Copy dependency files
COPY pyproject.toml poetry.lock ./

# Install dependencies
RUN poetry config virtualenvs.create false \
    && poetry install --no-dev --no-interaction --no-ansi

# Copy application code
COPY src/ ./src/

# Production stage
FROM python:3.11-slim

WORKDIR /app

# Copy from builder
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /app/src ./src

# Create non-root user
RUN useradd --create-home appuser
USER appuser

# Set environment
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')"

# Run application
CMD ["python", "-m", "src.main"]
```

**docker-compose for local development:**

```yaml
# docker-compose.yml
version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    environment:
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      - db
      - redis

  db:
    image: postgres:15
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine

volumes:
  postgres_data:
```

### Google Cloud Run

**Best for:** Simpler container deployments, auto-scaling to zero

```python
"""Cloud Run with Pulumi."""

import pulumi
import pulumi_gcp as gcp

service = gcp.cloudrun.Service(
    "api",
    location="us-central1",
    template=gcp.cloudrun.ServiceTemplateArgs(
        spec=gcp.cloudrun.ServiceTemplateSpecArgs(
            containers=[
                gcp.cloudrun.ServiceTemplateSpecContainerArgs(
                    image="gcr.io/my-project/my-app:latest",
                    ports=[gcp.cloudrun.ServiceTemplateSpecContainerPortArgs(container_port=8080)],
                    resources=gcp.cloudrun.ServiceTemplateSpecContainerResourcesArgs(
                        limits={"memory": "512Mi", "cpu": "1"},
                    ),
                    envs=[
                        gcp.cloudrun.ServiceTemplateSpecContainerEnvArgs(
                            name="NODE_ENV",
                            value="production",
                        ),
                    ],
                ),
            ],
        ),
        metadata=gcp.cloudrun.ServiceTemplateMetadataArgs(
            annotations={
                "autoscaling.knative.dev/minScale": "0",
                "autoscaling.knative.dev/maxScale": "10",
            },
        ),
    ),
)

# Make publicly accessible
iam = gcp.cloudrun.IamMember(
    "public",
    service=service.name,
    location=service.location,
    role="roles/run.invoker",
    member="allUsers",
)

pulumi.export("url", service.statuses[0].url)
```

## Workflow Management

### GitHub Actions (CI/CD)

```yaml
# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build Docker image
        run: docker build -t my-app:${{ github.sha }} .

      - name: Push to registry
        run: |
          docker tag my-app:${{ github.sha }} ${{ secrets.REGISTRY }}/my-app:${{ github.sha }}
          docker push ${{ secrets.REGISTRY }}/my-app:${{ github.sha }}

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Deploy to Fargate
        run: |
          pulumi up --yes --stack production
        env:
          PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
```

### Background Jobs

**For scheduled/background work:**

```python
"""Background job patterns."""

# Option 1: Scheduled Lambda/Cloud Function
# Use EventBridge (AWS) or Cloud Scheduler (GCP)

# Option 2: Queue-based processing
# SQS + Lambda, or Pub/Sub + Cloud Run

# Option 3: Cron in container
# Run cron daemon alongside application

# Example: SQS trigger with Pulumi
import pulumi_aws as aws

queue = aws.sqs.Queue("jobs", visibility_timeout_seconds=300)

lambda_fn = aws.lambda_.Function(
    "worker",
    handler="handler.process",
    runtime="python3.11",
    code=pulumi.FileArchive("./worker"),
)

trigger = aws.lambda_.EventSourceMapping(
    "sqs-trigger",
    event_source_arn=queue.arn,
    function_name=lambda_fn.arn,
    batch_size=10,
)
```

## Cost Comparison

### Monthly Cost Examples (2025-01)

| Service | Configuration | ~Cost/month |
|---------|--------------|-------------|
| Vercel Functions | 1M invocations | $0-20 |
| Cloudflare Workers | 10M requests | $5 |
| Fargate | 2 tasks, 0.5 vCPU | $30-50 |
| Cloud Run | 1M requests, 512MB | $5-20 |
| Lambda | 1M invocations, 256MB | $5-10 |

### Cost Optimization Tips

1. **Right-size containers** - Don't over-provision CPU/memory
2. **Use spot/preemptible** - For non-critical workloads
3. **Scale to zero** - Cloud Run, Fargate with scale-in
4. **Cache aggressively** - Reduce function invocations
5. **Use edge when possible** - Often cheaper than origin compute

## Related Documentation

- **Vercel**: [vercel.md](./vercel.md) - Vercel functions
- **Cloudflare**: [cloudflare.md](./cloudflare.md) - Workers
- **Supabase**: [supabase.md](./supabase.md) - Edge functions
- **Financial Governance**: [financial-governance.md](./financial-governance.md) - Cost management
- **Hybrid IaC**: [hybrid-iac-approaches.md](./hybrid-iac-approaches.md) - Multi-tool workflows

---

**Key Takeaway**: Choose compute based on workload characteristics—serverless for short-lived API calls, edge for global low-latency, containers for long-running or complex workloads. Start serverless and move to containers only when necessary.
