How Cloudfleet provisions nodes
If you’re coming from traditional Kubernetes, you’re probably familiar with node pools and cluster autoscaling. Cloudfleet takes a fundamentally different approach that eliminates upfront capacity planning entirely. This guide explains both provisioning models, highlights the key differences, and helps you choose the right approach for your infrastructure.
Traditional Kubernetes vs Cloudfleet
Traditional Kubernetes: the node pool model
In traditional Kubernetes environments like EKS, GKE, AKS, or self-managed clusters, infrastructure provisioning follows a capacity-first approach. You must plan and provision nodes before deploying workloads:
Define node pools upfront: Create groups of nodes with specific instance types, sizes, and configurations. For example, you might create a “general-purpose” pool with
m5.largeinstances and a “gpu-workloads” pool withp3.2xlargeinstances.Set scaling boundaries: Configure minimum and maximum node counts for each pool. The cluster autoscaler operates within these boundaries, scaling up when pods are pending and scaling down when nodes are underutilized.
Match workloads to pools: Use node selectors, taints, tolerations, or affinity rules to ensure pods land on appropriate node pools. A machine learning job needs to target the GPU pool; a web server targets the general-purpose pool.
Manage multiple configurations: As your workload diversity grows, so does the complexity. Different teams need different instance types. Some workloads need spot instances for cost savings. Others require specific CPU architectures. Each requirement often means another node pool to configure and maintain.
The challenge: This model requires you to predict your infrastructure needs before deploying workloads. You must decide on instance types, plan for peak capacity, and continuously tune your node pool configurations. Overprovisioning wastes money; underprovisioning causes deployment failures.
Cloudfleet: workload-driven provisioning
Cloudfleet inverts this model with a workload-first approach. Instead of pre-configuring infrastructure to match anticipated workloads, you deploy workloads and let Cloudfleet provision the optimal infrastructure automatically.
Cloudfleet offers two complementary approaches to node provisioning:
| Aspect | Node auto-provisioning | Self-managed nodes |
|---|---|---|
| How it works | Cloudfleet automatically provisions optimal nodes based on your pod specifications | You provision machines and register them with Cloudfleet |
| Supported infrastructure | AWS, GCP, Hetzner Cloud | Any Linux server (cloud, on-premises, edge, bare metal) |
| Capacity planning | None required; scales to zero when idle | You manage capacity and availability |
| Node lifecycle | Fully automated: provisioning, OS updates, security patches, repairs, and deletion | You manage the underlying infrastructure; Cloudfleet manages Kubernetes components |
| Cost optimization | Automatic instance type selection, bin-packing, and spot instance support | You control costs through your own provisioning and purchasing decisions |
| Best for | Primary compute on supported cloud providers | On-premises data centers, other cloud providers, specialized hardware, compliance requirements |
Node auto-provisioning via Fleets
Node auto-provisioning is Cloudfleet’s flagship capability for supported cloud providers. It represents a paradigm shift from traditional Kubernetes: you never create or manage node pools. Instead, you simply deploy workloads, and Cloudfleet handles everything else.
How it works
Connect your cloud account: Create a Fleet that authorizes Cloudfleet to provision resources in your AWS, GCP, or Hetzner Cloud account. A Fleet defines which regions, instance families, and capacity types (on-demand, spot) Cloudfleet can use.
Deploy your workloads: Submit pods with resource requests (CPU, memory, GPU) and optional scheduling constraints (node selectors, affinity rules, topology spread). This is standard Kubernetes; no Cloudfleet-specific configuration required.
Cloudfleet analyzes requirements: When a pod enters a Pending state because no suitable node exists, Cloudfleet’s node auto-provisioner analyzes the pod’s requirements: resource requests, node selectors, affinity rules, and topology constraints.
Optimal node provisioning: Cloudfleet selects the most cost-effective instance type that satisfies all requirements. It considers your Fleet’s constraints (allowed regions, instance families, spot vs on-demand) and provisions the node directly in your cloud account.
Automatic cleanup: When pods are deleted or scaled down, Cloudfleet identifies underutilized nodes and automatically terminates them. Your cluster can scale down to zero worker nodes when no workloads are running, ensuring you only pay for compute when you actually need it.
Example deployment
# Just deploy your workload. Cloudfleet handles the infrastructure.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: my-app:latest
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
When you apply this deployment, Cloudfleet examines the resource requests (512Mi memory, 500m CPU per replica), considers the total requirements for all three replicas, and provisions the most cost-effective node configuration. If you later scale to 10 replicas, Cloudfleet automatically provisions additional capacity. Scale back down, and unused nodes are terminated.
Controlling node selection without node pools
While Cloudfleet handles provisioning automatically, you retain full control over where and how your workloads run through standard Kubernetes scheduling mechanisms:
- Resource requests: Specify CPU, memory, and GPU requirements. Cloudfleet provisions nodes with sufficient capacity.
- Node selectors: Target specific cloud providers, regions, availability zones, or instance types using well-known labels.
- Node affinity: Define complex placement rules with required or preferred constraints.
- Topology spread: Distribute pods across availability zones or regions for high availability.
- Taints and tolerations: Reserve specific node types for particular workloads.
# Example: Run on AWS in eu-west-1, prefer spot instances
spec:
nodeSelector:
cfke.io/provider: aws
topology.kubernetes.io/region: eu-west-1
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: karpenter.sh/capacity-type
operator: In
values:
- spot
The key difference from traditional Kubernetes: you express requirements at the workload level, not the infrastructure level. You don’t pre-create a “spot instances in eu-west-1” node pool. You simply tell Cloudfleet what you need, and it provisions matching infrastructure on demand.
For complete details on all available labels and scheduling options, see the Node auto-provisioning documentation.
Self-managed nodes
Self-managed nodes extend your Cloudfleet cluster to infrastructure that Cloudfleet cannot directly provision. This includes on-premises servers, cloud providers without native Fleet support, edge locations, specialized hardware, or any scenario where you need direct control over the underlying machines.
How it works
With self-managed nodes, the provisioning model differs from node auto-provisioning:
You provision the infrastructure: Create VMs, provision bare-metal servers, or configure existing machines. The machines must run Ubuntu 22.04 or 24.04 and have SSH access.
Register nodes with Cloudfleet: Use the Cloudfleet CLI or Terraform to register each machine with your cluster. Cloudfleet connects via SSH, installs required components (kubelet, container runtime, networking), and joins the node to your cluster.
Cloudfleet manages Kubernetes components: Once registered, Cloudfleet handles Kubernetes-level operations: kubelet configuration, certificate rotation, and CNI networking. Your nodes participate fully in the cluster and can run any workload.
You manage the underlying infrastructure: Hardware failures, OS updates, capacity planning, and machine lifecycle remain your responsibility. Cloudfleet does not automatically replace failed self-managed nodes.
Use cases for self-managed nodes
Self-managed nodes are the right choice when:
On-premises requirements: Your workloads must run in your own data centers due to data sovereignty, compliance, or latency requirements. See the Proxmox guide for an example of on-premises virtualization.
Other cloud providers: You use cloud providers like OVH, Scaleway, Vultr, Exoscale, or regional providers where node auto-provisioning isn’t available yet.
Specialized hardware: Your workloads require specific GPU models, FPGAs, custom networking cards, or other hardware not available through standard cloud instance types.
Existing infrastructure investments: You have existing servers, reserved instances, or committed use discounts that you want to leverage within your Kubernetes cluster.
Edge and hybrid deployments: You need to run workloads close to users or data sources in locations without direct cloud provider presence.
Adding self-managed nodes
You can add self-managed nodes using either the Cloudfleet CLI or Terraform. Both methods connect to your server via SSH, install the required Kubernetes components, and register the node with your cluster.
Using the CLI:
cloudfleet clusters add-self-managed-node CLUSTER_ID \
--host HOST_IP \
--ssh-username SSH_USERNAME \
--ssh-key SSH_KEY_LOCATION \
--region DATACENTER_REGION \
--zone DATACENTER_ZONE
Using Terraform:
resource "cloudfleet_self_managed_node" "worker" {
cluster_id = cloudfleet_cluster.example.id
host = "192.168.1.100"
ssh_username = "ubuntu"
ssh_key = file("~/.ssh/id_rsa")
region = "on-premises"
zone = "datacenter-1"
}
The region and zone values you specify become Kubernetes node labels (cfke.io/region and cfke.io/zone). This allows you to target self-managed nodes with standard node selectors, keeping your workload definitions portable and consistent with auto-provisioned nodes.
Automating self-managed node provisioning
While you manage the underlying infrastructure, you can automate the entire provisioning pipeline using Terraform. Combine cloud provider Terraform resources (to create VMs) with the Cloudfleet Terraform provider (to register nodes) for fully automated infrastructure-as-code deployments.
For complete Terraform examples with specific cloud providers, see the guides for:
For complete details on requirements, GPU support, and node removal, see the Self-managed nodes documentation.
Choosing the right approach
Use this decision framework to determine which provisioning method fits your needs:
Is your infrastructure on AWS, GCP, or Hetzner Cloud?
│
├── Yes → Use node auto-provisioning (Fleets)
│
│ Benefits:
│ • Zero capacity planning or node pool management
│ • Automatic scaling including scale-to-zero
│ • Cost optimization through intelligent instance selection
│ • Fully managed node lifecycle (provisioning, updates, repairs)
│ • Pay only for compute when workloads are running
│
└── No → Use self-managed nodes
When to use:
• Other cloud providers (OVH, Scaleway, Vultr, Exoscale, etc.)
• On-premises data centers and private clouds
• Edge locations and remote sites
• Specialized hardware (specific GPUs, FPGAs, custom networking)
• Compliance requirements mandating infrastructure control
• Leveraging existing hardware investments
Combining both approaches
Many Cloudfleet users combine both approaches in a single cluster, leveraging the strengths of each. All nodes, whether auto-provisioned or self-managed, connect to each other through Cloudfleet’s secure overlay network. This means workloads on an AWS node can communicate directly with workloads on an on-premises server as if they were on the same local network. For details on how this works, see the networking architecture documentation.
Node auto-provisioning for elastic, general-purpose compute on supported cloud providers. Web applications, batch jobs, and variable workloads benefit from automatic scaling and cost optimization.
Self-managed nodes for specific requirements that demand infrastructure control. On-premises databases, GPU training clusters with specific hardware, or workloads with strict compliance requirements.
Kubernetes scheduling features let you control which workloads run on which nodes. Use node selectors to target specific infrastructure:
# Example: Run only on self-managed on-premises nodes
spec:
nodeSelector:
cfke.io/region: on-premises
cfke.io/zone: datacenter-1
# Example: Run on auto-provisioned cloud nodes, avoid on-premises
spec:
nodeSelector:
cfke.io/provider: aws
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: cfke.io/region
operator: NotIn
values:
- on-premises
Frequently asked questions
Q: Do I need to create node pools in Cloudfleet?
No. With node auto-provisioning, Cloudfleet dynamically provisions the right nodes based on your workload specifications. There are no predefined node pools to configure or manage. You express your requirements at the workload level (resource requests, node selectors, affinity rules), and Cloudfleet provisions matching infrastructure on demand.
This eliminates the operational overhead of maintaining multiple node pool configurations and the risk of capacity mismatches between pools and workloads.
Q: What happens when I delete a deployment?
With node auto-provisioning, Cloudfleet continuously monitors node utilization. When pods are deleted and nodes become underutilized, Cloudfleet cordons the node, drains remaining pods to other nodes, and terminates the instance. Your cluster can scale down to zero worker nodes when no workloads are running, ensuring you only pay for infrastructure while it’s actually in use.
For self-managed nodes, the nodes remain in your cluster until you explicitly remove them. Cloudfleet does not automatically terminate self-managed infrastructure.
Q: How do I ensure high availability?
Use Kubernetes topology spread constraints to distribute pods across failure domains. For auto-provisioned nodes, Cloudfleet provisions nodes in the appropriate availability zones to satisfy your constraints:
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: my-app
For self-managed nodes, ensure you register nodes across multiple zones or racks and use the region and zone labels to enable topology-aware scheduling.
Q: Can I migrate from traditional node pools to Cloudfleet?
Yes. Your existing Kubernetes workloads work without modification. Deployments, StatefulSets, Jobs, and other resources use standard Kubernetes APIs. Simply deploy them to your CFKE cluster, and Cloudfleet handles the infrastructure.
Any node selectors or affinity rules you’ve defined will continue to work. Cloudfleet recognizes standard Kubernetes labels (topology.kubernetes.io/zone, node.kubernetes.io/instance-type, etc.) and provisions matching nodes automatically.
Q: How does Cloudfleet choose which instance type to provision?
Cloudfleet’s node auto-provisioner evaluates all instance types available in your Fleet configuration and selects the most cost-effective option that satisfies the pod’s requirements. It considers:
- Resource requests (CPU, memory, GPU)
- Node selectors and affinity rules
- Fleet constraints (allowed regions, instance families, capacity types)
- Current spot pricing and availability
- Bin-packing efficiency (fitting multiple pods on a single node when possible)
You don’t need to specify instance types unless you have specific requirements. Cloudfleet handles the optimization automatically.
Q: What’s the difference between node auto-provisioning and self-managed nodes?
Node auto-provisioning is a fully automated system where Cloudfleet creates, manages, and deletes cloud instances based on your workload requirements. You never interact with the underlying VMs directly. This is available for AWS, GCP, and Hetzner Cloud.
Self-managed nodes are machines you provision and control. You create the VM or bare-metal server, then register it with Cloudfleet. Cloudfleet installs Kubernetes components and manages the node’s cluster membership, but you’re responsible for the underlying infrastructure. Use self-managed nodes for on-premises servers, other cloud providers, or specialized hardware requirements.
Q: Can I use both node auto-provisioning and self-managed nodes in the same cluster?
Yes. This is a common pattern. You might use node auto-provisioning for elastic cloud workloads that benefit from automatic scaling and cost optimization, while using self-managed nodes for on-premises databases, specialized GPU hardware, or workloads with specific compliance requirements. Kubernetes scheduling features let you control which workloads run on which type of node.
Q: Will node auto-provisioning support more cloud providers in the future?
Yes. Cloudfleet is actively working to expand node auto-provisioning support to additional cloud providers. In the meantime, you can use self-managed nodes with Terraform to automate node provisioning on any cloud provider. Check our release notes for announcements about new provider support.
Next steps
- Node auto-provisioning: Deep dive into workload-driven provisioning, scheduling constraints, and available labels
- Self-managed nodes: Complete guide for bringing your own infrastructure, including GPU support
- Terraform provider: Automate cluster and node provisioning with infrastructure-as-code
- Fleets: Configure cloud provider connections and define provisioning constraints
- Getting started: Deploy your first application on Cloudfleet
← What is Cloudfleet?