Gardner cluster IPAddress and DNS management

Dilip Kumar
9 min readJan 25, 2025

--

Chapter 1: Introduction to IP Management in Gardener

What is IP Management (IPAM)?

IPAM (IP Address Management) is the process of planning, tracking, and managing the allocation and usage of IP addresses in a network.

Importance in Gardener?

  • Ensures efficient and conflict-free allocation of IP addresses for resources in Shoot, Seed, and Garden clusters.
  • Supports dynamic scaling and automation in Kubernetes clusters.

Chapter 2: IP Management in Shoot Clusters

2.1 Overview

  • Shoot clusters are end-user Kubernetes clusters managed by Gardener.
  • IP management is critical for nodes, Pods, services, and load balancers.

2.2 Node IP Allocation

Worker nodes are assigned IP addresses from the node CIDR specified in the Shoot resource.

The infrastructure controller creates a subnet in the cloud provider’s VPC. The Machine Controller Manager (MCM) provisions worker nodes, and the cloud provider assigns IPs from the subnet.

Sample Shoot Configuration for Nodes IP Allocation

apiVersion: core.gardener.cloud/v1beta1
kind: Shoot
metadata:
name: my-shoot
namespace: garden-my-project
spec:
networking:
nodes: 10.250.0.0/16 # CIDR for Nodes
provider:
type: gcp
infrastructureConfig:
networks:
workers: 10.250.0.0/16 # Subnet for worker nodes

gcp extension controller code reference

The infrastructure controller creates subnets in the GCP VPC:

// pkg/controller/infrastructure/reconcile.go

func (a *actuator) reconcileInfrastructure(ctx context.Context, infra *extensionsv1alpha1.Infrastructure, cluster *controller.Cluster) error {
client, err := a.getGCPClient(ctx, infra, cluster)
if err != nil {
return err
}

// Create or update the subnet
subnet, err := client.CreateOrUpdateSubnet(ctx, infra, cluster)
if err != nil {
return err
}

// Update the infrastructure status
infra.Status.ProviderStatus = &runtime.RawExtension{
Object: &gcpapi.InfrastructureStatus{
Subnets: []gcpapi.Subnet{
{
Name: subnet.Name,
CIDR: subnet.CIDR,
},
},
},
}

return nil
}

The infrastructure controller configures firewall rules:

// pkg/controller/infrastructure/reconcile.go

func (a *actuator) reconcileFirewallRules(ctx context.Context, client gcpclient.Interface, infra *extensionsv1alpha1.Infrastructure, cluster *controller.Cluster) error {
rules := []gcpapi.FirewallRule{
{
Name: "allow-ssh",
Network: cluster.Shoot.Spec.Networking.Nodes,
SourceRanges: []string{"0.0.0.0/0"},
Allowed: []gcpapi.Allowed{
{
Protocol: "tcp",
Ports: []string{"22"},
},
},
},
}

for _, rule := range rules {
if err := client.CreateOrUpdateFirewallRule(ctx, rule); err != nil {
return err
}
}

return nil
}

2.3 Pod IP Allocation

Pods are assigned IP addresses from the pod CIDR specified in the Shoot resource. The CNI plugin (e.g., Calico, Cilium) manages IP allocation for Pods.

Sample Shoot Configuration for Pod IP Allocation

apiVersion: core.gardener.cloud/v1beta1
kind: Shoot
metadata:
name: my-shoot
namespace: garden-my-project
spec:
networking:
pods: 100.96.0.0/11 # CIDR for Pods

2.4 Service IP Allocation

Kubernetes services (e.g., ClusterIP, LoadBalancer) are assigned IP addresses from the service CIDR.

For LoadBalancer services, the cloud provider allocates a public IP and configures a load balancer.

Sample Shoot Configuration for Service IP Allocation

apiVersion: core.gardener.cloud/v1beta1
kind: Shoot
metadata:
name: my-shoot
namespace: garden-my-project
spec:
networking:
services: 100.64.0.0/13 # CIDR for Services

2.5 API Server IP Allocation

The Kubernetes API server requires a public or private IP address.

The controlplane controller allocates an IP for the API server.

Sample Shoot Configuration for Service IP Allocation

apiVersion: core.gardener.cloud/v1beta1
kind: Shoot
spec:
provider:
type: gcp
controlPlaneConfig:
apiServer:
dns:
domain: api.example.com
service:
type: LoadBalancer
loadBalancerIP: 203.0.113.10 # Optional: Static IP for API server

Chapter 3: IP Management in Seed Clusters

3.1 Overview

  • Seed clusters host the control plane of Shoot clusters.
  • IP management is required for control plane components and networking.

3.2 Control Plane IPs

Control plane components (e.g., API server, etcd) need IP addresses. The Seed controller manages IP allocation for control plane components.

3.3 LoadBalancer IPs

If the API server is exposed via a load balancer, a public IP address is required.

The cloud provider allocates a public IP for the load balancer.

Chapter 4: IP Management in Garden Clusters

4.1 Overview

  • The Garden cluster is the management cluster for Gardener.
  • IP management is required for the Gardener control plane.

4.2 Control Plane IPs

Gardener control plane components (e.g., Gardener API server) need IP addresses.

IP management is typically handled manually or using external tools (e.g., Terraform).

Chapter 5: IP Allocation using AddressPoolClaim

5.1 AddressPoolClaim

A custom resource for requesting IP addresses from a predefined pool. For example, allocating static IPs for LoadBalancer services or API servers.

Sample AddressPoolClaim

apiVersion: networking.gardener.cloud/v1alpha1
kind: AddressPoolClaim
metadata:
name: my-address-claim
spec:
poolRef:
name: my-address-pool
purpose: LoadBalancer
status:
allocatedAddress: 203.0.113.10

5.2 SubnetClaim

A custom resource for requesting subnets. It used to allocate subnets for worker nodes.

Sample SubnetClaim:

apiVersion: networking.gardener.cloud/v1alpha1
kind: SubnetClaim
metadata:
name: worker-node-network-subnet
spec:
cidr: 10.250.0.0/16

Chapter 6: Introduction to DNS Management in Gardener

6.1 What is DNS Management?

DNS (Domain Name System) management involves configuring and managing domain names and their mappings to IP addresses.

Importance in Gardener

  • Enables human-readable domain names for accessing Kubernetes clusters and services.
  • Supports dynamic DNS record creation and updates for Shoot clusters.

Chapter 7: DNS Management in Shoot Clusters

7.1 Overview

Shoot clusters require DNS management for:

  • API Server: A domain name for accessing the Kubernetes API server.
  • Ingress: Domain names for applications exposed via ingress controllers.
  • Services: Domain names for services of type LoadBalancer.

7.2 DNSRecord Resource

A custom resource (DNSRecord) is used to define DNS records for Shoot clusters.

Purpose: Maps domain names to IP addresses (e.g., for the API server or ingress).

Sample DNSRecord CRD

apiVersion: dns.gardener.cloud/v1alpha1
kind: DNSRecord
metadata:
name: api-server-dns-record
namespace: garden-my-project
spec:
zone: example.com.
name: api.example.com.
recordType: A
values:
- 203.0.113.10
ttl: 300
status:
observedGeneration: 1
state: Ready
message: "DNS record successfully reconciled"

DNSRecord Reconciliation

The DNS controller reconciles DNSRecord resources:

// pkg/controller/dnsrecord/actuator.go

func (a *actuator) Reconcile(ctx context.Context, dns *extensionsv1alpha1.DNSRecord, cluster *extensionscontroller.Cluster) error {
// Get the DNS provider client
client, err := a.getDNSClient(ctx, dns, cluster)
if err != nil {
return err
}

// Create or update the DNS record
if err := client.CreateOrUpdateDNSRecord(dns.Spec.Zone, dns.Spec.Name, dns.Spec.RecordType, dns.Spec.Values, dns.Spec.TTL); err != nil {
return err
}

// Update the DNSRecord status
dns.Status.ObservedGeneration = dns.Generation
dns.Status.State = extensionsv1alpha1.DNSRecordStateReady
dns.Status.Message = "DNS record successfully reconciled"

return nil
}

7.3 DNSProvider Resource

A custom resource (DNSProvider) defines the DNS provider (e.g., GCP Cloud DNS, AWS Route 53) and credentials.

Purpose: Specifies where DNS records should be created.

Sample DNSProvider CRD:

apiVersion: dns.gardener.cloud/v1alpha1
kind: DNSProvider
metadata:
name: gcp-dns-provider
namespace: garden-my-project
spec:
type: google-clouddns
secretRef:
name: gcp-dns-credentials
domains:
include:
- example.com.

DNSProvider Client

The DNS controller interacts with the DNS provider:

// pkg/controller/dnsrecord/client.go

type DNSClient interface {
CreateOrUpdateDNSRecord(zone, name, recordType string, values []string, ttl int) error
DeleteDNSRecord(zone, name, recordType string) error
}

type GCPDNSClient struct {
client *dns.Service
}

func (c *GCPDNSClient) CreateOrUpdateDNSRecord(zone, name, recordType string, values []string, ttl int) error {
// Logic to create or update DNS record in GCP Cloud DNS
return nil
}

func (c *GCPDNSClient) DeleteDNSRecord(zone, name, recordType string) error {
// Logic to delete DNS record in GCP Cloud DNS
return nil
}

7.4 DNS Controller

The DNS controller reconciles DNSRecord resources and interacts with the DNS provider to create/update DNS records.

Chapter 8: DNS Management in Seed Clusters

8.1 Overview

Seed clusters host the control plane of Shoot clusters. DNS management is required for:

  • Control Plane: Domain names for the API server and other control plane components.
  • Networking: Domain names for internal communication.

8.2 Control Plane DNS

The API server and other control plane components need domain names for external access.

The Seed controller manages DNS records for control plane components.

8.3 Internal DNS

Domain names for internal communication between Seed and Shoot clusters.

The Seed controller configures internal DNS records.

Chapter 9: DNS Management in Garden Clusters

9.1 Overview

The Garden cluster is the management cluster for Gardener. DNS management is required for:

  • Gardener Control Plane: Domain names for the Gardener API server and other components.
  • Networking: Domain names for internal communication.

9.2 Gardener Control Plane DNS

The Gardener API server and other components need domain names for external access.

DNS management is typically handled manually or using external tools (e.g., Terraform).

Chapter 10: DNS Management

10.1 DNS CNAME Records

CNAME records are used to alias one domain name to another.

Use Case: Mapping a custom domain name to the API server or ingress.

Sample DNSRecord for CNAME:

apiVersion: dns.gardener.cloud/v1alpha1
kind: DNSRecord
metadata:
name: app-cname-record
namespace: garden-my-project
spec:
zone: example.com.
name: app.example.com.
recordType: CNAME
values:
- example.com.
ttl: 300

10.2 DNS TXT Records

TXT records are used to store text data, often for verification or configuration.

Use Case: Domain verification for TLS certificates.

Sample DNSRecord for TXT

apiVersion: dns.gardener.cloud/v1alpha1
kind: DNSRecord
metadata:
name: verification-txt-record
namespace: garden-my-project
spec:
zone: example.com.
name: example.com.
recordType: TXT
values:
- "v=spf1 include:_spf.example.com ~all"
ttl: 300

Chapter 11: Subnet, IPAddress and DNS management flow

11.1 Overview

+-------------------+       +-------------------+       +-------------------+
| | | | | |
| Shoot Resource | | Infrastructure | | GCP Cloud DNS |
| (CIDR Ranges) | | Controller | | (DNS Records) |
| | | | | |
+--------+----------+ +--------+----------+ +--------+----------+
| | |
| 1. Define CIDR Ranges | |
+-------------------------->| |
| | 2. Create Subnet in VPC |
| +-------------------------->|
| | |
| | 3. Allocate Subnet |
| +-------------------------->|
| | |
| | 4. Provision Worker Nodes |
| +-------------------------->|
| | |
| | 5. Assign IPs to Nodes |
| +-------------------------->|
| | |
| | 6. Create DNSRecord CR |
| +-------------------------->|
| | |
| | 7. Map IP to DNS Record |
| +-------------------------->|
| | |
| | 8. Update DNS Provider |
| +-------------------------->|
| | |
+--------+----------+ +--------+----------+ +--------+----------+
| | | | | |
| Node IPs | | DNS Controller | | DNS Records |
| (e.g., 10.250.0.2)| | | | (e.g., api.example.com)|
| | | | | |
+-------------------+ +-------------------+ +-------------------+

11.2 Step-by-Step Flow

Step 1: Define CIDR Ranges in Shoot Resource

The user specifies the node CIDR, pod CIDR, and service CIDR in the Shoot resource.

apiVersion: core.gardener.cloud/v1beta1
kind: Shoot
metadata:
name: my-shoot
namespace: garden-my-project
spec:
networking:
nodes: 10.250.0.0/16 # CIDR for Nodes
pods: 100.96.0.0/11 # CIDR for Pods
services: 100.64.0.0/13 # CIDR for Services
provider:
type: gcp
infrastructureConfig:
networks:
workers: 10.250.0.0/16 # Subnet for worker nodes

Step 2: Infrastructure Controller Creates Subnet

The Infrastructure Controller creates a subnet in the GCP VPC based on the node CIDR specified in the Shoot resource.

// pkg/controller/infrastructure/reconcile.go

func (a *actuator) reconcileInfrastructure(ctx context.Context, infra *extensionsv1alpha1.Infrastructure, cluster *controller.Cluster) error {
client, err := a.getGCPClient(ctx, infra, cluster)
if err != nil {
return err
}

// Create or update the subnet
subnet, err := client.CreateOrUpdateSubnet(ctx, infra, cluster)
if err != nil {
return err
}

// Update the infrastructure status
infra.Status.ProviderStatus = &runtime.RawExtension{
Object: &gcpapi.InfrastructureStatus{
Subnets: []gcpapi.Subnet{
{
Name: subnet.Name,
CIDR: subnet.CIDR,
},
},
},
}

return nil
}

Step 3: Machine Controller Manager (MCM) Provisions Worker Nodes

  • The Machine Controller Manager (MCM) provisions worker nodes in the specified subnet.
  • GCP assigns IP addresses to the worker nodes from the subnet (10.250.0.0/16).

Step 4: Assign IPs to Nodes

Each worker node is assigned an IP address from the subnet (e.g., 10.250.0.2, 10.250.0.3).

Step 5: Create DNSRecord Resource

The Shoot Controller in the Gardener Control Plane is responsible for creating the DNSRecord resource to map the API server’s IP address to a domain name (e.g., api.example.com).

The Shoot Controller reads the Shoot resource’s configuration to determine the domain name and IP address for the API server.

The domain name is typically derived from the Shoot resource’s spec.dns.domain field.

apiVersion: core.gardener.cloud/v1beta1
kind: Shoot
metadata:
name: my-shoot
namespace: garden-my-project
spec:
dns:
domain: example.com # Base domain for the Shoot cluster
networking:
nodes: 10.250.0.0/16
provider:
type: gcp
controlPlaneConfig:
apiServer:
service:
type: LoadBalancer
loadBalancerIP: 203.0.113.10 # Optional: Static IP for API server

Once the DNSRecord resource is created, the DNS Controller takes over to reconcile the resource and create the actual DNS record in the DNS provider (e.g., GCP Cloud DNS).

Step 6: DNS Controller Reconciles DNSRecord

The DNS Controller watches for DNSRecord resources. When a DNSRecord is created or updated, the DNS Controller:

  1. Reads the DNSRecord specification (e.g., domain name, IP address, record type).
  2. Interacts with the DNS provider (e.g., GCP Cloud DNS) to create or update the DNS record.
  3. Updates the DNSRecord status to reflect the reconciliation result.
// pkg/controller/dnsrecord/actuator.go

func (a *actuator) Reconcile(ctx context.Context, dns *extensionsv1alpha1.DNSRecord, cluster *extensionscontroller.Cluster) error {
client, err := a.getDNSClient(ctx, dns, cluster)
if err != nil {
return err
}

// Create or update the DNS record
if err := client.CreateOrUpdateDNSRecord(dns.Spec.Zone, dns.Spec.Name, dns.Spec.RecordType, dns.Spec.Values, dns.Spec.TTL); err != nil {
return err
}

// Update the DNSRecord status
dns.Status.ObservedGeneration = dns.Generation
dns.Status.State = extensionsv1alpha1.DNSRecordStateReady
dns.Status.Message = "DNS record successfully reconciled"

return nil
}

Step 7: Map IP to DNS Record

The DNS provider (e.g., GCP Cloud DNS) creates a DNS record mapping the domain name (api.example.com) to the IP address (203.0.113.10).

Step 8: Update DNS Provider

The DNS provider updates its records, making the domain name (api.example.com) resolvable to the IP address (203.0.113.10).

This post is based on interaction with https://chat.deepseek.com/. LLM is changing the way we study and write :)

Enjoy learning Gardener’s internals :-)

--

--

Dilip Kumar
Dilip Kumar

Written by Dilip Kumar

With 18+ years of experience as a software engineer. Enjoy teaching, writing, leading team. Last 4+ years, working at Google as a backend Software Engineer.

No responses yet