3.2 Set Up Load Balancing¶
The load balancer module (modules/loadbalancer.pkl) creates a Network Load Balancer (NLB) that provides access to the Kubernetes API and Talos API on the control plane nodes. This is deployed as part of formae apply via main.pkl.
Step 1: Configure Load Balancer Variables¶
Open vars.pkl (or your environment override) and set the NLB parameters:
/// Deploy NLB as internal (true) or internet-facing (false).
nlbInternal: Boolean = true
/// Prevent accidental NLB deletion (disable for teardown workflows).
enableDeletionProtection: Boolean = false
/// Distribute NLB traffic across all AZs.
enableCrossZoneLoadBalancing: Boolean = true
Internal NLB (nlbInternal = true) — requires VPN or bastion host to reach the control plane from outside the VPC. Use this for production.
Internet-facing NLB (nlbInternal = false) — the NLB gets a public DNS name. Combine with allowedAdminCidr in the security group to restrict access. Use this for demo/testing:
// In envs/demo.pkl
nlbInternal = false
enableDeletionProtection = false
enableCrossZoneLoadBalancing = false // Single AZ, not needed
Health Check Tuning¶
/// NLB health check interval in seconds.
healthCheckInterval: Int = 10
/// NLB health check timeout in seconds.
healthCheckTimeout: Int = 5
/// Consecutive successful checks before marking target healthy.
healthyThreshold: Int = 2
/// Consecutive failed checks before marking target unhealthy.
unhealthyThreshold: Int = 2
Step 2: Understand the Module¶
The module is at modules/loadbalancer.pkl. It imports the network and compute modules to reference subnet IDs and instance IDs.
Network Load Balancer¶
local apiNlb = new loadbalancer.LoadBalancer {
label = "\(vars.environment)-talos-api-nlb"
name = "\(vars.environment)-talos-api-nlb"
scheme = if (vars.nlbInternal) "internal" else "internet-facing"
type = "network"
subnets = network.publicSubnetIds
loadBalancerAttributes {
new loadbalancer.LoadBalancerAttribute {
key = "deletion_protection.enabled"
value = if (vars.enableDeletionProtection) "true" else "false"
}
new loadbalancer.LoadBalancerAttribute {
key = "load_balancing.cross_zone.enabled"
value = if (vars.enableCrossZoneLoadBalancing) "true" else "false"
}
}
tags = makeTags(new Mapping {
["Name"] = "\(vars.environment)-talos-api-nlb"
["Purpose"] = "kubernetes-api"
})
}
Key points:
scheme— toggles between"internal"and"internet-facing"based onvars.nlbInternalsubnets— placed in public subnets (fromnetwork.publicSubnetIds)- Attributes are key-value pairs passed as
LoadBalancerAttributeobjects
Target Groups¶
Two target groups forward traffic to all control plane instances:
Kubernetes API (port 6443):
local k8sApiTg = new targetgroup.TargetGroup {
label = "\(vars.environment)-talos-api-tg"
name = "\(vars.environment)-talos-api-tg"
port = 6443
protocol = "TCP"
vpcId = network.vpcId
targetType = "instance"
healthCheckEnabled = true
healthCheckIntervalSeconds = vars.healthCheckInterval
healthCheckPort = "6443"
healthCheckProtocol = "TCP"
healthCheckTimeoutSeconds = vars.healthCheckTimeout
healthyThresholdCount = vars.healthyThreshold
unhealthyThresholdCount = vars.unhealthyThreshold
targetGroupAttributes {
new targetgroup.TargetGroupAttribute {
key = "deregistration_delay.timeout_seconds"
value = "30"
}
new targetgroup.TargetGroupAttribute {
key = "preserve_client_ip.enabled"
value = "true"
}
}
targets {
for (_idx, instId in compute.controlPlaneInstanceIds) {
new targetgroup.TargetDescription {
id = instId
port = 6443
}
}
}
}
Key points:
targets— dynamically populated fromcompute.controlPlaneInstanceIdsusing aforlooppreserve_client_ip.enabled = "true"— the NLB preserves the original source IPderegistration_delay.timeout_seconds = "30"— allows in-flight requests to complete before removing a target
Talos API (port 50000) follows the same pattern but on port 50000.
Listeners¶
Each listener forwards TCP traffic from the NLB to its target group:
local k8sApiListener = new listener.Listener {
label = "\(vars.environment)-talos-api-listener"
loadBalancerArn = apiNlb.res.loadBalancerArn
port = 6443
protocol = "TCP"
defaultActions {
new listener.Action {
type = "forward"
targetGroupArn = k8sApiTg.res.targetGroupArn
}
}
}
Step 3: Module Exports¶
/// NLB DNS name for external access.
nlbDnsName = apiNlb.res.dnsName
/// Kubernetes API endpoint URL.
kubernetesApiEndpoint = "https://\(apiNlb.res.dnsName):6443"
/// Talos API endpoint.
talosApiEndpoint = "\(apiNlb.res.dnsName):50000"
These exported values are used when configuring talosctl and kubectl after deployment:
# Configure talosctl to use the NLB endpoint
talosctl config endpoint <nlbDnsName>
# The kubeconfig will use the NLB DNS as the server URL
# https://<nlbDnsName>:6443
Customisation Summary¶
| What to Change | Where | Variable |
|---|---|---|
| Internal vs internet-facing | vars.pkl |
nlbInternal |
| Deletion protection | vars.pkl |
enableDeletionProtection |
| Cross-zone load balancing | vars.pkl |
enableCrossZoneLoadBalancing |
| Health check interval | vars.pkl |
healthCheckInterval |
| Health check timeout | vars.pkl |
healthCheckTimeout |
| Healthy/unhealthy thresholds | vars.pkl |
healthyThreshold, unhealthyThreshold |
Warning
The deregistration delay (30s) and client IP preservation are hardcoded in the module. To change these, edit modules/loadbalancer.pkl directly.