---
title: Deployment Guide
product: trilio-site-recovery-for-kubernetes
doc_type: guide
version: 0.2.0
source: git2docs (code-derived, validation-filtered)
canonical: https://docs-tsr.trilio.io/trilio-site-recovery-for-kubernetes/site-recovery/deployment-guide
---

# Deployment Guide

_Production deployment, RBAC setup, resource limits, and multi-cluster configuration_

## Overview

This page walks you through deploying Trilio Site Recovery on OpenShift in production: installing the operator via OLM, provisioning zone credentials, creating a ProtectionZone, and verifying that the full control plane stack is healthy across all three clusters. It also covers RBAC setup, resource limits, and the configuration knobs most relevant to a multi-cluster production environment. By the end you will have a running TSR-Manager cluster, two workload clusters joined to a ProtectionZone, and the DRBD node agent running on every worker node — ready for VM protection.

## Configuration

All configuration is expressed through Kubernetes custom resources and the ProtectionZone spec. The Helm charts are embedded in the operator binary and are not a customer-facing surface — you do not set chart values directly.

---

### ProtectionZone spec fields

| Field | Type | Default | Effect |
|---|---|---|---|
| `spec.storageBackendMode` | string | _(required)_ | Must be `DRBD`. `Linstor` is rejected at admission. |
| `spec.displayName` | string | _(required)_ | Human-friendly name shown in the TSR web console (5–253 chars). |
| `spec.clusters[].name` | string | _(required)_ | Operator-facing identifier for this cluster slot within the zone (1–63 chars). |
| `spec.clusters[].clusterID` | string | _(required)_ | Deployment slot: `cluster1` or `cluster2`. Both slots must be occupied. |
| `spec.clusters[].distributionName` | string | `RHEL-CoreOS-9` | Selects the DRBD kernel-module loader image family. `RHEL-CoreOS-10` is accepted but not validated in Tech Preview. |
| `spec.clusters[].kubeconfigSecretRef.name` | string | _(required)_ | Name of the Secret in the zone namespace holding the cluster kubeconfig. |
| `spec.clusters[].kubeconfigSecretRef.key` | string | _(required)_ | Key within the Secret (typically `kubeconfig`). |
| `spec.nodeAgent.startupDeadlineSeconds` | integer | `120` | How long (10–3600 s) the node agent keeps the `siterecovery.trilio.io/not-ready:NoSchedule` taint on its node during startup. Changing this value rolls the agent DaemonSet. |
| `spec.logging.level` | string | _(required if logging set)_ | Runtime log level for all zone components: `error`, `info`, `debug`, or `trace`. Takes effect within ~15 s without pod restarts, propagated via the `site-recovery-logging` ConfigMap. |
| `spec.logging.controlPlaneLevel` | string | _(inherits `level`)_ | Overrides `level` for control-plane managers only. |
| `spec.logging.nodeAgentLevel` | string | _(inherits `level`)_ | Overrides `level` for DRBD node agents only. |
| `spec.hooks.jobTTLSeconds` | integer | `3600` | How long a succeeded hook Job is retained on workload clusters (minimum 60 s). |
| `spec.hooks.failedJobRetentionSeconds` | integer | `604800` | How long a failed or timed-out hook Job is retained (minimum 60 s; 7 days default). |

---

### Node agent resource limits

The node agent DaemonSet runs on every schedulable worker node. Its default resource allocation is:

| | CPU | Memory |
|---|---|---|
| Request | 10m | 64Mi |
| Limit | 500m | 256Mi |

These are the values TSR is tested with. If your workload nodes require different limits, contact Trilio support — the values are set by the embedded workload chart and cannot be overridden through the ProtectionZone CR.

---

### DRBD replication policy

The ProtectionZone controller automatically creates a `DRBDReplicationPolicy` named `<zoneName>-default` in the zone namespace with `isDefault: true`. Protocol C (synchronous, RPO=0) is the only supported protocol — Protocol A is rejected at admission. You do not create or modify replication policies.

Key policy defaults (read-only reference):

| Field | Default | Notes |
|---|---|---|
| `spec.drbdProtocol` | `C` | Only supported value in Tech Preview |
| `spec.replicationMode` | `Synchronous` | Only supported value |
| `spec.resyncConfig.rate` | `100M` | Maximum resync rate |
| `spec.diskConfig.fencing` | `resource-only` | DRBD fencing policy |
| `spec.rpo.alertThresholdSeconds` | `30` | Lag threshold for RPO alerts |

---

### Runtime log level

You can change the log level of any zone component without a pod restart by editing the ProtectionZone spec:

```bash
oc --context tsr-manager patch pz my-zone -n dr-my-zone \
  --type merge -p '{"spec":{"logging":{"level":"debug"}}}'
```

The change propagates to the `site-recovery-logging` ConfigMap in each component's namespace and takes effect within approximately 15 seconds. Accepted values: `error`, `info`, `debug`, `trace`.

You can also edit the `site-recovery-logging` ConfigMap directly in any component namespace for per-component overrides without going through the ProtectionZone CR:

```bash
# On the TSR-Manager cluster, in the zone namespace
oc --context tsr-manager edit configmap site-recovery-logging -n dr-my-zone
```

The ConfigMap keys are:
- `level` — global level for all components reading this ConfigMap
- `level.control-plane` — override for the control-plane manager
- `level.drbd-node-agent` — override for the node agent
- `level.protectionzone` — override for the ProtectionZone controller

---

### Zone credential expiry

Credentials minted by `tsrctl zone-credential create` have a default lifetime of one year. The zone raises a `CredentialExpiring` advisory condition on `CredentialsValid` 30 days before the token expires (`credentialExpiryWarning` defaults to `720h` in the ProtectionZone controller). Inspect expiry:

```bash
oc --context tsr-manager get pz my-zone -n dr-my-zone \
  -o jsonpath='{.status.clusters[*].credentialExpiresAt}'
```

Rotate before expiry using `tsrctl zone-credential rotate` (see the Rotate credentials section under Usage).
