Skip to main content

Kubernetes Clusters via API

Create, connect to, and scale a Kubernetes cluster with the Hyperstack API.

Hyperstack provisions on-demand Kubernetes clusters from a single API call. You choose a Kubernetes version, a flavor for the worker nodes, and a CPU-only flavor for the control plane, and Hyperstack provisions every node, installs Kubernetes, and returns a kubeconfig you can hand straight to kubectl.

This page walks the core cluster operations: create a cluster, connect to it, scale it, and manage its lifecycle. Every one of these operations is also available in the console. To work through the same tasks in the browser, see Kubernetes Clusters via UI. For per-endpoint parameters, schemas, and error codes, see the Clusters API reference.

How a cluster is assembled

A cluster is a set of virtual machines that Hyperstack provisions and wires together for you. Understanding the four node roles makes the API parameters below self-explanatory:

  • Master nodes run the Kubernetes control plane. They take a CPU-only flavor (n1-cpu-small, n1-cpu-medium, or n1-cpu-large), and every cluster runs 2 or 3 of them.
  • Worker nodes run your workloads and take any flavor, including GPU flavors. They are grouped into node groups that share a single flavor. A group named default is created for you.
  • Bastion and load balancer nodes provide SSH access and route external traffic. They are provisioned in full deployment mode and omitted in standard mode.

You never choose a node image. Hyperstack selects the image that matches your kubernetes_version, so every node in the cluster runs a consistent Kubernetes build. A cluster keeps the version it was deployed with, so to move to a newer version you deploy a new cluster and migrate your workloads.

Billing

Only worker nodes and public IP addresses are billed. Master, bastion, and load balancer nodes incur no resource-based charges, and billing for any node begins only once its underlying virtual machine reaches the ACTIVE state. See Cluster Billing & Data Retention.

Deploy and connect to a cluster via the API

Go from an empty environment to a cluster you can schedule workloads on. You create the cluster with one request, poll it until it reports ACTIVE, then read its kubeconfig from the same endpoint and hand it to kubectl.

Before you begin

You'll need:

Regional Availability

Clusters deploy in the CANADA-1 and NORWAY-1 regions. The US-1 region is not currently supported for cluster deployment.

Creating and scaling clusters is permission-gated. If a request fails because your account lacks permission, ask an organization admin to assign you a role that grants cluster management. See User Roles.

Set your API key in the shell so the snippets below work as-is. Replace your-api-key-here with the key you generated:

export HYPERSTACK_API_KEY="your-api-key-here"

Step 1: Create a cluster

  1. Choose a Kubernetes version and master flavor

    Supported versions are region-scoped, so list the cluster versions and pick one available in your environment's region:

    curl https://infrahub-api.nexgencloud.com/v1/core/clusters/versions \
    -H "api_key: $HYPERSTACK_API_KEY"

    Then list the master flavors to see the CPU-only flavors available for the control plane:

    curl https://infrahub-api.nexgencloud.com/v1/core/clusters/master-flavors \
    -H "api_key: $HYPERSTACK_API_KEY"
  2. Create the cluster

    Create the cluster with the request body below. Replace your-environment and your-keypair with your own names.

    • kubernetes_version: a version returned by the versions endpoint above, available in your environment's region
    • master_flavor_name: a CPU-only flavor for the control plane
    • master_count: number of control-plane nodes, either 2 or 3
    • node_flavor_name and node_count: the flavor and size of the default worker node group. To run several groups on different flavors, send a node_groups array instead (see the endpoint reference)
    • deployment_mode: full adds a bastion and a load balancer, standard provisions master and worker nodes only. Defaults to full
    curl https://infrahub-api.nexgencloud.com/v1/core/clusters \
    -H "api_key: $HYPERSTACK_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
    "name": "example-cluster",
    "environment_name": "your-environment",
    "keypair_name": "your-keypair",
    "kubernetes_version": "1.36.1",
    "master_flavor_name": "n1-cpu-small",
    "master_count": 2,
    "node_flavor_name": "n3-A100x1",
    "node_count": 1,
    "deployment_mode": "full"
    }'

    The response returns the cluster id and a CREATING status. Key fields shown below; the full response also includes keypair_name, created_at, green_status, and per-node instance objects:

    Response
    {
    "status": true,
    "message": "Cluster created successfully",
    "cluster": {
    "id": 1838,
    "name": "example-cluster",
    "environment_name": "your-environment",
    "environment_region": "CANADA-1",
    "kubernetes_version": "1.36.1",
    "status": "CREATING",
    "api_address": null,
    "kube_config": null,
    "master_count": 2,
    "master_flavor": { "name": "n1-cpu-small", "cpu": 4, "ram": 4.0, "disk": 100 },
    "image": { "name": "Ubuntu 24.04 LTS Hyperstack Kubernetes v1.36.1" },
    "node_groups": [
    {
    "id": 1233,
    "name": "default",
    "role": "worker",
    "flavor": { "name": "n3-A100x1", "gpu": "A100-80G-PCIe", "gpu_count": 1 },
    "count": 1
    }
    ],
    "nodes": [
    { "id": 9549, "role": "bastion", "status": "CREATING" },
    { "id": 9550, "role": "load-balancer", "status": "CREATING" },
    { "id": 9551, "role": "master", "status": "CREATING" },
    { "id": 9552, "role": "master", "status": "CREATING" },
    { "id": 9553, "role": "worker", "status": "CREATING" }
    ]
    }
    }

    Note the id. Substitute it for <cluster_id> in the steps that follow.

  3. Wait for the cluster to become ACTIVE

    Retrieve the cluster by ID and check its status:

    curl https://infrahub-api.nexgencloud.com/v1/core/clusters/<cluster_id> \
    -H "api_key: $HYPERSTACK_API_KEY"

    The cluster moves through CREATING while its virtual machines are provisioned, then RECONCILING while Kubernetes is installed and configured, and finally ACTIVE. Re-run the request until it reports ACTIVE. Larger clusters and larger GPU flavors take longer.

    Once the cluster is ACTIVE, api_address holds the Kubernetes API endpoint and kube_config holds the kubeconfig you need in Step 2.

Step 2: Connect to your cluster

The cluster's kube_config field holds a base64-encoded kubeconfig file. Decode it, point KUBECONFIG at it, and kubectl talks to your cluster.

  1. Retrieve and decode the kubeconfig

    Read kube_config from the cluster detail response and decode it into a local file. Replace <cluster_id> with your cluster's ID:

    B64_KUBECONFIG=$(curl -s https://infrahub-api.nexgencloud.com/v1/core/clusters/<cluster_id> \
    -H "api_key: $HYPERSTACK_API_KEY" | jq -r '.cluster.kube_config')

    echo "$B64_KUBECONFIG" | base64 -d > kubeconfig.yaml

    Any HTTP client works here. The field is populated on the same cluster-detail response you polled in Step 1.

  2. Point kubectl at the kubeconfig

    export KUBECONFIG=$PWD/kubeconfig.yaml
  3. Verify the connection

    kubectl get nodes

    Each master and worker node reports Ready:

    Output
    NAME                        STATUS   ROLES           AGE   VERSION
    example-cluster-default-0 Ready worker 5m v1.36.1
    example-cluster-master-0 Ready control-plane 6m v1.36.1
    example-cluster-master-1 Ready control-plane 5m v1.36.1

    Bastion and load balancer nodes do not appear here. They support the cluster's access and traffic paths rather than running workloads, so they are not registered as Kubernetes nodes.

If kubectl cannot reach the cluster, confirm the cluster reports ACTIVE and review the official Kubernetes troubleshooting guide.

You can also retrieve the kubeconfig through Terraform. See Creating Kubernetes clusters for a full example.

Scale your cluster

Add or remove nodes to match your workload. Both worker and master nodes can be added to a running cluster, within the limits below.

  • Each node group holds between 1 and 20 worker nodes, and every cluster keeps at least one worker node.
  • Every cluster keeps 2 or 3 master nodes.
  • All existing nodes must be ACTIVE before you add or remove a node, and scaling operations run one at a time.

While a node is added or removed the cluster reports RECONCILING, and existing nodes may briefly report RECONCILING or WAITING. Their virtual machines stay ACTIVE throughout, so running workloads are not interrupted.

Add and remove nodes

  1. List the cluster's nodes

    Retrieve the cluster's nodes to get each node's id, role, and status:

    curl https://infrahub-api.nexgencloud.com/v1/core/clusters/<cluster_id>/nodes \
    -H "api_key: $HYPERSTACK_API_KEY"
  2. Add nodes

    Add one or more nodes by specifying the role. Use worker with a node_group to grow a worker group, or master to add a control-plane node:

    curl -X POST https://infrahub-api.nexgencloud.com/v1/core/clusters/<cluster_id>/nodes \
    -H "api_key: $HYPERSTACK_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
    "role": "worker",
    "count": 1,
    "node_group": "default"
    }'
    Response
    {
    "status": true,
    "message": "WORKER Node Created Successfully",
    "nodes": [
    {
    "id": 9554,
    "node_group_name": "default",
    "role": "worker",
    "status": "CREATING",
    "instance": { "id": 923594, "name": "example-cluster-default-1", "status": "CREATING" }
    }
    ]
    }
  3. Remove a node

    Drain the node from Kubernetes first, so its workloads reschedule onto the remaining nodes:

    kubectl drain example-cluster-default-1 --ignore-daemonsets --delete-emptydir-data
    kubectl delete node example-cluster-default-1

    Then delete the node using its id from the node list:

    curl -X DELETE https://infrahub-api.nexgencloud.com/v1/core/clusters/<cluster_id>/nodes/<node_id> \
    -H "api_key: $HYPERSTACK_API_KEY"
    Response
    {
    "status": true,
    "message": "Nodes [9554] are being deleted."
    }

    To remove several nodes in one request, delete multiple cluster nodes by passing an array of node IDs.

Deleting a Node Destroys Its Data

Any data stored on a deleted node is permanently lost and cannot be recovered. Drain the node before deleting it, and keep data that must survive a node on persistent volumes provisioned through the CSI driver.

Working with node groups

A node group is a set of worker nodes that share one flavor. Deploying a cluster with node_flavor_name and node_count creates a single group named default. To run a mix of hardware in one cluster, add more groups, each with its own flavor:

Manage the cluster lifecycle

Review cluster events

Retrieve a cluster's events to see the actions performed on it, each with a timestamp, type, and reason. Events record cluster creation, node group creation, node additions and deletions, and the outcome of each reconciliation:

curl https://infrahub-api.nexgencloud.com/v1/core/clusters/<cluster_id>/events \
-H "api_key: $HYPERSTACK_API_KEY"

Reconcile a cluster

Reconciliation reapplies the intended configuration to a cluster. Hyperstack reconciles automatically during creation and scaling. You can trigger a reconciliation when a cluster is in an ERROR state or has stalled, provided it is not already RECONCILING:

curl -X POST https://infrahub-api.nexgencloud.com/v1/core/clusters/<cluster_id>/reconcile \
-H "api_key: $HYPERSTACK_API_KEY"

If reconciliation does not resolve the issue, delete the cluster and create a new one rather than retrying. See Cluster Reconciliation.

Delete a cluster

Clusters do not support hibernation and are billed until deleted. To stop all charges, delete the cluster:

curl -X DELETE https://infrahub-api.nexgencloud.com/v1/core/clusters/<cluster_id> \
-H "api_key: $HYPERSTACK_API_KEY"
Response
{
"status": true,
"message": "Cluster example-cluster is being deleted"
}

Deletion is permanent and includes all data not stored externally. To reduce cost without losing the cluster, remove worker nodes instead. See Cluster Billing & Data Retention.

Whitelisting worker node IP addresses

Third-party services that restrict access by IP address need the public addresses your worker nodes use for outbound traffic. Worker nodes carry no public IP of their own, so their outbound traffic leaves through a different address than the bastion and load balancer public IPs. Retrieve it by opening a debug container on a worker node and querying an external echo service:

# List the nodes in the cluster
kubectl get nodes

# Open a debug terminal on a worker node
kubectl debug node/example-cluster-default-0 -it --image=busybox

# Retrieve the public IP address
wget -qO- ifconfig.me/ip

The echo service returns the address on its own line:

Output
203.0.113.42

Repeat for each worker node, then add every address returned to the third-party service's allowlist.

For the ports each node role requires, and the rules to apply when you expose a service, see Firewall Rules for Kubernetes Clusters.

Next steps

Clusters API reference

Every cluster, node, and node group endpoint with full parameters and schemas.

Clusters via the Console

Run the same operations in the browser, plus node types, statuses, and billing detail.

CSI Driver

Provision persistent volumes so data survives a node being replaced.

Configuring Ingress

Route external traffic to services running in your cluster.

Firewall Rules

Minimum required firewall rules for each cluster node role.

Deploy an LLM with vLLM

Run a large language model on your cluster with the vLLM inference framework.

Back to top