Last Updated: Dec 23, 2025
Introduction
The Crusoe Managed Kubernetes (CMK) cluster can be provisioned using Terraform, with the added capability to export the Kubeconfig as a Yaml file. This guide provides step-by-step instructions for setting up a CMK cluster with an Infiniband (IB)-enabled GPU nodepool and exporting the Kubeconfig, all through Terraform. This Kubeconfig file can then be used to access the newly created CMK cluster.
Prerequisites
- Terraform
- Crusoe Quota to spin up desired GPU resources
- Crusoe authentication credentials
Step-by-Step Instructions
The following example demonstrates how to create a CMK cluster with a H100 GPU nodepool and export it to a file named kubeconfig.yaml in the current directory.
Note: Please run the mentioned comments in code to find out the latest CMK/nodepool version.
-
Copy the following text in a file named main.tf
############################################# # Provider config ############################################# terraform { required_providers { crusoe = { source = "crusoecloud/crusoe" } } } ################################################## # Local config ################################################## locals { project_id = "<project-id>" my_ssh_public_key = file("<path to ssh public key>") control_plane_version = "1.33.4-cmk.2" worker_version = "1.33.4-cmk.2" location = "<crusoe location>" # See `crusoe locations list` for location options add_ons = [ # "cluster_autoscaler", # "nvidia_gpu_operator", # "nvidia_network_operator", # "crusoe_csi", ] worker_count = 1 worker_type = "h100-80gb-sxm-ib.8x" # use any IB supported SKU kubeconfig_path = "./kubeconfig.yaml" ib_network_id = "<IB network id>" subnet_id = "<Subnet id>" } #################################################### # CMK Cluster creation resource "crusoe_kubernetes_cluster" "my_cluster" { name = "my-cluster" project_id = local.project_id # Set the desired CMK control plane version # See `crusoe kubernetes versions list` for available versions version = local.control_plane_version # See `crusoe locations list` for location options location = local.location # Optional: Set cluster/service CIDRs and node CIDR mask size # cluster_cidr = "192.168.1.0/24" # node_cidr_mask_size = "27" # service_cluster_ip_range = "192.168.2.0/24" # Optional: Add additional add-ons # See `crusoe kubernetes clusters create --help` for available add-ons # add_ons = local.add_ons # Optional: Configure OIDC authentication for Kubernetes # Replace with your own identity provider values # oidc_issuer_url = "https://auth.example.com/oauth2/aussah0123456bd97" # oidc_client_id = "0123456789abcdef" # oidc_username_claim = "sub" # typically "sub" or "email" # oidc_groups_claim = "groups" # claim used to identify user groups # oidc_username_prefix = "" # prefix prepended to username claim } ###### # IB Partition creation resource "crusoe_ib_partition" "my_partition" { name = "my-ib-partition" project_id = local.project_id # Available IB network IDs can be listed with the CLI by running # `crusoe networking ib-network list` ib_network_id = local.ib_network_id } ###### # Nodepool creation resource "crusoe_kubernetes_node_pool" "my_nodepool" { name = "my-nodepool" cluster_id = crusoe_kubernetes_cluster.my_cluster.id instance_count = local.worker_count # Optional: Set the desired CMK worker node version # If not specified, the default is the latest stable version compatible with the cluster # List available node pool versions with "crusoe kubernetes versions list" version = local.worker_version type = local.worker_type # Optional: Add your SSH public key to the created nodes to allow SSH access ssh_key = local.my_ssh_public_key # Optional: Set ib_partition_id when using IB supported GPU types, such as - A100-SXM,H200s,H100s etc. # See `crusoe networking ib-partitions list` for all in partitions created in your projects ib_partition_id = crusoe_ib_partition.my_partition.id # See `crusoe networking vpc-subnets list` for all available vpc subnets subnet_id = local.subnet_id # Optional: Kubernetes Node objects will be labeled with the following key:value pairs # requested_node_labels = { # "labelkey" = "labelvalue" # } # Optional: Use local ephemeral NVMe disks for containerd storage # ephemeral_storage_for_containerd = true lifecycle { ignore_changes = [ ssh_key, ] } } ###### # Kubeconfig resource "crusoe_kubeconfig" "my_cluster_kubeconfig" { cluster_id = crusoe_kubernetes_cluster.my_cluster.id # Optional: Specify authentication type for kubeconfig. # Supported values: "admin_cert" (default), "oidc" # auth_type = "oidc" } # Optional: Output the kubeconfig YAML to a file resource "local_file" "kubeconfig_file" { content = crusoe_kubeconfig.my_cluster_kubeconfig.kubeconfig_yaml filename = local.kubeconfig_path } ############################################# # Outputs ############################################# output "cluster" { value = crusoe_kubernetes_cluster.my_cluster } output "nodepool" { value = crusoe_kubernetes_node_pool.my_nodepool } -
Once all the placeholders above are updated, run the following commands to apply the code:
$ terraform plan $ terraform apply -
Export Kubeconfig file to access the cluster
$ export KUBECONFIG=<path to kubeconfig file> -
Run a `kubectl` command to verify the cluster is accessible
$ kubectl get nodes NAME STATUS ROLES AGE VERSION np-8fa7d1df-1.us-east1-a.compute.internal Ready 103s v1.33.4
Additional Information
- Setup CMK cluster in Non-Default VPC Using UI/CLI/Terraform
- Crusoe Terraform GitHub
- Crusoe Terraform Provider
- CMK Orchestration Docs