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
idString - A unique identifier for each cluster. This is automatically generated.nameString - The human-readable name set for the cluster.networkString - The ID of the private network the cluster nodes communicate on.cluster_versionString - The Kubernetes version the control plane runs (e.g.v1.33).deploy_csiBoolean - Whether the Epilayer CSI driver is deployed to this cluster.statusString - The cluster status. Possible values arecreating,upgrading,active,erroranddeleting.created_atString - A time value given in ISO8601 combined date and time format that represents when the cluster was created.updated_atString - 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
nameString Required - The human-readable name for the cluster.networkString Optional - The private network ID for the cluster. Worker nodes must be on this network.cluster_versionString Optional - The Kubernetes version (e.g.v1.33). Defaults to the current default version when omitted. Use the/kubernetes-versionsendpoint to list supported versions.deploy_csiBoolean Optional - Deploy the Epilayer CSI driver to this cluster. Defaults tofalse.worker_nodesObject 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
countInteger - Number of worker nodes to create (min: 1, max: 100).typeString - Instance type for the worker nodes (e.g.vcpu-4_memory-24g).imageString - Boot image ID for the worker nodes.ssh_keysArray - SSH key IDs to install on worker nodes (at least one required).security_groupsArray Optional - Security group IDs to attach to worker nodes.private_networksArray 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_pageInteger Optional - A positive integer lower or equal to 100 (default: 50).pageInteger 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_idString - 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_idString - 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_idString - Cluster ID.
Body parameters
nameString Optional - New name for the cluster.cluster_versionString Optional - Target Kubernetes version. Must be the same or one minor version higher than the current version (no version skipping, no downgrade).networkString 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_idString - Cluster ID.
Body parameters
nameString Optional - New name for the cluster.cluster_versionString 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.33tov1.35directly will be rejected — first upgrade tov1.34, then tov1.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_idString - 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.
| Annotation | Direction | Description |
|---|---|---|
epilayer.io/floating-ip | User → CCM | ID 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-name | User → CCM | Name 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-name | CCM → User | Written 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>"