Examples¶
Ready-to-adapt manifests. Replace names, domains, CIDRs, and image references with your environment's values.
-
Minimal VLAN
Smallest useful
Infra: DHCP + DNS + proxy, no apps ingress. -
Full hosted cluster stack
A complete, generic configuration: apps ingress, MetalLB, ExternalDNS metadata, and the pod-network proxy view.
-
Public OAuth VIP
Publishing the OAuth endpoint through the hosting-cluster MetalLB.
-
Multi-cluster VLAN
One shared Infra serving several hosted clusters via attachments.
Minimal VLAN infrastructure¶
One isolated network, three services, nothing else:
apiVersion: hostedcluster.densityops.com/v1alpha1
kind: Infra
metadata:
name: mycluster
namespace: clusters
spec:
networkConfig:
cidr: 192.0.2.0/24
gateway: 192.0.2.1
networkAttachmentDefinition: vlan100
networkAttachmentNamespace: default
dnsServers:
- "resolv.conf" # inherit node resolvers
infraComponents:
dhcp:
serverIP: 192.0.2.2
rangeStart: 192.0.2.100
rangeEnd: 192.0.2.199
dns:
serverIP: 192.0.2.3
proxy:
serverIP: 192.0.2.10
---
apiVersion: hostedcluster.densityops.com/v1alpha1
kind: InfraClusterAttachment
metadata:
name: mycluster
namespace: clusters
spec:
infraRef:
name: mycluster
hostedClusterRef:
name: mycluster
namespace: clusters
dns:
clusterName: mycluster
baseDomain: example.com
What you get:
| Resource | Address | Purpose |
|---|---|---|
DHCPServer/mycluster-dhcp |
192.0.2.2 |
Leases .100–.199 to worker VMs |
DNSServer/mycluster-dns |
192.0.2.3 |
Split-horizon answers + forwarding |
ProxyServer/mycluster-proxy |
192.0.2.10 |
SNI passthrough for api :6443 and HCP :443 |
No internalProxyService → management pods get no static HCP answers.
No attachment appsIngress → no wildcard routing; consoles reachable only from
the VLAN via explicit hostnames you add yourself.
Full hosted cluster stack¶
This configuration shows a complete HostedCluster/NodePool attachment with documentation-only names and addresses:
apiVersion: hostedcluster.densityops.com/v1alpha1
kind: Infra
metadata:
name: example-hcp
namespace: clusters
spec:
networkConfig:
cidr: 192.0.2.0/24
gateway: 192.0.2.1
networkAttachmentDefinition: vlan100
networkAttachmentNamespace: default
dnsServers:
- 198.51.100.53
- 198.51.100.54
infraComponents:
dhcp:
enabled: true
serverIP: 192.0.2.2
rangeStart: 192.0.2.100
rangeEnd: 192.0.2.199
leaseTime: 1h
dns:
enabled: true
serverIP: 192.0.2.3
proxy:
enabled: true
serverIP: 192.0.2.4
internalProxyService: example-hcp-proxy.clusters.svc.cluster.local
---
apiVersion: hostedcluster.densityops.com/v1alpha1
kind: InfraClusterAttachment
metadata:
name: example-hcp
namespace: clusters
spec:
infraRef:
name: example-hcp
hostedClusterRef:
name: example-hcp
namespace: clusters
dns:
clusterName: example-hcp
baseDomain: clusters.example.com
externalService:
enabled: true
addressPoolName: hosting-public-pool
annotations:
external-dns.alpha.kubernetes.io/hostname: oauth.example-hcp.clusters.example.com.
labels:
external-dns.example.com/publish: "yes"
appsIngress:
enabled: true
metallb:
addressPoolName: apps-pool
ipAddressPoolRange: 192.0.2.200-192.0.2.220
service:
name: oooi-ingress
namespace: openshift-ingress
annotations:
external-dns.alpha.kubernetes.io/hostname: "*.apps.example-hcp.clusters.example.com."
labels:
external-dns.example.com/publish: "yes"
ports:
http: 80
https: 443
Resulting addressing on the VLAN:
192.0.2.1 gateway
192.0.2.2 DHCP
192.0.2.3 CoreDNS
192.0.2.4 Envoy (SNI proxy)
192.0.2.200 *.apps wildcard VIP (MetalLB L2, advertised by a worker)
192.0.2.100+ DHCP pool for worker VMs
Plus one hosting-cluster MetalLB VIP for the attachment's generated OAuth
Service <attachment>-proxy-external.
When the KubeVirt worker Machines report addresses in 192.0.2.0/24, the
shared proxy receives two source-scoped backends for the four kubernetes.*
aliases: port 443 for hostname-SNI clients and port 6443 for the IP-based
Kubernetes Service path without SNI. Inspect both generated ranges with:
kubectl -n clusters get proxyserver example-hcp-proxy \
-o jsonpath='{range .spec.backends[?(@.name=="example-hcp-kubernetes-hostname")].sourcePrefixRanges}{.}{"\n"}{end}'
kubectl -n clusters get proxyserver example-hcp-proxy \
-o jsonpath='{range .spec.backends[?(@.name=="example-hcp-kubernetes-service")].sourcePrefixRanges}{.}{"\n"}{end}'
The aliases are omitted until those Machine addresses are available. Fully
qualified api.example-hcp.clusters.example.com remains the bootstrap path.
Public OAuth VIP¶
The minimal delta that puts OAuth on a public VIP when the HostedCluster uses
the Route OAuth publishing strategy (see
Public DNS and OAuth publishing):
spec:
externalService:
enabled: true
addressPoolName: hosting-public-pool
annotations:
external-dns.alpha.kubernetes.io/hostname: oauth.mycluster.example.com.
labels:
external-dns.example.com/publish: "yes"
Behavior notes:
- Creates Service
<attachment>-proxy-external, typeLoadBalancer, port 443 only — never Envoy admin9901. addressPoolNamebecomes themetallb.universe.tf/address-poolannotation; omit it to use the cluster's default allocation policy.- Labels/annotations are reconciled on every sync; remove
enabled(or set it false) and the Service is deleted — then ExternalDNS cleans up its records.
More samples in the repository¶
| File | Shows |
|---|---|
config/samples/hostedcluster_v1alpha1_infra.yaml |
Infra scaffold |
config/samples/hostedcluster_v1alpha1_infraclusterattachment.yaml |
Attachment scaffold |
config/samples/hostedcluster_v1alpha1_dhcpserver.yaml etc. |
Individual child CRs |
| Hosted-cluster ExternalDNS sample | The repository includes a lab-specific manifest; adapt its structure, not its identifiers |
config/samples/openshift-example.yaml |
OpenShift-flavored example |