All Products
Search
Document Center

Container Service for Kubernetes:Configure custom parameters for managed CoreDNS

Last Updated:Mar 17, 2026

When you deploy containerized applications to a cluster, you often need to resolve external domain names in addition to in-cluster service names. Container Service for Kubernetes (ACK) lets you customize DNS behavior for managed CoreDNS by creating a CustomDNSConfig custom resource (CR). Use this to route specific domains to upstream DNS servers, map hostnames to static IP addresses, or override the default resolver for all queries.

Overview

ACK's managed CoreDNS exposes a cluster-scoped CustomDNSConfig CustomResourceDefinition (CRD) in the networking.alibabacloud.com/v1beta1 API group. When you create or update the default CR, a controller reconciles it into the CoreDNS ConfigMap (Corefile) and triggers a live reload — no pod restarts required.

The CustomDNSConfig CRD is cluster-scoped with a single instance named default. This design ensures a single authoritative DNS configuration per cluster and prevents conflicts between multiple configurations. To update the configuration, apply changes to the existing CR rather than creating a new one.

How it works:

CustomDNSConfig CR (default)
        ↓  controller reconciles
CoreDNS ConfigMap (Corefile)
        ↓  CoreDNS reloads (~20 seconds)
Live DNS resolution updated

CR template

The following example shows the full structure of a CustomDNSConfig CR with all supported fields and placeholder values:

apiVersion: networking.alibabacloud.com/v1beta1
kind: CustomDNSConfig
metadata:
  name: default
  namespace: default
spec:
  zones:
  - name: example.com
    forward:
      protocolStrategy: ""
      transportConfig: {}
      upstreams:
      - xxx.xxx.xxx.xxx     # IP address
      - xxx.xxx.xxx.xxx:53  # IP:port
    hosts:
    - hostName: "a.example.com"
      ipAddress: xxx.xxx.xxx.xxx

CR field reference

The following table describes the fields in the CustomDNSConfig CR:

  • spec.zones[].name: string, required, default ".". DNS zone name. Must be a fully qualified domain name (FQDN). The special zone "." matches all queries and represents the default resolver.

  • spec.zones[].forward.upstreams: []string, optional. Upstream DNS server addresses. Format: IP or IP:PORT. IPv4 only. Maximum 15 addresses per zone. If not set, Alibaba Cloud DNS PrivateZone is used.

  • spec.zones[].forward.protocolStrategy: string, optional, default "". Transport protocol. "" uses UDP; tcp forces TCP.

  • spec.zones[].forward.transportConfig: object, optional, default {}. TLS transport configuration. Cannot be changed.

  • spec.zones[].hosts[].hostName: string, required. Hostname to map statically. Must comply with DNS naming rules.

  • spec.zones[].hosts[].ipAddress: string, required. IPv4 address for the hostname.

Zone concept: A zone defines a DNS namespace. Specifying example.com matches example.com and all subdomains (for example, api.example.com). The special zone "." matches all queries and represents the default resolver.

The forward plugin routes queries for a zone to the specified upstream DNS servers. Use this for private domains hosted on on-premises DNS or another cloud DNS service.

The hosts plugin serves static hostname-to-IP mappings without querying an upstream server. Use this when you need a small number of fixed hostname overrides.

Prerequisites

Constraints

  • You can only create one CustomDNSConfig CR, and it must be named default. If you create a CR with any other name, its phase is set to NotSupported and the configuration is ignored.

  • The upstreams field supports IPv4 addresses only (format: IP or IP:PORT). Maximum 15 addresses per zone.

  • The ipAddress field in hosts entries supports IPv4 addresses only.

  • The transportConfig field cannot be modified.

Scenario 1: Configure a custom zone

Use this scenario to route queries for a specific domain to an upstream DNS server, or to map hostnames in a domain to static IP addresses.

The following example configures two custom zones:

  • example.com — routes all queries to upstream DNS servers 100.100.2.136 and 100.100.2.138 (the default internal DNS resolution service addresses; see Endpoints for details).

  • foo.com — maps a.foo.com and b.foo.com to static IP addresses using the hosts plugin.

Step 1: Create the CR manifest.

Create a file named default.yaml with the following content:

apiVersion: networking.alibabacloud.com/v1beta1
kind: CustomDNSConfig
metadata:
  name: default   # Must be named "default"
spec:
  zones:
  - name: example.com
    forward:
      upstreams:
      - 100.100.2.136  # Set the upstream DNS server addresses for example.com to 100.100.2.136 and 100.100.2.138.
      - 100.100.2.138
  - name: foo.com
    hosts:
    - hostName: "a.foo.com"  # Configure custom static IP addresses for a.foo.com and b.foo.com in the foo.com zone.
      ipAddress: 192.168.0.251
    - hostName: "b.foo.com"
      ipAddress: 192.168.0.252
Note

100.100.2.136 and 100.100.2.138 are the default internal DNS resolution service addresses allocated by the system. For more information, see Endpoints.

Step 2: Apply the manifest.

kubectl apply -f default.yaml

Step 3: Verify that the Corefile was generated.

kubectl get customdnsconfig default -o yaml | grep corefile -A 35 -B 1

Expected output:

status:
  corefile: |
    example.com:53 {
        prometheus :9153
        forward .  100.100.2.136 100.100.2.138 {
          policy random
          prefer_udp
        }
    ...
    }
    foo.com:53 {
        prometheus :9153
        hosts {
          192.168.0.251    a.foo.com
          192.168.0.252    b.foo.com
          fallthrough
        }
        forward .  /etc/resolv.conf {
          policy random
          prefer_udp
        }
    ...
    }
  ...
--
  corefileHash: 41f7be21cf3022c305091665ed33b1e5
  lastTransitionTime: "2024-09-13T09:07:37Z"
  phase: GenerateSuccess

The phase: GenerateSuccess status confirms that the CR was accepted and the Corefile was generated.

Step 4: Verify DNS resolution.

After the configuration reloads (approximately 20 seconds), run a test pod to confirm that DNS queries resolve correctly:

# Test that example.com resolves via the upstream DNS servers
kubectl run -it --rm dns-test --image=busybox:1.28 --restart=Never -- nslookup example.com

# Test that the static host mapping works for foo.com
kubectl run -it --rm dns-test --image=busybox:1.28 --restart=Never -- nslookup a.foo.com

The nslookup output should show the addresses you configured (192.168.0.251 for a.foo.com, 192.168.0.252 for b.foo.com).

Note

You can map a single hostname to multiple IP addresses. For example:

hosts:
  - hostName: "a.example.com"
    ipAddress: 10.0.0.123
  - hostName: "a.example.com"
    ipAddress: 10.0.0.124

Scenario 2: Modify the default zone configuration

Use this scenario to change the upstream DNS servers for all cluster queries — that is, to override the built-in default resolver zone (".").

Note

spec.zones configures custom zones. Use spec.zones with name: "." to override the upstream servers for the default zone that handles all cluster queries.

Step 1: Create the CR manifest.

Create a file named default.yaml with the following content:

apiVersion: networking.alibabacloud.com/v1beta1
kind: CustomDNSConfig
metadata:
  name: default   # Must be named "default"
spec:
  zones:
  - name: .
    forward:
      upstreams:
      - 100.100.2.136  # The upstream DNS server addresses for the custom default zone named "." are 100.100.2.136 and 100.100.2.138.
      - 100.100.2.138

Step 2: Apply the manifest.

kubectl apply -f default.yaml

Step 3: Verify that the Corefile was generated.

kubectl get customdnsconfig default -o yaml | grep corefile -A 35 -B 1

Expected output:

status:
  corefile: |
    .:53 {
        errors
        health {
          lameduck 20s
        }
        ready
        kubeapi {
          kubeconfig /etc/kubernetes/config/managed-coredns.conf
        }
        k8s_event {
          level error warning
        }
    ...
        prometheus :9153
        forward .  100.100.2.136 100.100.2.138 {
          policy random
          prefer_udp
        }
    ...
    }
  corefileHash: 847bf69cc4c97cee965945f45d17c661
  lastTransitionTime: "2024-09-13T09:54:22Z"
  phase: GenerateSuccess

The phase: GenerateSuccess status confirms that the default zone configuration was updated.

Step 4: Verify DNS resolution.

After the configuration reloads (approximately 20 seconds), run a test pod to confirm that external queries route through the configured upstream servers:

kubectl run -it --rm dns-test --image=busybox:1.28 --restart=Never -- nslookup kubernetes.default.svc.cluster.local
Note

After you create or modify the CustomDNSConfig CR, CoreDNS performs a configuration reload, which takes approximately 20 seconds. You can adjust the reload duration by modifying the lameduck value in the Corefile. The default value is 20 seconds.

Troubleshooting

CR named something other than default shows NotSupported

You can only create one CustomDNSConfig CR per cluster, and it must be named default. If you create a CR with a different name, the controller sets its phase to NotSupported and ignores it.

The following example demonstrates this behavior.

Step 1: Create a file named test.yaml with a non-default CR name.

apiVersion: networking.alibabacloud.com/v1beta1
kind: CustomDNSConfig
metadata:
  name: test  ## You can create only a CustomDNSConfig CR named default.
spec:
  zones:
  - name: example.com
    forward:
      upstreams:
      - 100.100.2.138
  - name: foo.com
    hosts:
    - hostName: "ah.foo.com"
      ipAddress: 1.1.xx.251
    - hostName: "aha.foo.com"
      ipAddress: 1.1.xx.252

Step 2: Apply the manifest.

kubectl apply -f test.yaml

Step 3: Check the status of all CustomDNSConfig CRs.

kubectl get customdnsconfig

Expected output:

NAME      PHASE             VERSION                            AGE
default   GenerateSuccess   847bf69cc4c97cee96xxxxxxxxxxx      89m
test      NotSupported                                         9s

The test CR shows NotSupported, confirming that only the CR named default is accepted. To fix this, delete the incorrectly named CR and apply your configuration to the default CR instead:

kubectl delete customdnsconfig test
kubectl apply -f default.yaml

Event information

The custom CoreDNS controller synchronizes event information to the default namespace. Use these events to confirm successful configuration sync or to diagnose failures.

Run the following command to view events:

kubectl get events

Expected output:

LAST SEEN   TYPE     REASON                  OBJECT                           MESSAGE
45m         Normal   CustomDNSConfigSyncOk   customdnsconfig/default          custom dns config sync to coredns configmap success

The following table describes the event types:

  • Normal / CustomDNSConfigSyncOk: The CR was successfully reconciled into the CoreDNS ConfigMap. No action required.

  • NotSupported: The CR name is not default. The configuration was rejected. Delete the CR and reapply with name: default.

To monitor the status of the CR in real time while changes propagate:

kubectl get customdnsconfig default -w