> ## 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.

# DigitalOcean Clusters

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

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

***

## Prerequisites

Before creating a DigitalOcean cluster, you need two credentials:

<CardGroup cols={2}>
  <Card title="DigitalOcean API Credential" icon="key">
    A DigitalOcean personal access token with read/write permissions. See [DigitalOcean Credentials](/platform/credentials/digitalocean).
  </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 a DigitalOcean Cluster

### Via the Platform UI

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

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

  <Step title="Select Credentials">
    Pick your DigitalOcean 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 a DigitalOcean region (e.g., `nyc3`, `fra1`, `lon1`). Each region shows the location and country.
  </Step>

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

    * **Bastion** - Droplet size for the SSH bastion host (e.g., `s-1vcpu-1gb`)
    * **Control Plane** - Count (1 or 3) and size (e.g., `s-2vcpu-4gb`)
    * **Workers** - Count and size (e.g., 2× `s-2vcpu-4gb`)

    The wizard shows vCPUs, RAM, and monthly cost for each size to help you choose.
  </Step>

  <Step title="Choose Distribution">
    Pick the Kubernetes distribution:
    **k3s** Lightweight Kubernetes with a user-selectable CNI (default).
    **kubeadm** Vanilla upstream Kubernetes bootstrapped with `kubeadm` and containerd. kubeadm clusters always use Cilium CNI and optionally support an external etcd topology with dedicated etcd droplets.

    See [Kubernetes Distribution](#kubernetes-distribution) for details.
  </Step>

  <Step title="Create & Track Progress">
    Click **Create** to start provisioning. A live progress view tracks credential setup, VPC creation, SSH key deployment, bastion provisioning, droplet creation, Kubernetes installation (k3s or kubeadm), and Ankra Agent setup. The cluster appears with an **offline** state until provisioning completes, then transitions to **online**.
  </Step>
</Steps>

### Via the CLI

```bash theme={null}
# Create credentials first
ankra credentials digitalocean create --name my-do-token  # securely prompts for token
ankra credentials digitalocean ssh-key create --name my-ssh-key --generate

# List regions and sizes for your credential
ankra cluster digitalocean regions --credential-id <digitalocean-credential-id>
ankra cluster digitalocean sizes --credential-id <digitalocean-credential-id> --region nyc3 --available-only

# Create the cluster
ankra cluster digitalocean create \
  --name my-cluster \
  --credential-id <digitalocean-credential-id> \
  --ssh-key-credential-id <ssh-key-credential-id> \
  --region nyc3 \
  --control-plane-count 1 \
  --control-plane-size s-2vcpu-4gb \
  --worker-count 2 \
  --worker-size s-2vcpu-4gb
```

### Via the API

```bash theme={null}
curl -X POST https://platform.ankra.app/api/v1/clusters/digitalocean \
  -H "Authorization: Bearer $ANKRA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-cluster",
    "credential_id": "<digitalocean-credential-id>",
    "ssh_key_credential_id": "<ssh-key-credential-id>",
    "region": "nyc3",
    "control_plane_count": 1,
    "control_plane_size": "s-2vcpu-4gb",
    "node_groups": [
      {"name": "default", "instance_type": "s-2vcpu-4gb", "count": 2}
    ],
    "distribution": "k3s"
  }'
```

***

## Cluster Configuration Options

| Parameter               | Default         | Description                                                                                                                                                                                        |
| ----------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                  | *required*      | Unique cluster name                                                                                                                                                                                |
| `credential_id`         | *required*      | DigitalOcean API credential ID                                                                                                                                                                     |
| `ssh_key_credential_id` | *required*      | SSH key credential ID                                                                                                                                                                              |
| `region`                | *required*      | DigitalOcean region slug                                                                                                                                                                           |
| `network_ip_range`      | `10.0.0.0/16`   | Private VPC IP range                                                                                                                                                                               |
| `bastion_size`          | `s-1vcpu-1gb`   | Droplet size for the bastion host                                                                                                                                                                  |
| `control_plane_count`   | `1`             | Number of control plane nodes (1 or 3)                                                                                                                                                             |
| `control_plane_size`    | `s-2vcpu-4gb`   | Droplet size for control planes                                                                                                                                                                    |
| `worker_count`          | `1`             | Number of worker nodes (legacy, use `node_groups` instead)                                                                                                                                         |
| `worker_size`           | `s-2vcpu-4gb`   | Droplet size for workers (legacy, use `node_groups` instead)                                                                                                                                       |
| `node_groups`           |                 | Array of node group definitions (see [Node Groups](#node-groups))                                                                                                                                  |
| `distribution`          | `k3s`           | Kubernetes distribution (`k3s` or `kubeadm`)                                                                                                                                                       |
| `kubernetes_version`    | *latest stable* | Kubernetes version (optional)                                                                                                                                                                      |
| `cni`                   | `flannel` (k3s) | CNI plugin. kubeadm clusters always use `cilium`                                                                                                                                                   |
| `cni_features`          | *all off*       | Advanced CNI feature toggles, fixed at creation. Cilium: `kube_proxy_replacement`, `hubble`, `wireguard_encryption`. Calico: `ebpf_dataplane`. See [Advanced CNI features](#advanced-cni-features) |
| `etcd_topology`         | `stacked`       | kubeadm only. `stacked` (etcd on control planes) or `external` (dedicated etcd droplets)                                                                                                           |
| `etcd_node_count`       | `3`             | kubeadm `external` topology only. Number of dedicated etcd droplets (3 or 5)                                                                                                                       |
| `etcd_size`             | `s-2vcpu-4gb`   | kubeadm `external` topology only. Droplet size for dedicated etcd nodes                                                                                                                            |
| `include_ingress`       | `false`         | Deploy Traefik + cert-manager for ingress                                                                                                                                                          |

### DigitalOcean Regions

| Region | Location                       |
| ------ | ------------------------------ |
| `nyc3` | New York 3, United States      |
| `sfo3` | San Francisco 3, United States |
| `ams3` | Amsterdam 3, Netherlands       |
| `sgp1` | Singapore 1, Singapore         |
| `lon1` | London 1, United Kingdom       |
| `fra1` | Frankfurt 1, Germany           |

<Note>
  Available regions and sizes depend on your account. Use `ankra cluster digitalocean regions` and `ankra cluster digitalocean sizes` to list what your credential can deploy.
</Note>

### Common Droplet Sizes

| Size          | vCPUs | RAM  | Typical use                    |
| ------------- | ----- | ---- | ------------------------------ |
| `s-1vcpu-1gb` | 1     | 1 GB | Bastion                        |
| `s-1vcpu-2gb` | 1     | 2 GB | Small workers                  |
| `s-2vcpu-4gb` | 2     | 4 GB | Control plane, general workers |
| `s-4vcpu-8gb` | 4     | 8 GB | Larger workloads               |

***

## Kubernetes Distribution

DigitalOcean clusters can be provisioned with either **k3s** (default) or **kubeadm**.

|                | k3s                                     | kubeadm                                                          |
| -------------- | --------------------------------------- | ---------------------------------------------------------------- |
| Kubernetes     | Lightweight, single-binary distribution | Vanilla upstream Kubernetes                                      |
| CNI            | User-selectable (Flannel default)       | Cilium (fixed, cannot be changed after creation)                 |
| etcd           | Embedded                                | `stacked` (on control planes) or `external` (dedicated droplets) |
| Version format | `v1.35.1+k3s1`                          | `v1.31.0` (plain upstream tag)                                   |

<Note>
  kubeadm clusters always use Cilium CNI (eBPF-based networking, L7 policies, Hubble observability). The CNI cannot be changed after creation.
</Note>

### Advanced CNI features

k3s clusters can enable advanced CNI features at creation time via `cni_features` (also available as toggles in the create wizard). Features are fixed once the cluster is created.

| Feature                  | CNI    | What it does                                                                                   |
| ------------------------ | ------ | ---------------------------------------------------------------------------------------------- |
| `kube_proxy_replacement` | Cilium | Replaces kube-proxy with Cilium's eBPF dataplane                                               |
| `hubble`                 | Cilium | Deploys Hubble relay and UI for network flow observability                                     |
| `wireguard_encryption`   | Cilium | Encrypts pod-to-pod traffic between nodes with WireGuard (UDP/51871 must be open node-to-node) |
| `ebpf_dataplane`         | Calico | Runs Calico in eBPF mode, bypassing kube-proxy                                                 |

<Warning>
  `kube_proxy_replacement` and `ebpf_dataplane` pin the CNI's API-server endpoint to the first control plane, so on k3s they require a **single control plane**. Creation and control-plane scaling both enforce this. Flannel accepts no feature toggles.
</Warning>

### External etcd topology (kubeadm)

By default kubeadm runs etcd **stacked** on the control plane nodes. For larger clusters you can run etcd on dedicated droplets by setting `etcd_topology` to `external`:

```bash theme={null}
curl -X POST https://platform.ankra.app/api/v1/clusters/digitalocean \
  -H "Authorization: Bearer $ANKRA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-cluster",
    "credential_id": "<digitalocean-credential-id>",
    "ssh_key_credential_id": "<ssh-key-credential-id>",
    "region": "nyc3",
    "control_plane_count": 3,
    "control_plane_size": "s-2vcpu-4gb",
    "node_groups": [
      {"name": "default", "instance_type": "s-2vcpu-4gb", "count": 2}
    ],
    "distribution": "kubeadm",
    "etcd_topology": "external",
    "etcd_node_count": 3,
    "etcd_size": "s-2vcpu-4gb"
  }'
```

The equivalent CLI flags are `--distribution kubeadm`, `--etcd-topology external`, `--etcd-node-count 3`, and `--etcd-size s-2vcpu-4gb`.

***

## Node Groups

Node groups let you organize worker nodes into logical groups with independent droplet sizes, counts, labels, and taints. Manage node groups from **Settings** > **Nodes** in the dashboard, or via the API.

### Node Group API Reference

| Endpoint                                                              | Method | Description                |
| --------------------------------------------------------------------- | ------ | -------------------------- |
| `/api/v1/clusters/digitalocean/{id}/node-groups`                      | GET    | List all node groups       |
| `/api/v1/clusters/digitalocean/{id}/node-groups`                      | POST   | Add a node group           |
| `/api/v1/clusters/digitalocean/{id}/node-groups/{name}/scale`         | PUT    | Scale a node group (0-100) |
| `/api/v1/clusters/digitalocean/{id}/node-groups/{name}/instance-type` | PUT    | Change droplet size        |
| `/api/v1/clusters/digitalocean/{id}/node-groups/{name}/labels`        | PUT    | Update labels              |
| `/api/v1/clusters/digitalocean/{id}/node-groups/{name}/taints`        | PUT    | Update taints              |
| `/api/v1/clusters/digitalocean/{id}/node-groups/{name}`               | DELETE | Delete a node group        |

For detailed usage examples, see [Hetzner Node Groups](/guides/hetzner-clusters#node-groups) - the API is identical across all providers.

***

## Legacy Worker Scaling

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

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

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

  curl -X POST https://platform.ankra.app/api/v1/clusters/digitalocean/<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 version on all nodes in a DigitalOcean cluster. Upgrades are applied to control plane nodes first, then workers. Both k3s and kubeadm clusters are supported.

<Warning>
  * Both k3s and kubeadm clusters are supported for version upgrades, including kubeadm clusters with an **external** etcd topology: the dedicated etcd members are upgraded first, one at a time, each saving a pre-upgrade snapshot before its static pod rolls to the etcd image matching the target Kubernetes version.
  * Use the matching version format for the target: `v1.35.1+k3s1` for k3s, or a plain `v1.31.0` upstream tag for kubeadm.
  * Downgrades are not supported - 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>

### Check Current Version

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

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

### Upgrade Version

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

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

For a kubeadm cluster, use a plain upstream tag instead:

```bash theme={null}
ankra cluster digitalocean upgrade <cluster_id> v1.31.0
```

***

## Deprovisioning

Deprovisioning deletes all DigitalOcean resources (droplets, VPC, SSH keys) and removes the cluster from Ankra.

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

<Warning>
  **Clean up DigitalOcean resources before terminating.** The DigitalOcean CCM and CSI driver create Load Balancers and Volumes in your account that Ankra does not track. Delete Kubernetes `LoadBalancer` services and PVCs using the `do-block-storage` StorageClass before deprovisioning, or remove orphaned resources in the [DigitalOcean Control Panel](https://cloud.digitalocean.com/).
</Warning>

<CodeGroup>
  ```bash CLI theme={null}
  ankra cluster digitalocean deprovision <cluster_id>
  ```

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

***

## Architecture

A DigitalOcean cluster provisions the following infrastructure:

| Component                | Description                                                                                                            |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| **VPC**                  | Private network for inter-node communication                                                                           |
| **Bastion Host**         | Jump server for secure SSH access to cluster nodes                                                                     |
| **Control Plane(s)**     | Kubernetes control plane droplets                                                                                      |
| **Worker(s)**            | Kubernetes worker droplets organized in [node groups](#node-groups)                                                    |
| **etcd Node(s)**         | Dedicated etcd droplets, only for kubeadm clusters with an `external` [etcd topology](#external-etcd-topology-kubeadm) |
| **SSH Keys**             | Deployed to all droplets for access                                                                                    |
| **Cloud Provider Stack** | DigitalOcean CCM and CSI for LoadBalancers and block storage                                                           |

All nodes are deployed within a private VPC. The bastion host provides the only external SSH access point.

Ankra automatically deploys a **digitalocean-cloud-provider** stack after the Ankra Agent is installed, including the DigitalOcean Cloud Controller Manager and CSI driver backed by your API credential.

***

## Provider-native Managed Kubernetes (DOKS & UKS)

In addition to self-managed k3s or kubeadm on droplets, Ankra can provision and import provider-native managed Kubernetes services:

| Provider kind | Service                                                                             | Credential             |
| ------------- | ----------------------------------------------------------------------------------- | ---------------------- |
| `doks`        | [DigitalOcean Kubernetes (DOKS)](https://www.digitalocean.com/products/kubernetes)  | DigitalOcean API token |
| `uks`         | [UpCloud Managed Kubernetes (UKS)](https://upcloud.com/products/managed-kubernetes) | UpCloud API token      |

See [Managed Kubernetes](/guides/managed-kubernetes) for the full guide covering live options and pricing, preflight checks, discovery and import, node pool autoscaling, and upgrades - across DOKS, UKS, GKE, OVHcloud MKS, AKS, and EKS.

Create a managed cluster from the platform UI or via the API:

```bash theme={null}
# DigitalOcean Kubernetes (DOKS)
curl -X POST https://platform.ankra.app/org/clusters/managed/doks \
  -H "Authorization: Bearer $ANKRA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-doks-cluster",
    "credential_id": "<digitalocean-credential-id>",
    "location": "nyc3",
    "node_pools": [
      {"name": "default", "size": "s-2vcpu-4gb", "count": 2}
    ]
  }'

# UpCloud Managed Kubernetes (UKS)
curl -X POST https://platform.ankra.app/org/clusters/managed/uks \
  -H "Authorization: Bearer $ANKRA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-uks-cluster",
    "credential_id": "<upcloud-credential-id>",
    "location": "fi-hel1",
    "node_pools": [
      {"name": "default", "size": "2xCPU-4GB", "count": 2}
    ]
  }'
```

Ankra provisions the cluster with the provider, stores kubeconfig securely, and installs the Ankra Agent so you can manage stacks and GitOps the same way as imported clusters.

***

## Troubleshooting

### Common Issues

| Issue                                   | Solution                                                                                                                            |
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| Cluster stuck in provisioning           | Check API token permissions and account quota                                                                                       |
| Cannot scale workers                    | Ensure cluster is online and no operations are running                                                                              |
| Invalid API token                       | Re-validate at [DigitalOcean Control Panel](https://cloud.digitalocean.com/account/api/tokens) - tokens are prefixed with `dop_v1_` |
| Droplet size unavailable                | Try a different region or size                                                                                                      |
| LoadBalancer service stuck in `Pending` | Verify the CCM is running in the `digitalocean-cloud-provider` namespace                                                            |
| PVCs stuck in `Pending`                 | Verify the CSI driver is running and the `do-block-storage` StorageClass exists                                                     |

### DigitalOcean Account Quotas

DigitalOcean has default resource limits per account. If provisioning fails, check your quotas in the [DigitalOcean Control Panel](https://cloud.digitalocean.com/):

* Droplets
* VPCs
* Load Balancers
* Volumes

Contact DigitalOcean support to increase limits if needed.
