---
title: "Docker"
description: "Docker documentation for Ring Platform"
locale: "en"
---
# Docker Deployment

Ring Platform can be deployed using Docker containers with full Kubernetes orchestration. This guide covers both development and production deployments.

## Prerequisites

### System Requirements
- Docker 20.10+
- Docker Compose 2.0+
- Kubernetes cluster (for production)
- 4GB RAM minimum, 8GB recommended
- 20GB disk space

### Network Requirements
- Outbound HTTPS access for package downloads
- Inbound access on ports 80/443 (production)
- Access to Forgejo OCI (registry.ringdom.org on ring-mesh)

## Development Deployment

### Docker Compose (Development)

{`services:
  ring-platform:
    build:
      context: .
      dockerfile: Dockerfile
      platform: linux/amd64
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
      - NEXTAUTH_URL=http://localhost:3000
      # Same-origin /api — no separate API host required in alpha
    volumes:
      - .:/app
      - /app/node_modules
    restart: unless-stopped

  postgres:
    image: postgres:15
    environment:
      - POSTGRES_DB=ring_platform
      - POSTGRES_USER=ring
      - POSTGRES_PASSWORD=secure_password
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

volumes:
  postgres_data:`}

### Quick Development Setup

Clone repository Start development environment View logs Access application

{`git clone https://github.com/connectplatform/ring.git
cd ring/ring-platform.org

docker-compose -f docker-compose.dev.yml up -d

docker-compose logs -f ring-platform

open http://localhost:3000`}

## Production Deployment

### Critical Build Requirements

> [!WARNING]
> **CRITICAL**: Never use server-side syntax highlighting or Mermaid.js imports at top level - causes 30-second load times and 503 timeouts!

#### Platform Specification
Always build with explicit platform for Kubernetes AMD64 nodes

{`docker build --platform linux/amd64 \
  -t registry.ringdom.org/ringdom-clones/ring:v0.9.18-ring-platform.org-amd64 \
  -f Dockerfile .`}

#### Docker Configuration
- **DO NOT** exclude `docs/` directory from `.dockerignore`
- **MUST** copy `lib/` and `docs/` directories in Dockerfile runtime stage
- **Use dynamic imports** for client-side libraries like Mermaid.js

### Build & Deploy Process

#### Step 1: Build Docker Image

{`cd ring-platform.org
docker build --platform linux/amd64 \
  -t registry.ringdom.org/ringdom-clones/ring:v0.9.18-ring-platform.org-amd64 \
  -f Dockerfile .`}

#### Step 2: Push to Registry

{`docker push registry.ringdom.org/ringdom-clones/ring:v0.9.18-ring-platform.org-amd64`}

#### Step 3: Deploy to Kubernetes
ssh k8s-control-01 'kubectl -n ring-platform-org set image \

{`deployment/ring-platform \
  ring-platform=registry.ringdom.org/ringdom-clones/ring:v0.9.18-ring-platform.org-amd64'`}

#### Step 4: Monitor Deployment

{`ssh k8s-control-01 'kubectl -n ring-platform-org rollout status deployment/ring-platform'
ssh k8s-control-01 'kubectl -n ring-platform-org get pods -l app=ring-platform'`}

---

# Kubernetes Deployment

## Overview

Ring Platform is deployed on Kubernetes using HAProxy as an external load balancer and MetalLB for internal service load balancing. This provides enterprise-grade scalability, high availability, and traffic management.

## Prerequisites

- Kubernetes cluster v1.29+
- HAProxy LoadBalancer installed (10.10.0.30)
- MetalLB configured with IP pool (10.10.0.40-10.10.0.50)
- Cilium CNI with WireGuard encryption
- NGINX Ingress Controller (optional)

## DNS Configuration

Configure your DNS provider to point `ring-platform.org` to your public IPs:

Primary setup (Recommended) Advanced setup with load balancing

{`ring-platform.org      A     195.95.233.69    # HAProxy LoadBalancer
www.ring-platform.org  CNAME ring-platform.org

ring-platform.org      A     195.95.233.69    # Primary (HAProxy)
ring-platform.org      A     195.95.233.15    # Secondary (MetalLB)`}

## Namespace Setup

Create Ring namespace Set as default for deployment

{`kubectl create namespace ring-platform-org

kubectl config set-context --current --namespace=ring-platform-org`}

## Ring Platform Application Deployment

ring-platform-deployment.yaml Ring Platform Service with MetalLB

{`apiVersion: apps/v1
kind: Deployment
metadata:
  name: ring-platform
  namespace: ring-platform-org
  labels:
    app: ring-platform
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ring-platform
  template:
    metadata:
      labels:
        app: ring-platform
    spec:
      containers:
      - name: ring-platform
        image: registry.ringdom.org/ringdom-clones/ring:v0.9.18-ring-platform.org-amd64
        ports:
        - containerPort: 3000
          name: http
        env:
        - name: NODE_ENV
          value: "production"
        - name: NEXTAUTH_URL
          value: "https://ring-platform.org"
        resources:
          requests:
            memory: "512Mi"
            cpu: "250m"
          limits:
            memory: "1Gi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /api/health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
        readinessProbe:
          httpGet:
            path: /api/health
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 3
---
apiVersion: v1
kind: Service
metadata:
  name: ring-platform-service
  namespace: ring-platform-org
  annotations:
    metallb.universe.tf/loadBalancerIPs: 10.10.0.41
spec:
  selector:
    app: ring-platform
  ports:
  - name: http
    port: 80
    targetPort: 3000
    protocol: TCP
  - name: https
    port: 443
    targetPort: 3000
    protocol: TCP
  type: LoadBalancer
  loadBalancerIP: 10.10.0.41`}

## NGINX Ingress Configuration

ring-platform-ingress.yaml Main application Documentation subdomain

{`apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ring-platform-ingress
  namespace: ring-platform-org
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/proxy-body-size: "50m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
spec:
  tls:
  - hosts:
    - ring-platform.org
    - www.ring-platform.org
    - docs.ring-platform.org
    secretName: ring-platform-tls
  rules:
  - host: ring-platform.org
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ring-platform-service
            port:
              number: 80
  - host: www.ring-platform.org
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ring-platform-service
            port:
              number: 80
  - host: docs.ring-platform.org
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ring-platform-service
            port:
              number: 80`}

## Secrets and ConfigMaps

ring-platform-secrets.yaml Base64 encoded values - generate these securely for your environment ring-platform-config.yaml

{`apiVersion: v1
kind: Secret
metadata:
  name: ring-platform-secrets
  namespace: ring-platform-org
type: Opaque
data:
  database-url: 
  nextauth-secret: 
  firebase-key: 
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: ring-platform-config
  namespace: ring-platform-org
data:
  NODE_ENV: "production"
  NEXTAUTH_URL: "https://ring-platform.org"
  LOG_LEVEL: "info"
  METRICS_ENABLED: "true"`}

## Deployment Commands

### Initial Deployment

1. Apply all configurations 2. Check deployment status 3. Check MetalLB IP allocation 4. Test external access 5. Check logs

{`kubectl apply -f ring-platform-deployment.yaml
kubectl apply -f ring-platform-ingress.yaml
kubectl apply -f ring-platform-secrets.yaml
kubectl apply -f ring-platform-config.yaml

kubectl get pods -n ring-platform-org
kubectl get svc -n ring-platform-org
kubectl get ingress -n ring-platform-org

kubectl get svc -n ring-platform-org -o wide

curl -H "Host: ring-platform.org" http://195.95.233.69
curl -H "Host: docs.ring-platform.org" http://195.95.233.69

kubectl logs -l app=ring-platform -n ring-platform-org --tail=50`}

### Updates and Rollbacks

Update to new version Check rollout status Rollback if needed

{`kubectl set image deployment/ring-platform \
  ring-platform=registry.ringdom.org/ringdom-clones/ring:v0.9.18-ring-platform.org-amd64 \
  -n ring-platform-org

kubectl rollout status deployment/ring-platform -n ring-platform-org

kubectl rollout undo deployment/ring-platform -n ring-platform-org`}

## Traffic Flow Architecture

```
Internet → DNS (ring-platform.org)
    ↓
Public IPs (195.95.233.69 / 195.95.233.15)
    ↓
HAProxy (10.10.0.30) or MetalLB (10.10.0.41-42)
    ↓
NGINX Ingress Controller
    ↓
Ring Platform Services (Pods)
    ↓
Application Containers (Next.js)
```

## Monitoring and Troubleshooting

### Production Health Checks

Application health Documentation pages Pod status Service status Ingress status

{`curl https://ring-platform.org/api/health

curl https://ring-platform.org/en/docs/architecture

kubectl get pods -n ring-platform-org -l app=ring-platform

kubectl get svc -n ring-platform-org

kubectl describe ingress ring-platform-ingress -n ring-platform-org`}

### Common Deployment Issues

#### 404 Errors on /docs Pages
Check if docs directory is included in Docker build Verify ingress configuration

{`kubectl exec -it  -n ring-platform-org -- ls -la /app/docs/

kubectl describe ingress ring-platform-ingress -n ring-platform-org`}

#### 503 Timeouts on Diagram Pages
Check for Mermaid.js errors in logs Verify dynamic imports are working

{`kubectl logs -l app=ring-platform -n ring-platform-org --tail=100 | grep -i mermaid

kubectl logs -l app=ring-platform -n ring-platform-org --tail=100 | grep -i "mermaid"`}

#### Syntax Highlighting / Docs Compile Slow
Code blocks are highlighted **once on the server** (`highlightCodeToHtml` + cached Shiki highlighter). Fenced markdown is converted to `` via `rehypeCodeFenceToMdx` — there is no client-side Shiki pass.

If docs pages are slow on first load, check server logs for highlight errors or missing language bundles:

{`kubectl logs -l app=ring-platform -n ring-platform-org --tail=100 | grep -i "shiki\\|syntax\\|highlight"`}

### Performance Monitoring

Check pod resource usage Monitor response times Check for memory issues

{`kubectl top pods -n ring-platform-org

kubectl logs -l app=ring-platform -n ring-platform-org --tail=50 | grep -E "(GET|POST).*(200|500|503)"

kubectl describe pod  -n ring-platform-org | grep -A 10 "Containers:"`}

## Scaling and Updates

### Horizontal Scaling
Scale Ring Platform application Check scaling status

{`kubectl scale deployment ring-platform --replicas=3 -n ring-platform-org

kubectl get pods -n ring-platform-org -l app=ring-platform`}

### Rolling Updates
Update with new version Check rollout status Rollback if needed

{`kubectl set image deployment/ring-platform \
  ring-platform=registry.ringdom.org/ringdom-clones/ring:v0.9.19-ring-platform.org-amd64 \
  -n ring-platform-org

kubectl rollout status deployment/ring-platform -n ring-platform-org

kubectl rollout undo deployment/ring-platform -n ring-platform-org`}

## Backup and Recovery

Backup configurations Backup secrets (careful with sensitive data) Restore

{`kubectl get all -n ring-platform-org -o yaml > ring-platform-backup.yaml

kubectl get secrets -n ring-platform-org -o yaml > ring-platform-secrets-backup.yaml

kubectl apply -f ring-platform-backup.yaml`}

## Security Considerations

### Image Security
- Use specific image tags, avoid 'latest'
- Scan images for vulnerabilities before deployment
- Use private registry with authentication

### Network Security
- Configure network policies between namespaces
- Use secrets for sensitive environment variables
- Enable pod security standards

### Access Control
- Implement RBAC for Kubernetes resources
- Use service account tokens with minimal permissions
- Regularly rotate credentials and certificates

## Maintenance & Operations

### Container Runtime Cleanup

Kubernetes doesn't provide native kubectl commands for container runtime maintenance. Use these Legiox-approved procedures for node-level cleanup:

#### Docker Image Cleanup on Nodes
On control plane node On worker nodes (via SSH) Check disk usage after cleanup

{`sudo docker image prune -a --filter "until=48h" -f
sudo docker system prune -f

ssh k8s-worker-01 "sudo docker image prune -a --filter 'until=48h' -f && sudo docker system prune -f"
ssh k8s-worker-02 "sudo docker image prune -a --filter 'until=48h' -f && sudo docker system prune -f"

df -h`}

#### Automated Cleanup Script
Legiox Kubernetes Node Maintenance Script Usage: ./k8s-node-maintenance.sh [node1] [node2] ...

{`#!/bin/bash

NODES=("$@")
if [ ${#NODES[@]} -eq 0 ]; then
    NODES=("k8s-control-01" "k8s-worker-01" "k8s-worker-02")
fi

echo "🛡️ Legiox Kubernetes Node Maintenance Starting..."

for node in "${NODES[@]}"; do
    echo "🔧 Cleaning node: $node"
    ssh "$node" "
        echo 'Stopping inactive containers...'
        docker stop \$(docker ps -q -f status=exited) 2>/dev/null || true

        echo 'Removing stopped containers...'
        docker rm \$(docker ps -q -f status=exited) 2>/dev/null || true

        echo 'Removing dangling images...'
        docker image prune -f

        echo 'Removing unused images older than 7 days...'
        docker image prune -a --filter 'until=168h' -f

        echo 'System-wide cleanup...'
        docker system prune -f

        echo 'Disk usage after cleanup:'
        df -h /
    "
    echo "✅ Node $node cleaned"
done

echo "🎯 Legiox maintenance complete!"`}

### Kubernetes Resource Cleanup

#### Remove Stuck/Terminating Pods
Force delete stuck terminating pod Remove all failed pods Remove completed jobs

{`kubectl delete pod  -n ring-platform-org --force --grace-period=0

kubectl delete pods --field-selector status.phase=Failed -n ring-platform-org

kubectl delete jobs --field-selector status.successful=1 -n ring-platform-org`}

#### Clean Up Unused Resources
Remove unused persistent volume claims Remove unused configmaps and secrets (be careful!) Clean up old replicasets from rollouts

{`kubectl delete pvc --field-selector status.phase=Lost -n ring-platform-org

kubectl get configmaps -n ring-platform-org
kubectl get secrets -n ring-platform-org

kubectl delete rs --field-selector status.replicas=0 -n ring-platform-org`}

### Node Maintenance

#### Check Node Resource Usage
Overall cluster resource usage Pod resource usage by namespace Check node capacity and allocation

{`kubectl top nodes

kubectl top pods -n ring-platform-org

kubectl describe nodes | grep -A 10 "Allocated resources"`}

#### Node Disk Cleanup
Check disk usage on all nodes Clean up kubelet logs (if needed)

{`for node in k8s-control-01 k8s-worker-01 k8s-worker-02; do
    echo "=== $node ==="
    ssh $node "df -h && echo && docker system df"
done

ssh k8s-control-01 "find /var/log/containers -name '*.log' -mtime +7 -delete"
ssh k8s-worker-01 "find /var/log/containers -name '*.log' -mtime +7 -delete"
ssh k8s-worker-02 "find /var/log/containers -name '*.log' -mtime +7 -delete"`}

### Database Maintenance

#### PostgreSQL Cleanup
Connect to PostgreSQL pod Vacuum and analyze tables Check table sizes Reindex if needed

{`kubectl exec -it postgres-7c5c6fc797-wn8j5 -n ring-platform-org -- psql -U ring_user -d ring_platform

VACUUM ANALYZE;

SELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;

REINDEX DATABASE ring_platform;`}

#### Backup Verification
List recent backups Check backup logs

{`kubectl get jobs -n ring-platform-org | grep backup

kubectl logs job/ring-platform-backup-20251018 -n ring-platform-org`}

### Monitoring & Alerting

#### Check System Health
Pod status overview Check for restarts Resource usage alerts

{`kubectl get pods -n ring-platform-org -o wide

kubectl get pods -n ring-platform-org --field-selector status.phase=Running -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.containerStatuses[0].restartCount}{"\n"}{end}'

kubectl top pods -n ring-platform-org --sort-by=cpu
kubectl top pods -n ring-platform-org --sort-by=memory`}

#### Log Aggregation
Recent application logs PostgreSQL logs

{`kubectl logs -l app=ring-platform -n ring-platform-org --tail=100 --since=1h

kubectl logs postgres-7c5c6fc797-wn8j5 -n ring-platform-org --tail=50`}

### Automated Maintenance Schedule

#### Daily Tasks
Clean up completed jobs and failed pods

{`kubectl delete jobs --field-selector status.successful=1 -n ring-platform-org
kubectl delete pods --field-selector status.phase=Failed -n ring-platform-org`}

#### Weekly Tasks
Docker image cleanup on nodes PostgreSQL maintenance

{`for node in k8s-control-01 k8s-worker-01 k8s-worker-02; do
    ssh $node "docker image prune -a --filter 'until=168h' -f"
done

kubectl exec -it postgres-7c5c6fc797-wn8j5 -n ring-platform-org -- psql -U ring_user -d ring_platform -c "VACUUM ANALYZE;"`}

#### Monthly Tasks
Full system cleanup Archive old logs

{`kubectl delete rs --field-selector status.replicas=0 -n ring-platform-org
kubectl delete pvc --field-selector status.phase=Lost -n ring-platform-org

for node in k8s-control-01 k8s-worker-01 k8s-worker-02; do
    ssh $node "find /var/log/containers -name '*.log' -mtime +30 -exec gzip {} \;"
done`}

## Version History

- **v1.6.2**: Unified server-only Shiki (`rehypeCodeFenceToMdx` → async ``); removed client re-highlight and `@shikijs/rehype`
- **v0.9.17**: Fixed Mermaid dynamic imports, resolved server-side rendering timeouts
- **v0.9.16**: Added Docker deployment guide, fixed Mermaid SSR issues
- **v0.9.15**: Added docs directory to Docker image, fixed .dockerignore configuration
- **v0.9.14**: Added Callout components and EnhanceCallouts
- **v0.9.13**: Documentation system with Shiki, Mermaid, and Callouts

This Kubernetes deployment provides enterprise-grade scalability, high availability, and robust traffic management for the Ring Platform using HAProxy and MetalLB load balancers.
