# How to Create a Cluster Template

Source: https://docs.quake.ai/docs/kubernetes/how-to/create-cluster-template
Markdown: https://docs.quake.ai/docs/kubernetes/how-to/create-cluster-template.md

---

# How to create a cluster template

Create a cluster template that defines the blueprint for Kubernetes clusters: Kubernetes version, node flavor, network driver, volume driver, and the label set that drives boot volume sizing, floating-IP allocation, and load-balancer behavior. You create the template once and reuse it to provision multiple clusters with the same configuration.

<PrerequisiteBlock methods={["console", "cli"]}>

- An [external network](/docs/network/how-to/create-network) available in your project (or use the default public network)
- A [key pair](/docs/tools/add-ssh-key) uploaded to your account for SSH access to cluster nodes
- Familiarity with available [flavors](/reference/compute/console/flavors); production master nodes typically need at least 4 vCPU and 8 GB RAM
- Available `compute_units` quota on the project (see [Sizing and quota](#sizing-and-quota) below)

</PrerequisiteBlock>


**Magnum cluster creation requires a password-scoped session.** Template creation works under any authenticated session, but `openstack coe cluster create` against this template later triggers Keystone trust delegation, which is not available to Keystone application credentials. Authenticate the CLI session with `OS_USERNAME` and `OS_PASSWORD` (password auth) before running `openstack coe cluster create`. The Cloud Console wizard works from any logged-in user session because it uses the user's password-scoped token. See [the Kubernetes FAQ](/docs/kubernetes/faq) for the full troubleshooting flow.


## Sizing and quota

Two Quake AI platform defaults shape the labels and the example flavor below.

**Zero-disk flavors require a boot volume.** Every Quake AI flavor family (`s1a.*`, `c2a.*`, `m2a.*`, `r2a.*`) ships with `disk: 0`. The Compute service rejects server creation against zero-disk flavors unless the request specifies a Block Storage boot volume. Magnum honors this through the `boot_volume_size` cluster-template label; without that label, cluster creation fails with `Forbidden: Only volume-backed servers are allowed for flavors with zero disk (HTTP 403)`. The platform-provided cluster templates set `boot_volume_size: '40'`; the examples below match.

**`compute_units` is a per-project quota.** Each flavor carries a `rumble:compute_units` value, visible via `openstack flavor show FLAVOR -f json`. The default-tier project quota is `8000`. Common Magnum-eligible flavors:

| Flavor | vCPUs | RAM | `compute_units` |
|---|---|---|---|
| `c2a.large` | 2 | 4 GB | 2000 |
| `c2a.xlarge` | 4 | 8 GB | 4000 |
| `c2a.2xlarge` | 8 | 16 GB | 8000 |

A minimum cluster of 1 master (`c2a.xlarge`) + 1 worker (`c2a.large`) consumes `6000` compute_units, which fits a fresh `8000`-quota project. Existing instances on the project subtract from that budget; check the live total with `openstack limits show --absolute` before sizing the template. Production sizing (multiple masters or larger workers) requires raising the project quota.

## Create the template

<MethodTabs>
<Method label="Console">

the Console renders the Create Cluster Template wizard as four numbered steps: **Cluster Info**, **Node Spec**, **Network Setting**, and **Additional Labels**. The bottom action bar reads **Cancel | Previous: `<step>` | Next: `<step>`** on steps 1 through 3, and **Cancel | Previous: Network Setting | Confirm** on step 4.

1. Go to **Kubernetes** > **Cluster Templates** and select **Create Cluster Template**.

2. **Step 1: Cluster Info.**
   - **Name**: a name for the template (for example, `production-k8s-calico`).
   - **Public**: makes the template available to all project users.
   - **Hidden**: suppresses the template from default list views.
   - **Enable Registry**: enable when the cluster needs an integrated container registry.
   - **Disable TLS**: leave unchecked for production. TLS protects the Kubernetes API.
   - Select **Next: Node Spec**.

3. **Step 2: Node Spec.**
   - **Image**: a Kubernetes-ready image (Fedora CoreOS is the supported choice today).
   - **Keypair**: the SSH key pair for node access.
   - **Flavor of Master Nodes**: master node flavor (for example, `c2a.xlarge` for 4 vCPU and 8 GB RAM). Optional; defaults to the worker flavor when blank.
   - **Flavor of Nodes**: worker node flavor (for example, `c2a.large` for 2 vCPU and 4 GB RAM).
   - **Docker Volume Size (GiB)**: dedicated volume size for the container-runtime graph on each node. Leave blank to let the Kubernetes service size it automatically. Platform-provided templates ship with `50`; production clusters typically use `50` or larger when pulling many large container images.
   - **Volume Driver**: select **Cinder** for Block Storage-backed persistent volumes. The Cloud Console shows the capitalized label; the API accepts `cinder`.
   - **Docker Storage Driver**: **Overlay2** is the default and the recommended choice on Fedora CoreOS. The Cloud Console shows the capitalized label; the API accepts `overlay2`.
   - Select **Next: Network Setting**.

4. **Step 3: Network Setting.**
   - **HTTP Proxy / HTTPS Proxy / No Proxy**: set when the cluster runs behind an outbound proxy.
   - **DNS**: ships blank. Set a public DNS server (for example, `8.8.8.8`) for clusters with public internet egress, or a private DNS server (for example, `10.0.0.2`) for clusters whose network has no public-DNS egress.
   - **External Network** (required): the network providing internet connectivity (for example, `PublicEphemeral` or `PublicStatic` in `us-east-1`).
   - **Fixed Network** and **Fixed Subnet**: leave blank to auto-create, or select existing resources.
   - **Network Driver**: **Calico** (recommended; supports network policies) or **Flannel**. The Cloud Console shows capitalized labels; the API accepts `calico` and `flannel`.
   - **Enable Load Balancer**: enable for clusters with multiple master nodes, or any cluster that should reach the Kubernetes API through a single endpoint. The checkbox label on the wizard reads **Enabled Load Balancer for Master Nodes**. The `master_lb_floating_ip_enabled` label on the next step controls whether that endpoint receives a floating IP.
   - Select **Next: Additional Labels**.

5. **Step 4: Additional Labels.** This step starts empty. Click **+ Add Label** to add each label the cluster requires. Each row exposes **Key**, **Value**, and a delete control.

   
   **`boot_volume_size=40` is required.** Without it, cluster creation against this template fails with the verbatim Heat error `Forbidden: Only volume-backed servers are allowed for flavors with zero disk`. See [the Kubernetes FAQ](/docs/kubernetes/faq) for the full troubleshooting flow.
   

   Required labels to add manually:

   | Label | Value | What it does |
   |---|---|---|
   | `boot_volume_size` | `40` | Backs every cluster node with a 40 GB Block Storage boot volume. Required because every Quake AI flavor is zero-disk. |
   | `master_lb_floating_ip_enabled` | `true` | Allocates a floating IP to the Kubernetes API endpoint. Set to `false` for a private API endpoint. |

   Add `floating_ip_enabled = false` via **+ Add Label** to keep node-level floating IPs off. The `iac/templates/k8s-cluster/` template ships this same shape: master LB FIP on, node FIPs off, one public IP per cluster.

6. Select **Confirm**.

The template appears in the **Cluster Templates** list. Pick it when you create a new cluster.

</Method>
<Method label="CLI">

Create a cluster template with `openstack coe cluster template create`. The example below sets the boot-volume and control-plane endpoint labels:

```bash
openstack coe cluster template create MY_TEMPLATE_NAME \
  --coe kubernetes \
  --image FEDORA_COREOS_IMAGE_ID \
  --keypair MY_KEYPAIR \
  --flavor c2a.xlarge \
  --external-network PublicStatic \
  --network-driver calico \
  --volume-driver cinder \
  --docker-storage-driver overlay2 \
  --dns-nameserver 8.8.8.8 \
  --master-lb-enabled \
  --floating-ip-disabled \
  --labels boot_volume_size=40,master_lb_floating_ip_enabled=true
```

Quake AI requires `--labels boot_volume_size=40` because every flavor family has `disk: 0`. Without it, cluster creation fails with `Forbidden: Only volume-backed servers are allowed for flavors with zero disk (HTTP 403)`. See [Sizing and quota](#sizing-and-quota) above.

Key parameters:

| Flag | Description |
|---|---|
| `--coe` | Container orchestration engine. Use `kubernetes`. |
| `--image` | Image ID or name. Use a Kubernetes-ready Fedora CoreOS image. Run `openstack image list` to find available images. |
| `--keypair` | SSH key pair name for node access. |
| `--flavor` | Worker node hardware profile. Run `openstack flavor list` to see options. Override per cluster on `openstack coe cluster create --flavor`. |
| `--master-flavor` | Master node hardware profile. Optional; defaults to the worker flavor when omitted. Override per cluster on `openstack coe cluster create --master-flavor`. |
| `--docker-volume-size` | Size in GiB of the dedicated container-runtime volume on each node. Platform-provided templates ship with `50`. |
| `--external-network` | Network providing internet connectivity. |
| `--network-driver` | `calico` (supports network policies) or `flannel` (simpler, lower overhead). |
| `--volume-driver` | `cinder` enables Kubernetes persistent volumes backed by Block Storage. |
| `--docker-storage-driver` | Storage driver for the container runtime on cluster nodes. `overlay2` is the default and the recommended choice on Fedora CoreOS. |
| `--dns-nameserver` | DNS server cluster nodes use to resolve external hostnames. The Cloud Console wizard ships this field blank; the CLI default is `8.8.8.8` (Google Public DNS). Set a private DNS server when the cluster network has no public-DNS egress. |
| `--master-lb-enabled` | Creates a load balancer for the Kubernetes API. Required when running multiple masters; recommended for any production cluster. |
| `--floating-ip-disabled` | Creates cluster nodes without floating IPs. The Magnum default, when the CLI omits both `--floating-ip-enabled` and `--floating-ip-disabled`, matches `--floating-ip-disabled`. Combine with `--master-lb-enabled` and `master_lb_floating_ip_enabled=true` to land on a 1-FIP cluster (the master LB VIP is the only public IP). |
| `--tls-disabled` | Disables TLS on the Kubernetes API. Omit in production. |
| `--labels` | Comma-separated key-value pairs. Quake AI requires `boot_volume_size=40` for cluster creation to succeed. The control-plane endpoint label in the example gives the Kubernetes API endpoint a floating IP. Add `floating_ip_enabled=false` to suppress node-level floating IPs. Other useful labels include `kube_dashboard_enabled=true` and `autoscaler_enabled=true`. |

To make the template available to all users in the project, add `--public`.

Verify the template:

```bash
openstack coe cluster template show MY_TEMPLATE_NAME
```

</Method>
</MethodTabs>

## Verify the result

Confirm the template appears in the template list and the configuration matches your intent:

- **Network driver** and **volume driver** are correct
- **Enable Load Balancer** is on if you plan to use multiple master nodes or want a single API VIP
- **Disable TLS** stays unchecked for production templates
- **Flavor of Nodes** meets your workload requirements
- **Additional Labels** include `boot_volume_size=40` and `master_lb_floating_ip_enabled=true`

## Next steps

- [Create a Kubernetes cluster](/docs/kubernetes/how-to/create-cluster) using this template
- [Kubernetes on Quake AI](/docs/kubernetes/concepts/kubernetes): architecture, templates, and resource planning
- [Cluster Templates Console](/reference/kubernetes/console/cluster-templates): manage templates in the console
- [Kubernetes CLI reference](/reference/kubernetes/cli)
- [`k8s-cluster` template](/resources/iac-templates/k8s-cluster): an OpenTofu module that gives the Kubernetes API endpoint one floating IP, disables node floating IPs, and sets `boot_volume_size=40`
