Skip to main content

Kubernetes Clusters

A Kubernetes cluster is a managed control plane that you can attach worker nodes (Epilayer instances) to. The cluster exposes a kubeconfig that lets you interact with it via kubectl or any other Kubernetes tooling.

Optionally, the Epilayer Cloud Controller Manager (CCM) can be deployed inside the cluster to automatically provision load balancers and update node metadata when LoadBalancer-type Services are created.

Cluster Schema

  • id String - A unique identifier for each cluster. This is automatically generated.
  • name String - The human-readable name set for the cluster.
  • network String - The ID of the private network the cluster nodes communicate on.
  • cluster_version String - The Kubernetes version the control plane runs (e.g. v1.33).
  • deploy_csi Boolean - Whether the Epilayer CSI driver is deployed to this cluster.
  • status String - The cluster status. Possible values are creating, upgrading, active, error and deleting.
  • created_at String - A time value given in ISO8601 combined date and time format that represents when the cluster was created.
  • updated_at String - A time value given in ISO8601 combined date and time format that represents when the cluster was last updated.

List Supported Kubernetes Versions

Returns the Kubernetes versions that can be used when creating or upgrading a cluster.

GET /compute/v1/kubernetes-versions (HTTP 200 - OK)

Response body

{
"versions": [
{
"name": "v1.33",
"version": "v1.33.7",
"is_default": true
},
{
"name": "v1.34",
"version": "v1.34.8",
"is_default": false
}
]
}

Create a Kubernetes Cluster

POST /compute/v1/kubernetes-clusters (HTTP 201 - Created)

Body parameters

  • name String Required - The human-readable name for the cluster.

  • network String Optional - The private network ID for the cluster. Worker nodes must be on this network.

  • cluster_version String Optional - The Kubernetes version (e.g. v1.33). Defaults to the current default version when omitted. Use the /kubernetes-versions endpoint to list supported versions.

  • deploy_csi Boolean Optional - Deploy the Epilayer CSI driver to this cluster. Defaults to false.

  • worker_nodes Object Optional - Provision worker nodes alongside the cluster. Node creation is best-effort: if the cluster is created but some nodes fail, per-node error details are included in the response.

    Worker node parameters

    • count Integer - Number of worker nodes to create (min: 1, max: 100).
    • type String - Instance type for the worker nodes (e.g. vcpu-4_memory-24g).
    • image String - Boot image ID for the worker nodes.
    • ssh_keys Array - SSH key IDs to install on worker nodes (at least one required).
    • security_groups Array Optional - Security group IDs to attach to worker nodes.
    • private_networks Array Optional - Private network IDs for the worker nodes. Defaults to the cluster network when omitted. The cluster network must always be included.
{
"name": "my-cluster",
"network": "3f4e5d6c-7b8a-9012-cdef-1234567890ab",
"cluster_version": "v1.33",
"deploy_csi": true,
"worker_nodes": {
"count": 3,
"type": "vcpu-4_memory-24g",
"image": "ac26fa2b-c6d5-47a7-bc4e-5a219797e70f",
"ssh_keys": ["45bcd3ac-fccd-4eea-a812-21f01d665464"]
}
}

Response body

{
"cluster": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "my-cluster",
"network": "3f4e5d6c-7b8a-9012-cdef-1234567890ab",
"cluster_version": "v1.33",
"deploy_csi": true,
"status": "creating",
"created_at": "2024-01-15T10:00:00.000Z",
"updated_at": "2024-01-15T10:00:00.000Z"
},
"worker_nodes": [
{ "name": "a1b2c3d4-e5f6-7890-abcd-ef1234567890-worker-1", "instance_id": "9e8ce501-d692-402c-8fca-5a8f5d8ddd57" },
{ "name": "a1b2c3d4-e5f6-7890-abcd-ef1234567890-worker-2", "instance_id": "7c6d5e4f-3a2b-1098-fedc-ba9876543210" },
{ "name": "a1b2c3d4-e5f6-7890-abcd-ef1234567890-worker-3", "error": "quota exceeded" }
]
}

List all Kubernetes Clusters

GET /compute/v1/kubernetes-clusters (HTTP 200 - OK)

Query parameters

  • per_page Integer Optional - A positive integer lower or equal to 100 (default: 50).
  • page Integer Optional - A positive integer to choose the page to return.

Response body

{
"clusters": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "my-cluster",
"network": "3f4e5d6c-7b8a-9012-cdef-1234567890ab",
"cluster_version": "v1.33.7",
"deploy_csi": true,
"status": "active",
"created_at": "2024-01-15T10:00:00.000Z",
"updated_at": "2024-01-15T10:05:00.000Z"
}
],
"total_count": 1,
"page": 1,
"per_page": 50
}

Get a Kubernetes Cluster

GET /compute/v1/kubernetes-clusters/{cluster_id} (HTTP 200 - OK)

Path parameters

  • cluster_id String - Cluster ID.

Response body

{
"cluster": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "my-cluster",
"network": "3f4e5d6c-7b8a-9012-cdef-1234567890ab",
"cluster_version": "v1.33.7",
"deploy_csi": true,
"status": "active",
"created_at": "2024-01-15T10:00:00.000Z",
"updated_at": "2024-01-15T10:05:00.000Z"
}
}

Get Cluster Credentials

Retrieves the kubeconfig for a cluster. Requires the k8s-clusters:admin scope.

GET /compute/v1/kubernetes-clusters/{cluster_id}/credentials (HTTP 200 - OK)

Path parameters

  • cluster_id String - Cluster ID.

Response body

{
"kubeconfig": "apiVersion: v1\nclusters:\n- ...",
"join_command": "kubeadm join ..."
}

Save the kubeconfig and use it with kubectl:

TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
CLUSTER_ID=a1b2c3d4-e5f6-7890-abcd-ef1234567890

curl -H "Authorization: Bearer $TOKEN" \
"https://public-api.krs-1.epilayer.eu/compute/v1/kubernetes-clusters/$CLUSTER_ID/credentials" \
| jq -r '.kubeconfig' > kubeconfig.yaml

kubectl --kubeconfig kubeconfig.yaml get nodes

Update a Kubernetes Cluster

Replace all mutable fields of a cluster.

PUT /compute/v1/kubernetes-clusters/{cluster_id} (HTTP 200 - OK)

Path parameters

  • cluster_id String - Cluster ID.

Body parameters

  • name String Optional - New name for the cluster.
  • cluster_version String Optional - Target Kubernetes version. Must be the same or one minor version higher than the current version (no version skipping, no downgrade).
  • network String Optional - The network field cannot be changed after cluster creation.

Partially Update a Kubernetes Cluster

Update only the fields you provide.

PATCH /compute/v1/kubernetes-clusters/{cluster_id} (HTTP 200 - OK)

Path parameters

  • cluster_id String - Cluster ID.

Body parameters

  • name String Optional - New name for the cluster.
  • cluster_version String Optional - Target Kubernetes version. Must be the same or one minor version higher than the current version (no version skipping, no downgrade).
{
"cluster_version": "v1.34.8"
}

Version skew policy: Kubernetes only supports upgrading one minor version at a time. For example, upgrading from v1.33 to v1.35 directly will be rejected — first upgrade to v1.34, then to v1.35. Downgrading is not supported.

Response body

{
"cluster": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "my-cluster",
"network": "3f4e5d6c-7b8a-9012-cdef-1234567890ab",
"cluster_version": "v1.34.8",
"deploy_csi": true,
"status": "upgrading",
"created_at": "2024-01-15T10:00:00.000Z",
"updated_at": "2024-02-01T09:00:00.000Z"
}
}

Delete a Kubernetes Cluster

DELETE /compute/v1/kubernetes-clusters/{cluster_id} (HTTP 204 - No Content)

Path parameters

  • cluster_id String - Cluster ID.

Cloud Controller Manager (CCM)

The Epilayer CCM integrates a cluster with the Epilayer API. When running inside your cluster, it watches LoadBalancer-type Services and automatically provisions or removes Epilayer load balancers to back them.

Service Annotations

The following annotations can be set on a Kubernetes Service of type LoadBalancer to control how the CCM provisions the backing load balancer.

AnnotationDirectionDescription
epilayer.io/floating-ipUser → CCMID of an existing floating IP to assign as the external IP of the load balancer. When omitted, an ephemeral IP is allocated automatically.
epilayer.io/floating-ip-nameUser → CCMName of a floating IP to assign as the external IP. If a floating IP with this name already exists it is reused; otherwise a new one is created automatically. Takes precedence over epilayer.io/floating-ip when both are set. Use this to maintain a stable external IP across Service re-creations without needing to know the floating IP ID in advance.
epilayer.io/loadbalancer-nameCCM → UserWritten back by the CCM once the load balancer is created. Shows the name of the Epilayer load balancer backing this Service. Read-only; do not set manually.

Example: Service with a reserved floating IP (by ID)

apiVersion: v1
kind: Service
metadata:
name: my-service
annotations:
epilayer.io/floating-ip: "db1bf06d-528d-4fac-96d8-390798f83388"
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 8080

Example: Service with a floating IP created by name

apiVersion: v1
kind: Service
metadata:
name: my-service
annotations:
epilayer.io/floating-ip-name: "my-service-ip"
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 8080

After the CCM processes the Service, it adds the epilayer.io/loadbalancer-name annotation and Kubernetes populates .status.loadBalancer.ingress[].ip with the external IP.

Examples (cURL)

# List supported Kubernetes versions
curl -H "Authorization: Bearer $TOKEN" \
"https://public-api.krs-1.epilayer.eu/compute/v1/kubernetes-versions"
# Create a cluster
curl -H "Authorization: Bearer $TOKEN" \
-X POST "https://public-api.krs-1.epilayer.eu/compute/v1/kubernetes-clusters" \
-H "Content-Type: application/json" \
--data-raw '{
"name": "my-cluster",
"network": "3f4e5d6c-7b8a-9012-cdef-1234567890ab",
"cluster_version": "v1.33"
}'
# List all clusters
curl -H "Authorization: Bearer $TOKEN" \
"https://public-api.krs-1.epilayer.eu/compute/v1/kubernetes-clusters"
# Get a cluster
curl -H "Authorization: Bearer $TOKEN" \
"https://public-api.krs-1.epilayer.eu/compute/v1/kubernetes-clusters/<cluster_id>"
# Get cluster credentials (kubeconfig)
curl -H "Authorization: Bearer $TOKEN" \
"https://public-api.krs-1.epilayer.eu/compute/v1/kubernetes-clusters/<cluster_id>/credentials"
# Upgrade to the next minor version
curl -H "Authorization: Bearer $TOKEN" \
-X PATCH "https://public-api.krs-1.epilayer.eu/compute/v1/kubernetes-clusters/<cluster_id>" \
-H "Content-Type: application/json" \
--data-raw '{"cluster_version": "v1.34.8"}'
# Delete a cluster
curl -H "Authorization: Bearer $TOKEN" \
-X DELETE "https://public-api.krs-1.epilayer.eu/compute/v1/kubernetes-clusters/<cluster_id>"