Traffic Flow¶
Each Pool owns a Kubernetes Service that selects Server pods by label. The CA server can participate in both pools - handling CA requests via its dedicated pool and also serving catalog requests through the server pool.
LoadBalancer Services¶
The simplest setup - each Pool gets its own external IP:
graph LR
Agent["Agents"] --> LB
Agent --> CA_SVC
subgraph Kubernetes
LB["Pool: puppet<br/>Service (LoadBalancer)"]
CA_SVC["Pool: puppet-ca<br/>Service (LoadBalancer)"]
LB --> CA["Server: ca<br/>replicas: 1"]
LB --> Stable["Server: stable<br/>replicas: 3"]
LB --> Canary["Server: canary<br/>replicas: 1"]
CA_SVC --> CA
end
This works well for single-environment setups. For multiple environments, each Pool creates a separate LoadBalancer, which can become expensive.
Gateway API TLSRoute¶
All Pools share a single LoadBalancer, routed by SNI hostname. Since Puppet uses mTLS, TLS passthrough is required - the Gateway does not terminate TLS.
graph LR
Agent["Agents"] --> GW
subgraph Kubernetes
GW["Gateway<br/>(shared LoadBalancer)"]
GW --> TR1["TLSRoute<br/>puppet.example.com"]
GW --> TR2["TLSRoute<br/>puppet-ca.example.com"]
TR1 --> LB["Pool: puppet<br/>Service (ClusterIP)"]
TR2 --> CA_SVC["Pool: puppet-ca<br/>Service (ClusterIP)"]
LB --> CA["Server: ca<br/>replicas: 1"]
LB --> Stable["Server: stable<br/>replicas: 3"]
LB --> Canary["Server: canary<br/>replicas: 1"]
CA_SVC --> CA
end
With this setup, Pools use ClusterIP Services and the Gateway handles external access. Adding a new environment only requires a new TLSRoute - no additional LoadBalancer.
See Gateway API for the full configuration guide.