Skip to main content
Swytch Documentation
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Deployment

This guide covers deploying Swytch in production environments, including container images, systemd services, and Kubernetes.

Container Images

Official Docker images are available on GitHub Container Registry:

# Latest stable release
docker pull ghcr.io/bottledcode/swytch:latest

# Specific version
docker pull ghcr.io/bottledcode/swytch:1.0.0

Running with Docker

# Redis mode (in-memory)
docker run -d \
  --name swytch-redis \
  -p 6379:6379 \
  ghcr.io/bottledcode/swytch:latest \
  redis --bind 0.0.0.0 --maxmemory 4gb

# Redis mode (persistent)
docker run -d \
  --name swytch-redis \
  -p 6379:6379 \
  -v /data/swytch:/data \
  ghcr.io/bottledcode/swytch:latest \
  redis --persistent --db-path /data/redis.db --bind 0.0.0.0 --maxmemory 4gb

# Memcached mode
docker run -d \
  --name swytch-memcached \
  -p 11211:11211 \
  ghcr.io/bottledcode/swytch:latest \
  memcached -l 0.0.0.0 -m 4096

Docker Compose

services:
  swytch:
    image: ghcr.io/bottledcode/swytch:latest
    command: redis --persistent --db-path /data/redis.db --bind 0.0.0.0 --maxmemory 4gb --metrics-port 9090
    ports:
      - "6379:6379"
      - "9090:9090"
    volumes:
      - swytch-data:/data
    deploy:
      resources:
        limits:
          memory: 5G
        reservations:
          memory: 4G
    restart: unless-stopped

volumes:
  swytch-data:

Authentication

To enable password authentication, use --requirepass. Since the container image is built FROM scratch (no shell), you cannot use shell variable expansion. Instead:

Docker Compose: Use host environment variable interpolation:

services:
  swytch:
    image: ghcr.io/bottledcode/swytch:latest
    command:
      - redis
      - --bind=0.0.0.0
      - --requirepass=${REDIS_PASSWORD}
    ports:
      - "6379:6379"

Set REDIS_PASSWORD in your environment or .env file before running docker compose up.

Kubernetes: Use a Secret with environment variable substitution:

env:
  - name: REDIS_PASSWORD
    valueFrom:
      secretKeyRef:
        name: swytch-secrets
        key: password
args:
  - redis
  - --bind=0.0.0.0
  - --requirepass=$(REDIS_PASSWORD)

Kubernetes substitutes $(REDIS_PASSWORD) at pod creation time—no shell required.

Systemd

For bare-metal or VM deployments, use systemd to manage Swytch as a service.

Example Unit File

Create /etc/systemd/system/swytch.service:

[Unit]
Description=Swytch Redis-compatible cache server
Documentation=https://bottledcode.github.io/swytch/
After=network.target

[Service]
Type=simple
User=swytch
Group=swytch
ExecStart=/usr/local/bin/swytch redis \
    --persistent \
    --db-path /var/lib/swytch/redis.db \
    --bind 127.0.0.1 \
    --maxmemory 4gb \
    --metrics-port 9090
ExecStop=/bin/kill -SIGTERM $MAINPID
Restart=on-failure
RestartSec=5

# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/swytch
PrivateTmp=true

# Resource limits
LimitNOFILE=65535
MemoryMax=5G

[Install]
WantedBy=multi-user.target

Installation

# Create service user
sudo useradd --system --no-create-home --shell /usr/sbin/nologin swytch

# Create data directory
sudo mkdir -p /var/lib/swytch
sudo chown swytch:swytch /var/lib/swytch

# Install binary
sudo cp swytch /usr/local/bin/
sudo chmod +x /usr/local/bin/swytch

# Enable and start service
sudo systemctl daemon-reload
sudo systemctl enable swytch
sudo systemctl start swytch

# Check status
sudo systemctl status swytch
sudo journalctl -u swytch -f

Kubernetes

Manifests

Example Kubernetes manifests are shown below. Adapt them to your environment.

Basic StatefulSet

For persistent deployments, use a StatefulSet with a PersistentVolumeClaim:

apiVersion: v1
kind: Service
metadata:
  name: swytch
  labels:
    app: swytch
spec:
  ports:
    - port: 6379
      name: redis
    - port: 9090
      name: metrics
  clusterIP: None
  selector:
    app: swytch
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: swytch
spec:
  serviceName: swytch
  replicas: 1
  selector:
    matchLabels:
      app: swytch
  template:
    metadata:
      labels:
        app: swytch
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9090"
    spec:
      terminationGracePeriodSeconds: 30
      containers:
        - name: swytch
          image: ghcr.io/bottledcode/swytch:latest
          args:
            - redis
            - --persistent
            - --db-path=/data/redis.db
            - --bind=0.0.0.0
            - --maxmemory=4gb
            - --metrics-port=9090
          ports:
            - containerPort: 6379
              name: redis
            - containerPort: 9090
              name: metrics
          resources:
            requests:
              memory: "4Gi"
              cpu: "1"
            limits:
              memory: "5Gi"
              cpu: "4"
          volumeMounts:
            - name: data
              mountPath: /data
          readinessProbe:
            tcpSocket:
              port: 6379
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            tcpSocket:
              port: 6379
            initialDelaySeconds: 15
            periodSeconds: 20
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: [ "ReadWriteOnce" ]
        storageClassName: fast-ssd  # Use your NVMe/SSD storage class
        resources:
          requests:
            storage: 100Gi

Resource Planning

Memory

Set resource limits higher than --maxmemory to account for:

  • Go runtime overhead (~100–200MB)
  • Connection buffers (~1KB per client)
  • Temporary allocations during operations

Rule of thumb: Set container/process memory limit to maxmemory + 20% or maxmemory + 512MB, whichever is larger.

maxmemoryRecommended limit
1GB1.5GB
4GB5GB
16GB19GB
64GB77GB

CPU

Swytch scales well with multiple cores. For sizing:

  • Light workloads (<50k ops/sec): 1–2 cores
  • Moderate workloads (50k-200k ops/sec): 2–4 cores
  • Heavy workloads (>200k ops/sec): 4–8 cores

Set CPU requests to your expected baseline and limits higher to handle spikes.

Note
GOMAXPROCS in containers: The --threads flag sets GOMAXPROCS. Go’s runtime doesn’t always correctly detect cgroup CPU limits in containers. If you set a CPU limit (e.g., cpu: "2"), explicitly set --threads=2 to match. Otherwise, Go may spawn more OS threads than your limit allows, causing throttling.

Storage

For persistent mode:

  • Use NVMe or SSD storage classes (not spinning disks)
  • Provision 2-3x your expected data size to allow for growth and defragmentation headroom
  • Monitor disk usage—unlike memory, disk is not bounded by --maxmemory

File Descriptors

Each client connection uses a file descriptor. Set LimitNOFILE (systemd) or container ulimits appropriately:

# Kubernetes
securityContext:
  capabilities:
    add: [ "SYS_RESOURCE" ]
# Or set in the container runtime

For systemd, LimitNOFILE=65535 is usually sufficient.

Health Checks

The simplest and most reliable health check is a TCP connection to the Redis port:

readinessProbe:
  tcpSocket:
    port: 6379
  initialDelaySeconds: 5
  periodSeconds: 10
livenessProbe:
  tcpSocket:
    port: 6379
  initialDelaySeconds: 15
  periodSeconds: 20

This is the recommended approach because the Swytch container image is built FROM scratch and does not include redis-cli or any other tools.

Redis PING (Sidecar Required)

For more thorough checks using redis-cli, you need a sidecar container or to build a custom image that includes it:

readinessProbe:
  exec:
    command:
      - redis-cli
      - ping
  initialDelaySeconds: 5
  periodSeconds: 10

Metrics Endpoint

If metrics are enabled, check the /metrics endpoint:

livenessProbe:
  httpGet:
    path: /metrics
    port: 9090
  initialDelaySeconds: 10
  periodSeconds: 30

Graceful Shutdown

Swytch handles SIGTERM gracefully: it stops accepting new connections, completes in-flight requests, flushes pending writes (in persistent mode), and exits cleanly. The terminationGracePeriodSeconds in the StatefulSet example (30s) is typically enough.

A preStop hook is not required. Kubernetes sends SIGTERM directly to the container, and Swytch handles it correctly. The FROM scratch image contains only the Swytch binary (no shell), so shell-based preStop hooks won’t work without a custom image.