> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ankra.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# OVH Clusters

> Create, manage, and scale Kubernetes clusters on OVH Cloud with Ankra.

Ankra supports provisioning fully managed Kubernetes clusters on [OVH Cloud](https://www.ovhcloud.com/). You can create clusters with configurable control planes, workers, and networking - then scale workers up or down as needed.

***

## Prerequisites

Before creating an OVH cluster, you need two credentials:

<CardGroup cols={2}>
  <Card title="OVH API Credential" icon="key">
    OVH Cloud API credentials (application key, application secret, consumer key, and project ID). See [OVH API Credentials](/platform/credentials/ovh).
  </Card>

  <Card title="SSH Key Credential" icon="lock">
    An SSH public key for server access. You can provide your own or let Ankra generate one. See [SSH Key Credentials](/platform/credentials/ssh-key).
  </Card>
</CardGroup>

***

## Creating an OVH Cluster

### Via the Platform UI

A guided wizard walks you through creating an OVH cluster - select credentials, pick a region, choose instance flavors (general purpose, CPU-optimized, or RAM-optimized), set control plane and worker counts, and launch.

<Steps>
  <Step title="Navigate to Clusters">
    Go to **Clusters** in the Ankra dashboard and click **Create Cluster**.
  </Step>

  <Step title="Select OVH Cloud">
    Choose **OVH Cloud** as the provider.
  </Step>

  <Step title="Select Credentials">
    Pick your OVH API credential and SSH key credential from the dropdowns. You can also create new credentials directly from the wizard.
  </Step>

  <Step title="Choose Region">
    Select an OVH Cloud region (e.g., Gravelines, Strasbourg, Beauharnois, Warsaw, London, Frankfurt). Each region shows the location and country.
  </Step>

  <Step title="Configure Nodes">
    Set your cluster topology:

    * **Bastion** - instance flavor for the SSH bastion (e.g., `b2-7`)
    * **Control Plane** - count and flavor (e.g., 1x `b2-15`)
    * **Workers** - count and flavor (e.g., 2x `b2-15`)

    The wizard shows vCPUs, RAM, disk, and hourly cost for each flavor to help you choose.
  </Step>

  <Step title="Create & Track Progress">
    Click **Create** to start provisioning. A live progress view tracks every step - network creation, bastion setup, control plane provisioning, worker provisioning, Kubernetes installation (kubeadm or k3s), and Ankra Agent setup. The cluster appears with an **offline** state until provisioning completes, then transitions to **online**.
  </Step>
</Steps>

### Managing from the Dashboard

Once your OVH cluster is online, you can manage it directly from the Ankra dashboard:

* **Scale workers** - go to **Cluster Settings** → **General** to scale worker nodes up or down
* **Upgrade Kubernetes** - upgrade the Kubernetes version from cluster settings
* **Deprovision** - delete the cluster and all OVH resources from the **Danger Zone** in cluster settings

### Via the CLI

```bash theme={null}
# Create credentials first
ankra credentials ovh create --name my-ovh-cred --project-id <project-id>
# You will be prompted for application key, application secret, and consumer key

ankra credentials ovh ssh-key create --name my-ssh-key --generate

# Create the cluster
ankra cluster ovh create \
  --name my-cluster \
  --credential-id <ovh-credential-id> \
  --ssh-key-credential-id <ssh-key-credential-id> \
  --region GRA7 \
  --control-plane-count 1 \
  --control-plane-flavor-id b2-15 \
  --worker-count 2 \
  --worker-flavor-id b2-15
```

### Via the API

```bash theme={null}
curl -X POST https://platform.ankra.app/api/v1/clusters/ovh \
  -H "Authorization: Bearer $ANKRA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-cluster",
    "credential_id": "<ovh-credential-id>",
    "ssh_key_credential_id": "<ssh-key-credential-id>",
    "region": "GRA7",
    "control_plane_count": 1,
    "control_plane_flavor_id": "b2-15",
    "worker_count": 2,
    "worker_flavor_id": "b2-15",
    "distribution": "k3s"
  }'
```

Every configuration parameter, the region list, and instance flavors are in the [OVH Reference](/reference/ovh).

***

## Availability Zones

Some OVH regions are *3-AZ*: one region spanning three availability zones with independent power, cooling, and networking. `EU-WEST-PAR` holds `eu-west-par-a`, `eu-west-par-b` and `eu-west-par-c`, and `EU-SOUTH-MIL` holds the equivalent three. Every other region is a single failure domain, so check before you plan around zones.

Two rules come from OVH and shape everything below. An instance's zone is chosen at creation, and a request that names no zone gets whichever zone OVH picks - in practice the same one for every node of a cluster. And an instance's zone is fixed for its lifetime, so re-placing a node means replacing it.

### Find the zones a region has

Zone names are region-scoped, so check the spelling before you use one. Only a region whose type is `region-3-az` accepts zone placement.

```bash theme={null}
ankra cluster ovh regions --credential-id <ovh-credential-id> --with-zones
```

```
Regions available to credential <ovh-credential-id>:
  EU-WEST-PAR      region-3-az    zones: eu-west-par-a, eu-west-par-b, eu-west-par-c
  GRA              region
```

### Spread a new cluster across zones

Pass the zone pool at create. Ankra distributes instances across it deterministically: control planes and etcd spread per role, workers spread per node group, so a three-node database group gets one node in each zone rather than being balanced against unrelated workers.

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh create \
    --name my-cluster \
    --credential-id <ovh-credential-id> \
    --ssh-key-credential-id <ssh-key-credential-id> \
    --region EU-WEST-PAR \
    --availability-zones eu-west-par-a,eu-west-par-b,eu-west-par-c \
    --control-plane-count 3 \
    --control-plane-flavor-id b2-15 \
    --worker-count 3 \
    --worker-flavor-id b2-15
  ```

  ```bash cURL theme={null}
  curl -X POST https://platform.ankra.app/api/v1/clusters/ovh \
    -H "Authorization: Bearer $ANKRA_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "my-cluster",
      "credential_id": "<ovh-credential-id>",
      "ssh_key_credential_id": "<ssh-key-credential-id>",
      "region": "EU-WEST-PAR",
      "availability_zones": ["eu-west-par-a", "eu-west-par-b", "eu-west-par-c"],
      "control_plane_count": 3,
      "control_plane_flavor_id": "b2-15",
      "worker_count": 3,
      "worker_flavor_id": "b2-15",
      "distribution": "k3s"
    }'
  ```
</CodeGroup>

<Warning>
  Spreading across more than one zone requires **at least 3 control planes**. Fewer cannot keep etcd quorum through the loss of a zone, which is the only reason to spread a control plane, so the create is refused rather than quietly producing a cluster that fails on the first zone outage.
</Warning>

Omitting the zones leaves placement to OVH and changes nothing about how clusters behaved before. Clusters in single-zone regions are unaffected by everything on this page.

### Pin a node group to one zone

A node group can be pinned to a single zone instead of spreading. Pin the group that runs zonal storage, because an OVH volume cannot attach from another zone.

```bash theme={null}
ankra cluster ovh node-group add <cluster-id> \
  --name database-par-a \
  --instance-type r3-128 \
  --count 1 \
  --availability-zone eu-west-par-a
```

Day-2 growth follows the cluster's stored zone pool: node group add, node group scale, worker scale, and control plane growth all balance new instances around where the existing ones already are. A group whose nodes all share one zone is treated as pinned and grows in that zone; a group that is already spread keeps spreading.

### Node topology labels

Every OVH node carries the standard Kubernetes topology pair, so zone-aware scheduling works without extra configuration:

| Label                           | Value                                 |
| ------------------------------- | ------------------------------------- |
| `topology.kubernetes.io/zone`   | the zone OVH reports for the instance |
| `topology.kubernetes.io/region` | the cluster's region                  |

The zone comes from what OVH reports for the live instance rather than what was requested, so it is correct even on clusters created before zone placement existed.

On those older clusters Ankra records the zone automatically the next time it reads the instance, but the labels are written by a server sync. Trigger one rather than waiting for it:

```bash theme={null}
ankra cluster reconcile <cluster-id>
kubectl get nodes -L topology.kubernetes.io/zone
```

### Fixing a cluster that is already in one zone

* **Workers - in place.** Add a node group pinned to the target zone, drain the old group, then delete it. No cluster rebuild.
* **Control planes - not in place.** The zone is immutable, Ankra never re-places an existing control plane, and a control plane count change is stopped-cluster-only. A zone-spread control plane on an existing cluster means recreating the cluster.

A cluster created before zone placement existed has no stored zone pool, so a node group added to it without a zone still lands wherever OVH picks. Pin each group explicitly: three zones means three pinned node groups.

### Zone tolerance needs more than node spread

**OVH High Speed block storage is zonal.** It is triple-replicated *within* a single zone and cannot attach from another. A single database pod with a single PersistentVolume is therefore **not** zone-fault-tolerant however the nodes are spread: the volume is the single-zone dependency, and if its zone goes down the pod cannot start anywhere else.

A zone-fault-tolerant stateful workload needs all of:

* **Replication at the application layer** - CloudNativePG or Patroni with one replica per zone, each with its own volume. Node spread gives the replicas somewhere to live; it does not create them.
* **A `WaitForFirstConsumer` StorageClass** so the volume is provisioned in the zone the pod was actually scheduled to, rather than binding first and stranding the pod. Ankra ships `csi-cinder-sc-topology` for exactly this reason, and marks it the default on new OVH clusters. On a cluster created earlier, k3s's `local-path` class is still present and also marked default, so name the class explicitly on anything that matters rather than relying on which default wins:

  ```yaml theme={null}
  spec:
    storageClassName: csi-cinder-sc-topology
  ```
* **`allowedTopologies`** on the StorageClass, or a zone-pinned node group per replica, so a rescheduled pod cannot land where its volume is not.
* **`topologySpreadConstraints`** keyed on `topology.kubernetes.io/zone` for the stateless tiers.

Node spread is necessary but never sufficient.

***

## Node Groups

Node groups let you organize worker nodes into logical groups with independent instance flavors, counts, labels, and taints. Each group can be scaled, re-flavored, and configured independently.

### Via the Platform UI

Navigate to cluster **Settings** > **Nodes** to manage node groups. From this tab you can:

* View all node groups with their instance flavor, count, labels, and taints
* Add new node groups with a name, instance flavor, count, and optional labels/taints
* Scale individual groups up or down (0–100 nodes)
* Upgrade the instance flavor (upgrade only - see [Instance Flavor Changes](#instance-flavor-changes))
* Edit labels and taints per group
* Delete a node group and all its nodes

### List Node Groups

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh node-group list <cluster_id>
  ```

  ```bash cURL theme={null}
  curl https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/node-groups \
    -H "Authorization: Bearer $ANKRA_API_TOKEN"
  ```
</CodeGroup>

Response:

```json theme={null}
{
  "node_groups": [
    {
      "name": "default",
      "instance_type": "b2-15",
      "count": 2,
      "min": 0,
      "max": 100,
      "labels": {},
      "taints": []
    }
  ]
}
```

### Add a Node Group

From the CLI, a node group can be created with its Kubernetes labels and taints in one step:

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh node-group add <cluster_id> \
    --name gpu-workers \
    --instance-type b2-30 \
    --count 2 \
    --labels workload=gpu \
    --taints dedicated=gpu:NoSchedule
  ```

  ```bash cURL theme={null}
  curl -X POST https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/node-groups \
    -H "Authorization: Bearer $ANKRA_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "gpu-workers",
      "instance_type": "b2-30",
      "count": 2,
      "labels": {"workload": "gpu"},
      "taints": [{"key": "dedicated", "value": "gpu", "effect": "NoSchedule"}]
    }'
  ```
</CodeGroup>

### Scale a Node Group

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh node-group scale <cluster_id> default 4
  ```

  ```bash cURL theme={null}
  curl -X PUT https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/node-groups/default/scale \
    -H "Authorization: Bearer $ANKRA_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"count": 4}'
  ```
</CodeGroup>

Node groups can be scaled to 0 nodes. This keeps the group definition but removes all instances.

### Instance Flavor Changes

<Warning>
  Instance flavor upgrades are one-way - you cannot downgrade a node group to a smaller flavor. To use a smaller flavor, create a new node group with the desired flavor and delete the old one.
</Warning>

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh node-group upgrade <cluster_id> default b2-30
  ```

  ```bash cURL theme={null}
  curl -X PUT https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/node-groups/default/instance-type \
    -H "Authorization: Bearer $ANKRA_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"instance_type": "b2-30"}'
  ```
</CodeGroup>

Each node is powered off, resized, and powered back on. This causes brief downtime for workloads on those nodes.

### Update Labels and Taints

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh node-group labels <cluster_id> default --labels env=production,tier=backend
  ankra cluster ovh node-group taints <cluster_id> default --taints dedicated=ml:NoSchedule
  ```

  ```bash cURL theme={null}
  curl -X PUT https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/node-groups/default/labels \
    -H "Authorization: Bearer $ANKRA_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"labels": {"env": "production", "tier": "backend"}}'

  curl -X PUT https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/node-groups/default/taints \
    -H "Authorization: Bearer $ANKRA_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"taints": [{"key": "dedicated", "value": "ml", "effect": "NoSchedule"}]}'
  ```
</CodeGroup>

Labels and taints are applied to every node in the group; passing `--clear` (or an empty value via the API) removes them, and a taint effect defaults to `NoSchedule`.

### Delete a Node Group

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh node-group delete <cluster_id> gpu-workers
  ```

  ```bash cURL theme={null}
  curl -X DELETE https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/node-groups/gpu-workers \
    -H "Authorization: Bearer $ANKRA_API_TOKEN"
  ```
</CodeGroup>

<Warning>
  Deleting a node group removes all its instances. Workloads running on those nodes will be evicted.
</Warning>

### Node Group API Reference

All node-group operations are also available via the REST API - see the [OVH Node Group API](/reference/ovh#node-group-api-reference).

***

## Legacy Worker Scaling

The legacy `scale-workers` and `worker-count` endpoints still work for backward compatibility.

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh workers <cluster_id>
  ankra cluster ovh scale <cluster_id> 4
  ```

  ```bash cURL theme={null}
  curl https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/worker-count \
    -H "Authorization: Bearer $ANKRA_API_TOKEN"

  curl -X POST https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/scale-workers \
    -H "Authorization: Bearer $ANKRA_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"worker_count": 4}'
  ```
</CodeGroup>

<Note>
  For new clusters, prefer using [Node Groups](#node-groups) for more granular control.
</Note>

***

## Upgrading Kubernetes Version

You can upgrade the Kubernetes (k3s) version on all nodes in an OVH cluster. Upgrades are applied to control plane nodes first, then workers.

<Warning>
  * Only k3s clusters are supported for version upgrades.
  * Downgrades are not supported - k3s downgrades require an etcd snapshot restore.
  * You can only upgrade one minor version at a time (e.g., v1.33.x to v1.34.x, not v1.33.x to v1.35.x).
  * The cluster must be online with no active operations.
</Warning>

### Via the Dashboard

Go to your cluster → **Settings** → **General** to see the current k3s version and trigger an upgrade.

### Check Current Version

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh k8s-version <cluster_id>
  ```

  ```bash cURL theme={null}
  curl https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/k8s-version \
    -H "Authorization: Bearer $ANKRA_API_TOKEN"
  ```
</CodeGroup>

Response:

```json theme={null}
{
  "current_version": "v1.34.4+k3s1",
  "distribution": "k3s"
}
```

### Upgrade Version

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh upgrade <cluster_id> v1.35.1+k3s1
  ```

  ```bash cURL theme={null}
  curl -X POST https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/upgrade-k8s-version \
    -H "Authorization: Bearer $ANKRA_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"target_version": "v1.35.1+k3s1"}'
  ```
</CodeGroup>

Response:

```json theme={null}
{
  "previous_version": "v1.34.4+k3s1",
  "new_version": "v1.35.1+k3s1",
  "nodes_affected": 3
}
```

***

## Stopping and Starting a Cluster

You can stop an OVH cluster to release its compute (node instances, the bastion, and the managed network gateway) while keeping its configuration, networking definition, and SSH keys. Starting the cluster re-provisions the compute and reconciles it back to a running state. This is useful for pausing non-production clusters to save cost.

When starting, use `--scope control_plane` to bring up only the control plane first (for example to inspect or repair it), or `--scope all` (the default) to provision the whole cluster.

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh stop <cluster_id>
  ankra cluster ovh stop <cluster_id> --force                # also delete Cinder volumes and load balancers
  ankra cluster ovh start <cluster_id>                       # scope defaults to "all"
  ankra cluster ovh start <cluster_id> --scope control_plane # control plane only
  ```

  ```bash cURL theme={null}
  curl -X POST https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/stop \
    -H "Authorization: Bearer $ANKRA_API_TOKEN"

  curl -X POST "https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/start?scope=all" \
    -H "Authorization: Bearer $ANKRA_API_TOKEN"
  ```
</CodeGroup>

<Note>
  Stop and start are background operations. A start returns `409` if a stop or terminate operation is still running. The private network is preserved while stopped and reused on the next start.
</Note>

A plain stop keeps the Cinder volumes your workloads provisioned through the CSI driver, and OVH bills them while the cluster is parked. Pass `--force` (or `?force=true` on the API) to delete them together with any load balancers the cluster created. Ankra deletes exactly the volumes it recorded for this cluster, never other volumes in the project.

<Warning>
  A forced stop destroys the data on those volumes. A later start brings the cluster back with empty storage.
</Warning>

***

## SSH Access and Keys

`ankra cluster ovh access-info` prints the bastion and control plane IPs along with ready-to-paste `ssh -J` jump and Kubernetes API port-forward commands, so you can reach nodes behind the bastion without looking up IPs by hand.

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh access-info <cluster_id>
  ```

  ```bash cURL theme={null}
  curl https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/access-info \
    -H "Authorization: Bearer $ANKRA_API_TOKEN"
  ```
</CodeGroup>

You can also view and replace the SSH key credentials attached to a cluster. Replacing the keys applies on the next reconciliation.

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh ssh-keys get <cluster_id>
  ankra cluster ovh ssh-keys set <cluster_id> --ssh-key-credential-ids <id>,<id>
  ```

  ```bash cURL theme={null}
  curl https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/ssh-keys \
    -H "Authorization: Bearer $ANKRA_API_TOKEN"

  curl -X PUT https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/ssh-keys \
    -H "Authorization: Bearer $ANKRA_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"ssh_key_credential_ids": ["<ssh-key-credential-id>"]}'
  ```
</CodeGroup>

***

## Managing the Control Plane

Inspect the control plane configuration, then change the node count or instance flavor. OVH control planes support a count of `1` or `3`.

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh control-plane get <cluster_id>
  ankra cluster ovh control-plane set-count <cluster_id> 3
  ankra cluster ovh control-plane set-instance-type <cluster_id> b2-15
  ```

  ```bash cURL theme={null}
  curl https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/control-plane \
    -H "Authorization: Bearer $ANKRA_API_TOKEN"

  curl -X PUT https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/control-plane \
    -H "Authorization: Bearer $ANKRA_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"count": 3}'

  curl -X PUT https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/control-plane/instance-type \
    -H "Authorization: Bearer $ANKRA_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"instance_type": "b2-15"}'
  ```
</CodeGroup>

<Warning>
  Control plane changes require the cluster to be **stopped** first. Changing the count or instance type on a running cluster returns `409` with "The cluster must be stopped" - stop it, apply the change, then start it again.
</Warning>

***

## Inspecting Nodes

List every node in the cluster or fetch the details of a single node by ID. The list includes each node's live status as last reported by the OVH API (`provider_status` / `provider_power_state`) - useful for spotting a crashed or unexpectedly powered-off instance before you restart it.

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh nodes list <cluster_id>
  ankra cluster ovh nodes get <cluster_id> <node_id>
  ```

  ```bash cURL theme={null}
  curl https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/nodes \
    -H "Authorization: Bearer $ANKRA_API_TOKEN"

  curl https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/nodes/<node_id> \
    -H "Authorization: Bearer $ANKRA_API_TOKEN"
  ```
</CodeGroup>

***

## Restarting a Node

Restart any individual node - a control plane node, a worker, or the bastion/gateway - without waiting for a full reconciliation. Ankra schedules the restart as a tracked operation via the OVH API: a running instance gets a soft reboot (falling back to a hard reboot if the guest OS doesn't respond), and a `SHUTOFF` instance is started instead.

### Via the Platform UI

Open cluster **Settings** > **Nodes**, find the node in the table, and choose **Restart** from its row menu. Confirm the dialog to schedule the restart.

### Via the CLI or API

Find the node's ID with `nodes list`, then restart it:

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh nodes list <cluster_id>
  ankra cluster ovh nodes restart <cluster_id> <node_id>
  ```

  ```bash cURL theme={null}
  curl -X POST https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/nodes/<node_id>/restart \
    -H "Authorization: Bearer $ANKRA_API_TOKEN"
  ```
</CodeGroup>

Response:

```json theme={null}
{
  "operation_id": "9f2b1e3a-...",
  "node_id": "<node_id>",
  "job_name": "ovh_restart_server"
}
```

<Note>
  The node must be in the `up` state with no restart already in flight. Track the restart with the returned `operation_id` via `ankra cluster operations list <operation_id>` or the [CLI reference](/reference/cli/cluster#ankra-cluster-operations-list). Workloads on the node are briefly unavailable while it reboots.
</Note>

You can also ask the Ankra AI assistant to do this in chat or Slack - for example, "restart the bastion on my-cluster" or "restart worker-2".

***

## Resizing the Bastion or Gateway

Change the bastion/gateway's instance flavor without recreating the cluster. Ankra powers it off, resizes it, and powers it back on - causing a brief SSH and outbound-NAT interruption.

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh bastion resize <cluster_id> b2-15
  ```

  ```bash cURL theme={null}
  curl -X PUT https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>/bastion/instance-type \
    -H "Authorization: Bearer $ANKRA_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"instance_type": "b2-15"}'
  ```
</CodeGroup>

<Note>
  Like node-group writes, this endpoint answers `202 Accepted` and applies the resize in the background unless you pass `--wait` (CLI) or `?wait=true` (API).
</Note>

***

## Deprovisioning

Deprovisioning deletes all OVH resources (instances, networks, SSH keys) and removes the cluster from Ankra.

<Warning>
  This action is irreversible. All data on the cluster will be permanently deleted.
</Warning>

### Via the Dashboard

Go to your cluster → **Settings** → **General** → **Danger Zone** and click **Deprovision Cluster**. You will be asked to confirm before the operation begins.

### Via CLI or API

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster ovh deprovision <cluster_id>
  ankra cluster ovh deprovision <cluster_id> --force  # also delete Cinder volumes and load balancers
  ```

  ```bash cURL theme={null}
  curl -X DELETE https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id> \
    -H "Authorization: Bearer $ANKRA_API_TOKEN"

  curl -X DELETE "https://platform.ankra.app/api/v1/clusters/ovh/<cluster_id>?force=true" \
    -H "Authorization: Bearer $ANKRA_API_TOKEN"
  ```
</CodeGroup>

A plain deprovision leaves behind the Cinder volumes your workloads provisioned through the CSI driver, and OVH keeps billing them. `--force` deletes them along with the rest of the infrastructure, tolerates unreachable cluster infrastructure, and works on a cluster that was stopped earlier: the volumes recorded at stop time are still known and get reclaimed.

***

## Architecture

An OVH cluster provisions the following infrastructure:

| Component                   | Description                                                                                                      |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| **Private Network**         | Isolated vRack VLAN with a DHCP subnet for inter-node communication                                              |
| **Managed Network Gateway** | OVH-managed gateway attached to the subnet - the default route and NAT for all node egress                       |
| **Bastion**                 | Small instance holding the cluster's only public IP - the SSH jump host Ankra uses to provision and manage nodes |
| **Control Plane(s)**        | Kubernetes control plane instances (private IPs only)                                                            |
| **Worker(s)**               | Kubernetes worker instances for running workloads (private IPs only)                                             |
| **SSH Keys**                | Deployed to all instances for access                                                                             |

```mermaid theme={null}
flowchart TB
    Internet((Internet))
    Platform[Ankra Platform]

    subgraph Network [OVH private network - vRack VLAN]
        Bastion[Bastion<br/>public + private IP]
        CP[Control plane nodes<br/>private IP only]
        Workers[Worker nodes<br/>private IP only]
        Agent[Ankra Agent<br/>runs in the cluster]
    end

    MGW[OVH managed network gateway<br/>default route + NAT]

    Platform -->|SSH to public IP| Bastion
    Bastion -->|SSH jump| CP
    Bastion -->|SSH jump| Workers
    Agent -->|outbound only - NATS| Platform
    CP -->|egress| MGW
    Workers -->|egress| MGW
    MGW --> Internet
```

All nodes are deployed within a private OVH network and have no public IPs. Two different components share the word "gateway", so it helps to keep them apart:

* The **managed network gateway** (created alongside the private network, named `<cluster>-network-gw`) is the actual router: every node's default route points at it, and all outbound traffic to the internet leaves through it.
* The **bastion** (named `<cluster>-bastion`) is an SSH jump host, not a router. No workload or egress traffic flows through it. Ankra connects to its public IP to provision nodes, install Kubernetes, apply upgrades, and run reconciliation, and you can use it for `ssh -J` access to the nodes.

<Note>
  Clusters created before the bastion rename carry the instance name `<cluster>-gateway` in OVH instead of `<cluster>-bastion`. It is the same component with the same role; existing clusters keep their original instance name.
</Note>

Because the data plane does not depend on the bastion, workloads keep running if it is briefly unavailable - but Ankra cannot provision, scale, upgrade, or reconcile the cluster until it is back, and the cluster can appear degraded in the dashboard while reads fail.

***

## Troubleshooting

### Common Issues

| Issue                         | Solution                                                       |
| ----------------------------- | -------------------------------------------------------------- |
| Cluster stuck in provisioning | Check OVH API credentials and project quota                    |
| Cannot scale workers          | Ensure cluster is online and no operations are running         |
| Invalid API credentials       | Re-validate at [OVH API Console](https://api.ovh.com/console/) |
| Flavor unavailable            | Try a different region or flavor                               |

### OVH Cloud Quotas

OVH Cloud has default resource limits per project. If provisioning fails, check your quotas in the [OVH Control Panel](https://www.ovh.com/manager/):

* Instances
* Networks / VLANs
* SSH Keys

Contact OVH support to increase limits if needed.
