# Deploying on Kubernetes

This guide shows how to run EventSourcingDB **in a Kubernetes cluster** using a **production-ready configuration**. It provides a reference manifest and explains the **most important settings and their implications**.

You should already have a Kubernetes cluster, a configured `kubectl` context, and an existing namespace. This guide assumes basic knowledge of Kubernetes concepts such as Pods, StatefulSets, Services, and PersistentVolumeClaims.

## Reference Manifest

The following manifest shows how to deploy EventSourcingDB in a **single-replica setup** using HTTP. The configuration uses a **PersistentVolumeClaim** for durable storage and passes secrets and configuration via arguments:

```yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: esdb
  namespace: <NAMESPACE>
spec:
  serviceName: esdb
  replicas: 1
  selector:
    matchLabels:
      app: esdb
  template:
    metadata:
      labels:
        app: esdb
    spec:
      securityContext:
        fsGroup: 101
      containers:
      - name: esdb
        image: thenativeweb/eventsourcingdb:<VERSION>
        ports:
        - name: http
          containerPort: 3000
        args: [
          "run",
          "--api-token", "<API_TOKEN>",
          "--license-string", "<LICENSE_STRING>",
          "--data-directory", "/var/lib/esdb",
          "--http-enabled",
          "--https-enabled=false"
        ]
        volumeMounts:
        - name: esdb-data
          mountPath: /var/lib/esdb
        resources:
          requests:
            memory: "256Mi"
            cpu: "1000m"
          limits:
            memory: "1Gi"
            cpu: "4000m"
        readinessProbe:
          httpGet:
            path: /api/v1/ping
            port: http
          initialDelaySeconds: 1
        livenessProbe:
          httpGet:
            path: /api/v1/ping
            port: http
          initialDelaySeconds: 1
      automountServiceAccountToken: false
  volumeClaimTemplates:
  - metadata:
      name: esdb-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: do-block-storage
      resources:
        requests:
          storage: 100Gi
---
apiVersion: v1
kind: Service
metadata:
  name: esdb
  namespace: <NAMESPACE>
spec:
  clusterIP: None
  ports:
  - name: http
    port: 3000
    targetPort: http
  selector:
    app: esdb
```

Replace:

- **`<NAMESPACE>`** with the namespace in which to deploy EventSourcingDB
- **`<VERSION>`** with the desired version of the Docker image (e.g., `1.2.0`)
- **`<API_TOKEN>`** with a secure string (at least 32 characters, mixed-case letters and digits)
- **`<LICENSE_STRING>`** with your commercial license string

> **Single Replica Only**
>
> EventSourcingDB **does not yet support clustered operation**. You must set `replicas: 1` in your deployment. **Multi-replica support will be added in a future version.**

## Design Considerations

### Using HTTP

This example **uses HTTP** (port 3000) and **explicitly disables HTTPS**. This is acceptable in private cluster environments where access is tightly controlled via NetworkPolicies or internal-only services.

> **Internal Access Only**
>
> **Do not expose this HTTP-based deployment** to the public internet. It is your responsibility to **restrict access at the network level**.

### Persistent Storage

The deployment uses a `PersistentVolumeClaim` named `esdb-data`, which mounts to `/var/lib/esdb` inside the container. This is **required for durability**.

The `clusterIP: None` setting creates a **headless service**, which allows direct access to the Pod without load balancing. This is r**equired by the StatefulSet for stable network identity**.

> **DigitalOcean-Specific Storage Class**
>
> The `storageClassName` is set to `do-block-storage`, which is a **DigitalOcean-specific storage class**. If you're using a different Kubernetes provider, adjust the value to match your environment.

The requested size is `100Gi`, which should be **adjusted based on your expected event volume**.

### Resource Configuration

The resource requests and limits are intentionally generous:

```yaml
requests:
  memory: "256Mi"
  cpu: "1000m"
limits:
  memory: "1Gi"
  cpu: "4000m"
```

These values are examples. Adjust them **according to your cluster capacity and workload profile**.

### API Token and License

Both the API token and the commercial license are passed as arguments via `--api-token` and `--license-string`. This keeps configuration simple and avoids the need for mounted secrets or files.

If you prefer, you can **inject these values using Kubernetes secrets and environment variables**, but this is out of scope for this guide.

### Probes

Readiness and liveness probes use the endpoint `/api/v1/ping`. This ensures the container is only marked ready **after the database is up and responsive**.

## Key Takeaways

This Kubernetes deployment:

- Uses a **pinned Docker image version**
- Stores data in a **persistent volume** (`/var/lib/esdb`)
- **Uses HTTP** for internal-only communication
- **Disables HTTPS** explicitly
- Requires **exactly one replica** (`replicas: 1`)
- Passes the license and token as **runtime arguments**
- Sets up **liveness and readiness probes**
- Is **isolated to a specific namespace** and tightly scoped

Adapt the manifest to your infrastructure and workload. This example is optimized for internal, single-node deployments in managed Kubernetes environments.
