Deployment Guide

Best practices for deploying and managing applications in production

Production Deployment Checklist

Essential steps before going live

Production Deployment Checklist

Ensure your SimplyStream application is production-ready with this comprehensive checklist.

Pre-Deployment

1. Testing

  • All features tested in staging environment
  • Load testing completed with expected user count
  • Streaming quality verified across different network conditions
  • Cross-browser compatibility tested (Chrome, Firefox, Safari, Edge)
  • Mobile responsiveness verified
  • Error handling tested for common failure scenarios
  • Backup and recovery procedures tested

2. Performance Optimization

  • Build size optimized (compression, code splitting)
  • Images and assets optimized
  • Streaming bitrate configured appropriately
  • CDN configured for static assets
  • Database queries optimized
  • Caching strategy implemented
  • API rate limits configured

3. Security

  • HTTPS/SSL certificates configured
  • API keys and secrets stored securely
  • Authentication and authorization implemented
  • Input validation and sanitization in place
  • Content Security Policy (CSP) configured
  • CORS properly configured
  • DDoS protection enabled
  • Regular security updates scheduled

4. Monitoring & Logging

  • Error tracking configured (Sentry, LogRocket, etc.)
  • Performance monitoring enabled (New Relic, DataDog, etc.)
  • Uptime monitoring configured
  • Log aggregation setup
  • Alerts configured for critical issues
  • Analytics tracking implemented
  • User session recording enabled (optional)

5. Infrastructure

  • Auto-scaling configured
  • Load balancer setup
  • Database backups automated
  • Disaster recovery plan documented
  • Multiple regions configured for redundancy
  • CDN configured for global delivery
  • DNS configured correctly

Configuration

Environment Variables

Ensure all environment variables are set:

# Production .env
NODE_ENV=production
SIMPLYSTREAM_API_KEY=your_production_api_key
SIMPLYSTREAM_PROJECT_ID=your_project_id

# Database
DATABASE_URL=your_production_database_url
REDIS_URL=your_redis_url

# Security
SESSION_SECRET=your_session_secret
JWT_SECRET=your_jwt_secret

# Monitoring
SENTRY_DSN=your_sentry_dsn
ANALYTICS_ID=your_analytics_id

# Email
SMTP_HOST=your_smtp_host
SMTP_PORT=587
SMTP_USER=your_smtp_user
SMTP_PASSWORD=your_smtp_password

SimplyStream Configuration

Configure production-specific settings:

import { SimplyStreamClient } from '@simplystream/sdk';

const client = new SimplyStreamClient({
	apiKey: process.env.SIMPLYSTREAM_API_KEY,
	projectId: process.env.SIMPLYSTREAM_PROJECT_ID,
	environment: 'production',
	timeout: 30000,
	retryConfig: {
		maxRetries: 3,
		retryDelay: 1000
	}
});

Deployment Steps

1. Build

# Install dependencies
npm ci --production

# Run production build
npm run build

# Verify build output
ls -la dist/

2. Database Migration

# Run database migrations
npm run migrate:production

# Verify migrations
npm run migrate:status

3. Upload Assets

# Upload build to SimplyStream
npm run upload:build

# Upload static assets to CDN
npm run upload:assets

4. Deploy Application

# Deploy to production
npm run deploy:production

# Verify deployment
npm run health:check

5. Smoke Testing

After deployment, verify critical functionality:

# Run smoke tests
npm run test:smoke

# Check endpoints
curl https://your-app.com/health
curl https://your-app.com/api/status

Post-Deployment

1. Monitoring

Monitor the application for the first hour:

  • Check error rates in monitoring dashboard
  • Verify all services are healthy
  • Monitor response times and latency
  • Check user sessions are being created
  • Verify streaming sessions work correctly

2. Rollback Plan

Be prepared to rollback if issues occur:

# Rollback to previous version
npm run deploy:rollback

# Or manually specify version
npm run deploy:rollback --version=1.2.3

3. Communication

  • Notify team of successful deployment
  • Update status page
  • Announce new features to users (if applicable)
  • Update documentation

Performance Benchmarks

Track these metrics post-deployment:

Metric Target Critical Threshold
Page Load Time < 2s < 5s
API Response Time < 200ms < 1s
Session Creation Time < 3s < 10s
Stream Start Time < 5s < 15s
Error Rate < 0.1% < 1%
Uptime > 99.9% > 99%

Security Checklist

Authentication

  • Secure session management implemented
  • Password policies enforced
  • Multi-factor authentication available
  • Account lockout after failed attempts
  • Session timeout configured

Data Protection

  • Sensitive data encrypted at rest
  • Sensitive data encrypted in transit
  • PII handling compliant with regulations
  • Data retention policies implemented
  • Right to deletion implemented (GDPR)

API Security

  • Rate limiting enabled
  • API authentication required
  • Input validation on all endpoints
  • SQL injection protection
  • XSS protection
  • CSRF protection

Compliance

GDPR (if applicable)

  • Privacy policy published
  • Cookie consent implemented
  • Data export functionality
  • Data deletion functionality
  • Data processing agreement signed

Accessibility

  • WCAG 2.1 Level AA compliance
  • Keyboard navigation supported
  • Screen reader compatible
  • Color contrast ratios met
  • Alt text for all images

Documentation

  • API documentation updated
  • User documentation current
  • Deployment procedures documented
  • Runbook for common issues
  • Architecture diagrams updated

Maintenance

Regular Tasks

Daily:

  • Monitor error rates
  • Check system health
  • Review user feedback

Weekly:

  • Review performance metrics
  • Check backup integrity
  • Review security logs
  • Update dependencies

Monthly:

  • Security audit
  • Performance review
  • Capacity planning
  • Cost optimization review

Emergency Contacts

Maintain a list of emergency contacts:

Team Lead: [email protected], +1-xxx-xxx-xxxx
DevOps: [email protected], +1-xxx-xxx-xxxx
SimplyStream Support: [email protected]
Hosting Provider: [email protected]

Cost Optimization

  • Auto-scaling configured correctly
  • Unused resources identified and removed
  • Reserved instances purchased (if applicable)
  • CDN caching optimized
  • Database query performance optimized
  • Compression enabled
  • Resource usage alerts configured

Final Verification

Before marking deployment as complete:

  1. Functionality: All features working as expected
  2. Performance: Meeting performance benchmarks
  3. Security: All security measures in place
  4. Monitoring: Alerts and monitoring active
  5. Documentation: All documentation updated
  6. Team: Team notified and aware of changes
  7. Rollback: Rollback plan tested and ready

Next Steps

CI/CD Integration

Automate deployments with CI/CD pipelines

CI/CD Integration

Automate your SimplyStream deployments with continuous integration and continuous deployment pipelines.

GitHub Actions

Basic Deployment Workflow

Create .github/workflows/deploy.yml:

name: Deploy to SimplyStream

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  SIMPLYSTREAM_API_KEY: ${{ secrets.SIMPLYSTREAM_API_KEY }}
  SIMPLYSTREAM_PROJECT_ID: ${{ secrets.SIMPLYSTREAM_PROJECT_ID }}

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

      - name: Run linter
        run: npm run lint

  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build application
        run: npm run build

      - name: Upload build artifact
        uses: actions/upload-artifact@v3
        with:
          name: build
          path: dist/

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v3

      - name: Download build artifact
        uses: actions/download-artifact@v3
        with:
          name: build
          path: dist/

      - name: Deploy to SimplyStream
        run: |
          npm install -g @simplystream/cli
          simplystream deploy \
            --project-id $SIMPLYSTREAM_PROJECT_ID \
            --api-key $SIMPLYSTREAM_API_KEY \
            --build-path dist/

Advanced Workflow with Staging

name: CI/CD Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: npm ci
      - run: npm test
      - run: npm run test:e2e

  deploy-staging:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/develop'
    environment:
      name: staging
      url: https://staging.yourapp.com
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: npm ci
      - run: npm run build
      - name: Deploy to Staging
        env:
          SIMPLYSTREAM_API_KEY: ${{ secrets.STAGING_API_KEY }}
        run: |
          npm install -g @simplystream/cli
          simplystream deploy \
            --project-id ${{ secrets.STAGING_PROJECT_ID }} \
            --environment staging

  deploy-production:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment:
      name: production
      url: https://yourapp.com
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: npm ci
      - run: npm run build:production
      - name: Deploy to Production
        env:
          SIMPLYSTREAM_API_KEY: ${{ secrets.PRODUCTION_API_KEY }}
        run: |
          npm install -g @simplystream/cli
          simplystream deploy \
            --project-id ${{ secrets.PRODUCTION_PROJECT_ID }} \
            --environment production \
            --release-notes "${{ github.event.head_commit.message }}"

      - name: Create GitHub Release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: v${{ github.run_number }}
          release_name: Release ${{ github.run_number }}
          body: ${{ github.event.head_commit.message }}

GitLab CI

.gitlab-ci.yml Configuration

stages:
  - test
  - build
  - deploy

variables:
  NODE_VERSION: '18'

test:
  stage: test
  image: node:${NODE_VERSION}
  cache:
    paths:
      - node_modules/
  script:
    - npm ci
    - npm run test
    - npm run lint
  artifacts:
    reports:
      junit: junit.xml
      coverage: coverage/

build:
  stage: build
  image: node:${NODE_VERSION}
  cache:
    paths:
      - node_modules/
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 week

deploy:staging:
  stage: deploy
  image: node:${NODE_VERSION}
  environment:
    name: staging
    url: https://staging.yourapp.com
  only:
    - develop
  script:
    - npm install -g @simplystream/cli
    - simplystream deploy
      --project-id $STAGING_PROJECT_ID
      --api-key $STAGING_API_KEY
      --build-path dist/
      --environment staging

deploy:production:
  stage: deploy
  image: node:${NODE_VERSION}
  environment:
    name: production
    url: https://yourapp.com
  only:
    - main
  when: manual
  script:
    - npm install -g @simplystream/cli
    - simplystream deploy
      --project-id $PRODUCTION_PROJECT_ID
      --api-key $PRODUCTION_API_KEY
      --build-path dist/
      --environment production

CircleCI

.circleci/config.yml

version: 2.1

orbs:
  node: circleci/[email protected]

jobs:
  test:
    docker:
      - image: cimg/node:18.0
    steps:
      - checkout
      - node/install-packages:
          pkg-manager: npm
      - run:
          name: Run tests
          command: npm test
      - run:
          name: Run linter
          command: npm run lint

  build:
    docker:
      - image: cimg/node:18.0
    steps:
      - checkout
      - node/install-packages:
          pkg-manager: npm
      - run:
          name: Build application
          command: npm run build
      - persist_to_workspace:
          root: .
          paths:
            - dist

  deploy:
    docker:
      - image: cimg/node:18.0
    steps:
      - checkout
      - attach_workspace:
          at: .
      - run:
          name: Install SimplyStream CLI
          command: npm install -g @simplystream/cli
      - run:
          name: Deploy to SimplyStream
          command: |
            simplystream deploy \
              --project-id $SIMPLYSTREAM_PROJECT_ID \
              --api-key $SIMPLYSTREAM_API_KEY \
              --build-path dist/

workflows:
  test-build-deploy:
    jobs:
      - test
      - build:
          requires:
            - test
      - deploy:
          requires:
            - build
          filters:
            branches:
              only: main

Jenkins

Jenkinsfile

pipeline {
    agent any

    environment {
        SIMPLYSTREAM_API_KEY = credentials('simplystream-api-key')
        SIMPLYSTREAM_PROJECT_ID = credentials('simplystream-project-id')
    }

    stages {
        stage('Install') {
            steps {
                sh 'npm ci'
            }
        }

        stage('Test') {
            steps {
                sh 'npm test'
                sh 'npm run lint'
            }
        }

        stage('Build') {
            steps {
                sh 'npm run build'
            }
        }

        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                sh 'npm install -g @simplystream/cli'
                sh '''
                    simplystream deploy \
                        --project-id $SIMPLYSTREAM_PROJECT_ID \
                        --api-key $SIMPLYSTREAM_API_KEY \
                        --build-path dist/
                '''
            }
        }
    }

    post {
        success {
            slackSend color: 'good', message: "Deployment successful: ${env.JOB_NAME} ${env.BUILD_NUMBER}"
        }
        failure {
            slackSend color: 'danger', message: "Deployment failed: ${env.JOB_NAME} ${env.BUILD_NUMBER}"
        }
    }
}

SimplyStream CLI

Installation

npm install -g @simplystream/cli
# or
yarn global add @simplystream/cli

Authentication

# Login interactively
simplystream login

# Or use API key
simplystream auth:set-key YOUR_API_KEY

Deployment Commands

# Deploy current directory
simplystream deploy

# Deploy specific build
simplystream deploy --build-path ./dist

# Deploy with custom configuration
simplystream deploy \
  --project-id proj_123 \
  --environment production \
  --region us-west-2 \
  --release-notes "Bug fixes and improvements"

# Deploy with version tag
simplystream deploy --tag v1.2.3

# List deployments
simplystream deployments list

# Rollback to previous version
simplystream deployments rollback

# Get deployment status
simplystream deployments status deployment_123

Automated Testing in CI/CD

Integration Tests

// tests/integration/deployment.test.ts
import { SimplyStreamClient } from '@simplystream/sdk';

describe('Deployment Tests', () => {
	let client: SimplyStreamClient;
	let sessionId: string;

	beforeAll(() => {
		client = new SimplyStreamClient({
			apiKey: process.env.SIMPLYSTREAM_API_KEY,
			projectId: process.env.SIMPLYSTREAM_PROJECT_ID
		});
	});

	test('should create session successfully', async () => {
		const session = await client.sessions.create({
			buildId: process.env.BUILD_ID
		});

		expect(session.id).toBeDefined();
		expect(session.status).toBe('creating');
		sessionId = session.id;
	});

	test('session should become ready', async () => {
		const session = await client.sessions.waitForReady(sessionId, {
			timeout: 60000
		});

		expect(session.status).toBe('ready');
		expect(session.url).toBeDefined();
	}, 60000);

	test('should load streaming page', async () => {
		const response = await fetch(session.url);
		expect(response.status).toBe(200);
	});

	afterAll(async () => {
		if (sessionId) {
			await client.sessions.terminate(sessionId);
		}
	});
});

Smoke Tests

#!/bin/bash
# smoke-test.sh

set -e

echo "Running smoke tests..."

# Test API health
echo "Testing API..."
curl -f https://api.yourapp.com/health || exit 1

# Test session creation
echo "Testing session creation..."
SESSION_ID=$(curl -X POST https://api.yourapp.com/sessions \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"buildId":"'$BUILD_ID'"}' | jq -r '.id')

if [ -z "$SESSION_ID" ]; then
  echo "Failed to create session"
  exit 1
fi

echo "Smoke tests passed!"

Deployment Notifications

Slack Integration

# GitHub Actions
- name: Notify Slack
  if: always()
  uses: 8398a7/action-slack@v3
  with:
    status: ${{ job.status }}
    text: |
      Deployment ${{ job.status }}
      Branch: ${{ github.ref }}
      Commit: ${{ github.sha }}
      Author: ${{ github.actor }}
    webhook_url: ${{ secrets.SLACK_WEBHOOK }}

Email Notifications

// notify.ts
import { sendEmail } from './email-service';

async function notifyDeployment(result: DeploymentResult) {
	await sendEmail({
		to: '[email protected]',
		subject: `Deployment ${result.status}: ${result.version}`,
		html: `
      <h2>Deployment ${result.status}</h2>
      <ul>
        <li>Version: ${result.version}</li>
        <li>Environment: ${result.environment}</li>
        <li>Duration: ${result.duration}s</li>
        <li>Deployed by: ${result.author}</li>
      </ul>
    `
	});
}

Best Practices

  1. Use environment-specific configurations

    • Separate configs for dev, staging, production
    • Never commit secrets to version control
  2. Implement proper testing

    • Unit tests run on every commit
    • Integration tests before deployment
    • Smoke tests after deployment
  3. Use semantic versioning

    • Tag releases with version numbers
    • Maintain changelog
  4. Enable rollback capabilities

    • Keep previous versions available
    • Test rollback procedures
  5. Monitor deployments

    • Track deployment success/failure rates
    • Monitor application health post-deployment
    • Set up alerts for failures
  6. Use deployment gates

    • Manual approval for production
    • Automated checks before deployment
    • Gradual rollouts when possible

Next Steps

Docker & Containers

Deploy with Docker and Kubernetes

Docker & Containers

Deploy SimplyStream applications using Docker and container orchestration platforms.

Dockerfile

Basic Dockerfile

# Build stage
FROM node:18-alpine AS builder

WORKDIR /app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm ci --only=production

# Copy source code
COPY . .

# Build application
RUN npm run build

# Production stage
FROM node:18-alpine

WORKDIR /app

# Copy built assets from builder
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./

# Set environment
ENV NODE_ENV=production

# Expose port
EXPOSE 3000

# Start application
CMD ["node", "dist/server.js"]

Multi-Stage Dockerfile with SimplyStream

FROM node:18-alpine AS builder

WORKDIR /app

# Install dependencies
COPY package*.json ./
RUN npm ci

# Build application
COPY . .
RUN npm run build

# Upload to SimplyStream
FROM node:18-alpine AS uploader

WORKDIR /app

COPY --from=builder /app/dist ./dist

# Install SimplyStream CLI
RUN npm install -g @simplystream/cli

# Upload build (runs during image build)
ARG SIMPLYSTREAM_API_KEY
ARG SIMPLYSTREAM_PROJECT_ID
RUN simplystream deploy \
    --build-path ./dist \
    --project-id $SIMPLYSTREAM_PROJECT_ID \
    --api-key $SIMPLYSTREAM_API_KEY

# Final runtime stage
FROM node:18-alpine

WORKDIR /app

# Copy application
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package.json ./

ENV NODE_ENV=production

EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD node healthcheck.js

CMD ["node", "dist/server.js"]

Docker Compose

Development Setup

# docker-compose.yml
version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - '3000:3000'
    environment:
      - NODE_ENV=development
      - SIMPLYSTREAM_API_KEY=${SIMPLYSTREAM_API_KEY}
      - SIMPLYSTREAM_PROJECT_ID=${SIMPLYSTREAM_PROJECT_ID}
    volumes:
      - .:/app
      - /app/node_modules
    depends_on:
      - redis
      - postgres

  redis:
    image: redis:7-alpine
    ports:
      - '6379:6379'
    volumes:
      - redis-data:/data

  postgres:
    image: postgres:15-alpine
    ports:
      - '5432:5432'
    environment:
      - POSTGRES_DB=simplystream
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
    volumes:
      - postgres-data:/var/lib/postgresql/data

volumes:
  redis-data:
  postgres-data:

Production Setup

# docker-compose.prod.yml
version: '3.8'

services:
  app:
    image: your-registry/simplystream-app:latest
    restart: unless-stopped
    ports:
      - '80:3000'
    environment:
      - NODE_ENV=production
      - SIMPLYSTREAM_API_KEY=${SIMPLYSTREAM_API_KEY}
      - SIMPLYSTREAM_PROJECT_ID=${SIMPLYSTREAM_PROJECT_ID}
      - DATABASE_URL=${DATABASE_URL}
      - REDIS_URL=${REDIS_URL}
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
        max_attempts: 3

  nginx:
    image: nginx:alpine
    restart: unless-stopped
    ports:
      - '443:443'
      - '80:80'
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - app

Kubernetes

Deployment

# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: simplystream-app
  labels:
    app: simplystream
spec:
  replicas: 3
  selector:
    matchLabels:
      app: simplystream
  template:
    metadata:
      labels:
        app: simplystream
    spec:
      containers:
        - name: app
          image: your-registry/simplystream-app:latest
          ports:
            - containerPort: 3000
          env:
            - name: NODE_ENV
              value: 'production'
            - name: SIMPLYSTREAM_API_KEY
              valueFrom:
                secretKeyRef:
                  name: simplystream-secrets
                  key: api-key
            - name: SIMPLYSTREAM_PROJECT_ID
              valueFrom:
                configMapKeyRef:
                  name: simplystream-config
                  key: project-id
          resources:
            requests:
              memory: '256Mi'
              cpu: '250m'
            limits:
              memory: '512Mi'
              cpu: '500m'
          livenessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /ready
              port: 3000
            initialDelaySeconds: 5
            periodSeconds: 5

Service

# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: simplystream-service
spec:
  selector:
    app: simplystream
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000
  type: LoadBalancer

ConfigMap

# k8s/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: simplystream-config
data:
  project-id: 'proj_your_project_id'
  environment: 'production'
  region: 'us-west-2'

Secret

# k8s/secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: simplystream-secrets
type: Opaque
stringData:
  api-key: 'your_api_key_here'
  database-url: 'postgresql://user:pass@host:5432/db'

Ingress

# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simplystream-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
    - hosts:
        - yourapp.com
      secretName: simplystream-tls
  rules:
    - host: yourapp.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: simplystream-service
                port:
                  number: 80

Helm Chart

Chart.yaml

apiVersion: v2
name: simplystream
description: A Helm chart for SimplyStream application
type: application
version: 1.0.0
appVersion: '1.0.0'

values.yaml

replicaCount: 3

image:
  repository: your-registry/simplystream-app
  pullPolicy: IfNotPresent
  tag: 'latest'

service:
  type: LoadBalancer
  port: 80

ingress:
  enabled: true
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: yourapp.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: simplystream-tls
      hosts:
        - yourapp.com

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80

env:
  - name: NODE_ENV
    value: production
  - name: SIMPLYSTREAM_PROJECT_ID
    value: proj_your_project_id

secrets:
  - name: SIMPLYSTREAM_API_KEY
    value: your_api_key

Container Registry

Build and Push

# Build image
docker build -t your-registry/simplystream-app:latest .

# Tag with version
docker tag your-registry/simplystream-app:latest \
  your-registry/simplystream-app:1.0.0

# Push to registry
docker push your-registry/simplystream-app:latest
docker push your-registry/simplystream-app:1.0.0

GitHub Container Registry

# .github/workflows/docker.yml
name: Docker Build and Push

on:
  push:
    branches: [main]
    tags: ['v*']

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

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

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Log in to Container Registry
        uses: docker/login-action@v2
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v4
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

AWS ECS

Task Definition

{
	"family": "simplystream-app",
	"networkMode": "awsvpc",
	"requiresCompatibilities": ["FARGATE"],
	"cpu": "256",
	"memory": "512",
	"containerDefinitions": [
		{
			"name": "app",
			"image": "your-registry/simplystream-app:latest",
			"portMappings": [
				{
					"containerPort": 3000,
					"protocol": "tcp"
				}
			],
			"environment": [
				{
					"name": "NODE_ENV",
					"value": "production"
				},
				{
					"name": "SIMPLYSTREAM_PROJECT_ID",
					"value": "proj_your_project_id"
				}
			],
			"secrets": [
				{
					"name": "SIMPLYSTREAM_API_KEY",
					"valueFrom": "arn:aws:secretsmanager:region:account:secret:simplystream-api-key"
				}
			],
			"logConfiguration": {
				"logDriver": "awslogs",
				"options": {
					"awslogs-group": "/ecs/simplystream-app",
					"awslogs-region": "us-west-2",
					"awslogs-stream-prefix": "ecs"
				}
			}
		}
	]
}

Google Cloud Run

Deploy to Cloud Run

# Build container
gcloud builds submit --tag gcr.io/your-project/simplystream-app

# Deploy to Cloud Run
gcloud run deploy simplystream-app \
  --image gcr.io/your-project/simplystream-app \
  --platform managed \
  --region us-central1 \
  --allow-unauthenticated \
  --set-env-vars NODE_ENV=production \
  --set-secrets SIMPLYSTREAM_API_KEY=simplystream-api-key:latest \
  --min-instances 1 \
  --max-instances 10

Best Practices

1. Use Multi-Stage Builds

Reduce image size and improve security:

# Build stage
FROM node:18-alpine AS builder
# ... build steps

# Production stage
FROM node:18-alpine
COPY --from=builder /app/dist ./dist
# Only copy what's needed

2. Use .dockerignore

node_modules
npm-debug.log
.git
.env
.env.local
dist
coverage
.vscode
.idea

3. Run as Non-Root User

# Create app user
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

# Change ownership
RUN chown -R nodejs:nodejs /app

# Switch to app user
USER nodejs

4. Health Checks

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1

5. Use Build Arguments

ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpine

ARG BUILD_DATE
ARG VERSION
LABEL build_date=$BUILD_DATE
LABEL version=$VERSION

Monitoring

Prometheus Metrics

// metrics.ts
import promClient from 'prom-client';

const register = new promClient.Registry();

const httpRequestDuration = new promClient.Histogram({
	name: 'http_request_duration_seconds',
	help: 'Duration of HTTP requests in seconds',
	labelNames: ['method', 'route', 'status_code'],
	registers: [register]
});

export { register, httpRequestDuration };

Expose Metrics Endpoint

app.get('/metrics', async (req, res) => {
	res.set('Content-Type', register.contentType);
	res.end(await register.metrics());
});

Next Steps

Environment Configuration

Manage environment variables and secrets

Environment Configuration

Manage environment variables and configuration across different deployment stages.

Environment Variables

Required Variables

# SimplyStream Configuration
SIMPLYSTREAM_API_KEY=your_api_key
SIMPLYSTREAM_PROJECT_ID=your_project_id
SIMPLYSTREAM_ENVIRONMENT=production # development, staging, production

# Application
NODE_ENV=production
PORT=3000
HOST=0.0.0.0

# Database
DATABASE_URL=postgresql://user:password@host:5432/database
DATABASE_POOL_SIZE=20
DATABASE_SSL=true

# Redis (for session/caching)
REDIS_URL=redis://host:6379
REDIS_PASSWORD=your_redis_password

# Security
SESSION_SECRET=your_session_secret
JWT_SECRET=your_jwt_secret
ENCRYPTION_KEY=your_encryption_key

# API Configuration
API_RATE_LIMIT=100
API_TIMEOUT=30000

Optional Variables

# Monitoring & Logging
SENTRY_DSN=https://[email protected]/project
LOG_LEVEL=info # debug, info, warn, error
NEW_RELIC_LICENSE_KEY=your_new_relic_key

# Email
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your_smtp_user
SMTP_PASSWORD=your_smtp_password
[email protected]

# Storage
AWS_ACCESS_KEY_ID=your_aws_key
AWS_SECRET_ACCESS_KEY=your_aws_secret
AWS_REGION=us-west-2
S3_BUCKET=your-bucket-name

# Analytics
GOOGLE_ANALYTICS_ID=UA-XXXXX-Y
MIXPANEL_TOKEN=your_mixpanel_token

Environment Files

Development (.env.development)

NODE_ENV=development
SIMPLYSTREAM_ENVIRONMENT=development

# Use local services
DATABASE_URL=postgresql://localhost:5432/simplystream_dev
REDIS_URL=redis://localhost:6379

# Relaxed security for development
SESSION_SECRET=dev_session_secret
JWT_SECRET=dev_jwt_secret

# Debug logging
LOG_LEVEL=debug
SENTRY_DSN= # Disabled in development

# Development API key (limited quota)
SIMPLYSTREAM_API_KEY=dev_api_key_here
SIMPLYSTREAM_PROJECT_ID=dev_project_id

Staging (.env.staging)

NODE_ENV=production
SIMPLYSTREAM_ENVIRONMENT=staging

# Staging database
DATABASE_URL=${STAGING_DATABASE_URL}
REDIS_URL=${STAGING_REDIS_URL}

# Staging secrets
SESSION_SECRET=${STAGING_SESSION_SECRET}
JWT_SECRET=${STAGING_JWT_SECRET}

# Enable monitoring
SENTRY_DSN=${STAGING_SENTRY_DSN}
LOG_LEVEL=info

# Staging API key
SIMPLYSTREAM_API_KEY=${STAGING_API_KEY}
SIMPLYSTREAM_PROJECT_ID=${STAGING_PROJECT_ID}

Production (.env.production)

NODE_ENV=production
SIMPLYSTREAM_ENVIRONMENT=production

# Production database with SSL
DATABASE_URL=${PRODUCTION_DATABASE_URL}
DATABASE_SSL=true
DATABASE_POOL_SIZE=20

# Production Redis
REDIS_URL=${PRODUCTION_REDIS_URL}

# Production secrets (from secret manager)
SESSION_SECRET=${PRODUCTION_SESSION_SECRET}
JWT_SECRET=${PRODUCTION_JWT_SECRET}
ENCRYPTION_KEY=${PRODUCTION_ENCRYPTION_KEY}

# Full monitoring
SENTRY_DSN=${PRODUCTION_SENTRY_DSN}
NEW_RELIC_LICENSE_KEY=${PRODUCTION_NEW_RELIC_KEY}
LOG_LEVEL=warn

# Production API key
SIMPLYSTREAM_API_KEY=${PRODUCTION_API_KEY}
SIMPLYSTREAM_PROJECT_ID=${PRODUCTION_PROJECT_ID}

# Production settings
API_RATE_LIMIT=100
API_TIMEOUT=30000

Configuration Management

config.ts

import dotenv from 'dotenv';

// Load environment variables
dotenv.config({
	path: `.env.${process.env.NODE_ENV || 'development'}`
});

interface Config {
	env: string;
	port: number;
	simplystream: {
		apiKey: string;
		projectId: string;
		environment: string;
	};
	database: {
		url: string;
		poolSize: number;
		ssl: boolean;
	};
	redis: {
		url: string;
		password?: string;
	};
	security: {
		sessionSecret: string;
		jwtSecret: string;
	};
	monitoring: {
		sentryDsn?: string;
		logLevel: string;
	};
}

function validateConfig(): Config {
	const required = [
		'SIMPLYSTREAM_API_KEY',
		'SIMPLYSTREAM_PROJECT_ID',
		'DATABASE_URL',
		'REDIS_URL',
		'SESSION_SECRET',
		'JWT_SECRET'
	];

	const missing = required.filter((key) => !process.env[key]);
	if (missing.length > 0) {
		throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
	}

	return {
		env: process.env.NODE_ENV || 'development',
		port: parseInt(process.env.PORT || '3000', 10),
		simplystream: {
			apiKey: process.env.SIMPLYSTREAM_API_KEY!,
			projectId: process.env.SIMPLYSTREAM_PROJECT_ID!,
			environment: process.env.SIMPLYSTREAM_ENVIRONMENT || 'development'
		},
		database: {
			url: process.env.DATABASE_URL!,
			poolSize: parseInt(process.env.DATABASE_POOL_SIZE || '10', 10),
			ssl: process.env.DATABASE_SSL === 'true'
		},
		redis: {
			url: process.env.REDIS_URL!,
			password: process.env.REDIS_PASSWORD
		},
		security: {
			sessionSecret: process.env.SESSION_SECRET!,
			jwtSecret: process.env.JWT_SECRET!
		},
		monitoring: {
			sentryDsn: process.env.SENTRY_DSN,
			logLevel: process.env.LOG_LEVEL || 'info'
		}
	};
}

export const config = validateConfig();

Usage

import { config } from './config';

// Initialize SimplyStream client
const client = new SimplyStreamClient({
	apiKey: config.simplystream.apiKey,
	projectId: config.simplystream.projectId,
	environment: config.simplystream.environment
});

// Connect to database
const db = await createDatabaseConnection({
	url: config.database.url,
	ssl: config.database.ssl,
	pool: { max: config.database.poolSize }
});

Secret Management

AWS Secrets Manager

import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager';

async function getSecret(secretName: string): Promise<string> {
	const client = new SecretsManagerClient({ region: 'us-west-2' });

	const command = new GetSecretValueCommand({ SecretId: secretName });
	const response = await client.send(command);

	return response.SecretString!;
}

// Load secrets at startup
const secrets = {
	apiKey: await getSecret('simplystream/api-key'),
	dbPassword: await getSecret('database/password'),
	jwtSecret: await getSecret('auth/jwt-secret')
};

Google Cloud Secret Manager

import { SecretManagerServiceClient } from '@google-cloud/secret-manager';

async function getSecret(name: string): Promise<string> {
	const client = new SecretManagerServiceClient();

	const [version] = await client.accessSecretVersion({
		name: `projects/${PROJECT_ID}/secrets/${name}/versions/latest`
	});

	return version.payload?.data?.toString() || '';
}

// Usage
const apiKey = await getSecret('simplystream-api-key');

HashiCorp Vault

import vault from 'node-vault';

const client = vault({
	apiVersion: 'v1',
	endpoint: process.env.VAULT_ADDR,
	token: process.env.VAULT_TOKEN
});

async function getSecrets() {
	const result = await client.read('secret/data/simplystream');
	return result.data.data;
}

// Usage
const secrets = await getSecrets();
const apiKey = secrets.SIMPLYSTREAM_API_KEY;

Environment-Specific Configuration

Feature Flags

export const features = {
	enableAnalytics: process.env.ENABLE_ANALYTICS === 'true',
	enableCaching: process.env.ENABLE_CACHING !== 'false',
	maxUploadSize: parseInt(process.env.MAX_UPLOAD_SIZE || '10485760', 10),
	sessionTimeout: parseInt(process.env.SESSION_TIMEOUT || '3600', 10),

	// Environment-specific defaults
	byEnvironment: {
		development: {
			enableAnalytics: false,
			enableCaching: false,
			debug: true
		},
		staging: {
			enableAnalytics: true,
			enableCaching: true,
			debug: false
		},
		production: {
			enableAnalytics: true,
			enableCaching: true,
			debug: false
		}
	}[process.env.NODE_ENV || 'development']
};

Region-Specific Configuration

const regionConfig = {
	'us-west-2': {
		cdnUrl: 'https://cdn-us-west.yourapp.com',
		apiEndpoint: 'https://api-us-west.yourapp.com',
		streamRegion: 'us-west-2'
	},
	'eu-west-1': {
		cdnUrl: 'https://cdn-eu.yourapp.com',
		apiEndpoint: 'https://api-eu.yourapp.com',
		streamRegion: 'eu-west-1'
	}
};

export function getRegionConfig(region: string) {
	return regionConfig[region] || regionConfig['us-west-2'];
}

Best Practices

1. Never Commit Secrets

# .gitignore
.env
.env.local
.env.*.local
.env.development
.env.staging
.env.production
secrets/
*.pem
*.key

2. Use Environment Variables for Everything

// Good
const apiKey = process.env.SIMPLYSTREAM_API_KEY;

// Bad - hardcoded
const apiKey = 'sk_live_123456789';

3. Validate on Startup

function validateEnvironment() {
	const required = ['API_KEY', 'DATABASE_URL', 'REDIS_URL'];

	const missing = required.filter((key) => !process.env[key]);

	if (missing.length > 0) {
		console.error('Missing required environment variables:', missing);
		process.exit(1);
	}
}

validateEnvironment();

4. Use TypeScript for Type Safety

declare global {
	namespace NodeJS {
		interface ProcessEnv {
			NODE_ENV: 'development' | 'staging' | 'production';
			PORT: string;
			SIMPLYSTREAM_API_KEY: string;
			SIMPLYSTREAM_PROJECT_ID: string;
			DATABASE_URL: string;
			REDIS_URL: string;
		}
	}
}

5. Document All Variables

Create env.example:

# SimplyStream Configuration
SIMPLYSTREAM_API_KEY=sk_test_your_key_here
SIMPLYSTREAM_PROJECT_ID=proj_your_project_id
SIMPLYSTREAM_ENVIRONMENT=development

# Database
DATABASE_URL=postgresql://user:password@localhost:5432/dbname

# Redis
REDIS_URL=redis://localhost:6379

# Security
SESSION_SECRET=generate_random_string_here
JWT_SECRET=generate_random_string_here

Deployment

Docker

# Build-time variables
ARG NODE_ENV=production
ENV NODE_ENV=$NODE_ENV

# Runtime variables from environment
ENV SIMPLYSTREAM_API_KEY=${SIMPLYSTREAM_API_KEY}
ENV DATABASE_URL=${DATABASE_URL}

Kubernetes

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  NODE_ENV: production
  PORT: '3000'
---
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
stringData:
  SIMPLYSTREAM_API_KEY: sk_live_xxxxx
  DATABASE_URL: postgresql://...

CI/CD

# GitHub Actions
env:
  NODE_ENV: production
  SIMPLYSTREAM_API_KEY: ${{ secrets.SIMPLYSTREAM_API_KEY }}
  DATABASE_URL: ${{ secrets.DATABASE_URL }}

Next Steps