Set up a custom kube-dns Deployment

This document explains how to customize the DNS setup in your Google Kubernetes Engine (GKE) Standard cluster by replacing the default, GKE-managed kube-dns with your own deployment. This gives you more control over your cluster's DNS provider. For example, you can:

  • Fine-tune CPU and memory resources for DNS components.
  • Use a specific kube-dns image version.
  • Deploy an alternative DNS provider, such as CoreDNS, that adheres to the Kubernetes DNS specification.

This document is only for Standard clusters; Google manages the DNS configuration in Autopilot clusters. For a deeper understanding of DNS providers in GKE, see About service discovery and kube-dns.

Caution: If you run a custom DNS deployment, you are responsible for its ongoing maintenance. This includes ensuring the kube-dns and autoscaler container images are up to date with the latest versions and security patches. To find the latest recommended images, inspect the default kube-dns deployment in the kube-system namespace of a GKE cluster.

This document is for GKE users, including Developers and Admins and architects. To learn more about common roles and example tasks in Google Cloud, see Common GKE Enterprise user roles and tasks.

This document assumes you are familiar with the following:

Set up a custom kube-dns deployment

This section explains how to replace the GKE-managed kube-dns with your own deployment.

Create and deploy the custom manifest

  1. Save the following Deployment manifest as custom-kube-dns.yaml. This manifest uses kube-dns.

    apiVersion: apps/v1 kind: Deployment metadata:  name: DNS_DEPLOYMENT_NAME  namespace: kube-system  labels:  k8s-app: kube-dns  annotations:  deployment.kubernetes.io/revision: "1" spec:  selector:  matchLabels:  k8s-app: kube-dns  strategy:  rollingUpdate:  maxSurge: 10%  maxUnavailable: 0  type: RollingUpdate  template:  metadata:  creationTimestamp: null  labels:  k8s-app: kube-dns  spec:  containers:  - name: kubedns  image: registry.k8s.io/dns/k8s-dns-kube-dns:1.22.28  resources:  limits:  memory: '170Mi'  requests:  cpu: 100m  memory: '70Mi'  livenessProbe:  httpGet:  path: /healthcheck/kubedns  port: 10054  scheme: HTTP  initialDelaySeconds: 60  timeoutSeconds: 5  successThreshold: 1  failureThreshold: 5  readinessProbe:  httpGet:  path: /readiness  port: 8081  scheme: HTTP  initialDelaySeconds: 3  timeoutSeconds: 5  args:  - --domain=cluster.local.  - --dns-port=10053  - --config-dir=/kube-dns-config  - --v=2  env:  - name: PROMETHEUS_PORT  value: "10055"  ports:  - containerPort: 10053  name: dns-local  protocol: UDP  - containerPort: 10053  name: dns-tcp-local  protocol: TCP  - containerPort: 10055  name: metrics  protocol: TCP  volumeMounts:  - name: kube-dns-config  mountPath: /kube-dns-config  securityContext:  allowPrivilegeEscalation: false  readOnlyRootFilesystem: true  runAsUser: 1001  runAsGroup: 1001  - name: dnsmasq  image: registry.k8s.io/dns/k8s-dns-dnsmasq-nanny:1.22.28  livenessProbe:  httpGet:  path: /healthcheck/dnsmasq  port: 10054  scheme: HTTP  initialDelaySeconds: 60  timeoutSeconds: 5  successThreshold: 1  failureThreshold: 5  args:  - -v=2  - -logtostderr  - -configDir=/etc/k8s/dns/dnsmasq-nanny  - -restartDnsmasq=true  - --  - -k  - --cache-size=1000  - --no-negcache  - --dns-forward-max=1500  - --log-facility=-  - --server=/cluster.local/127.0.0.1#10053  - --server=/in-addr.arpa/127.0.0.1#10053  - --server=/ip6.arpa/127.0.0.1#10053  ports:  - containerPort: 53  name: dns  protocol: UDP  - containerPort: 53  name: dns-tcp  protocol: TCP  resources:  requests:  cpu: 150m  memory: 20Mi  volumeMounts:  - name: kube-dns-config  mountPath: /etc/k8s/dns/dnsmasq-nanny  securityContext:  capabilities:  drop:  - all  add:  - NET_BIND_SERVICE  - SETGID  - name: sidecar  image: registry.k8s.io/dns/k8s-dns-sidecar:1.22.28  livenessProbe:  httpGet:  path: /metrics  port: 10054  scheme: HTTP  initialDelaySeconds: 60  timeoutSeconds: 5  successThreshold: 1  failureThreshold: 5  args:  - --v=2  - --logtostderr  - --probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.cluster.local,5,SRV  - --probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.cluster.local,5,SRV  ports:  - containerPort: 10054  name: metrics  protocol: TCP  resources:  requests:  memory: 20Mi  cpu: 10m  securityContext:  allowPrivilegeEscalation: false  readOnlyRootFilesystem: true  runAsUser: 1001  runAsGroup: 1001  dnsPolicy: Default  restartPolicy: Always  schedulerName: default-scheduler  securityContext: {}  serviceAccount: kube-dns  serviceAccountName: kube-dns  terminationGracePeriodSeconds: 30  tolerations:  - key: CriticalAddonsOnly  operator: Exists  volumes:  - configMap:  defaultMode: 420  name: kube-dns  optional: true  name: kube-dns-config 

    Replace DNS_DEPLOYMENT_NAME with the name of your custom DNS Deployment.

  2. Apply the manifest to the cluster:

    kubectl create -f custom-kube-dns.yaml 

Scale down the GKE-managed kube-dns

To avoid conflicts, disable the GKE-managed kube-dns and kube-dns-autoscaler Deployments by scaling them to zero replicas:

kubectl scale deployment --replicas=0 kube-dns-autoscaler kube-dns --namespace=kube-system 

Configure a custom autoscaler

The default kube-dns-autoscaler only scales the GKE-managed kube-dns Deployment. If your custom DNS provider requires autoscaling, you must deploy a separate autoscaler and grant it permissions to modify your custom DNS Deployment.

  1. Create the following manifest and save it as custom-dns-autoscaler.yaml.

    apiVersion: v1 kind: ConfigMap metadata:  name: custom-dns-autoscaler  namespace: kube-system data:  linear: |-  {  "coresPerReplica": 256,  "nodesPerReplica": 16,  "preventSinglePointFailure": true  } --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata:  name: system:custom-dns-autoscaler roleRef:  apiGroup: rbac.authorization.k8s.io  kind: ClusterRole  name: system:custom-dns-autoscaler subjects: - kind: ServiceAccount  name: kube-dns-autoscaler  namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata:  name: system:custom-dns-autoscaler rules: - apiGroups:  - ""  resources:  - nodes  verbs:  - list  - watch - apiGroups:  - apps  resourceNames:  - DNS_DEPLOYMENT_NAME  resources:  - deployments/scale  verbs:  - get  - update - apiGroups:  - ""  resources:  - configmaps  verbs:  - get  - create --- apiVersion: apps/v1 kind: Deployment metadata:  name: custom-dns-autoscaler  namespace: kube-system  labels:  k8s-app: custom-dns-autoscaler spec:  selector:  matchLabels:  k8s-app: custom-dns-autoscaler  template:  metadata:  labels:  k8s-app: custom-dns-autoscaler  spec:  priorityClassName: system-cluster-critical  securityContext:  seccompProfile:  type: RuntimeDefault  supplementalGroups: [ 65534 ]  fsGroup: 65534  nodeSelector:  kubernetes.io/os: linux  containers:  - name: autoscaler  image: registry.k8s.io/autoscaling/cluster-proportional-autoscaler:1.8.9  resources:  requests:  cpu: "20m"  memory: "10Mi"  command:  - /cluster-proportional-autoscaler  - --namespace=kube-system  - --configmap=custom-dns-autoscaler  - --target=Deployment/DNS_DEPLOYMENT_NAME  - --default-params={"linear":{"coresPerReplica":256,"nodesPerReplica":16,"preventSinglePointFailure":true}}  - --logtostderr=true  - --v=2  tolerations:  - key: "CriticalAddonsOnly"  operator: "Exists"  serviceAccountName: kube-dns-autoscaler 

    Replace DNS_DEPLOYMENT_NAME in the resourceNames field and in the command field with the name of your custom DNS Deployment.

  2. Apply the manifest to the cluster:

    kubectl create -f custom-dns-autoscaler.yaml 

Verify the deployment

Verify that your custom DNS Pods are running:

kubectl get pods -n kube-system -l k8s-app=kube-dns 

Because you scaled the GKE-managed kube-dns deployment to zero replicas, only Pods from your custom Deployment appear in the output. Verify that their status is Running.

Restore the GKE-managed kube-dns

If you deployed a custom kube-dns configuration and need to revert to the default GKE-managed setup, you must delete your custom resources and re-enable the managed kube-dns deployment.

Follow these steps to restore the GKE-managed kube-dns:

  1. Delete the custom kube-dns deployment and its autoscaler. If you saved the manifests as custom-kube-dns.yaml and custom-dns-autoscaler.yaml, run the following commands to delete the resources:

    kubectl delete -f custom-dns-autoscaler.yaml kubectl delete -f custom-kube-dns.yaml 

    If you did not save the manifests, manually delete the Deployment, ClusterRole, and ClusterRoleBinding that you created for your custom deployment.

  2. Restore the GKE-managed kube-dns-autoscaler. Run the following command to scale the kube-dns-autoscaler deployment back to one replica:

    kubectl scale deployment --replicas=1 kube-dns-autoscaler --namespace=kube-system 

    This command re-enables the managed kube-dns-autoscaler, which then automatically scales the managed kube-dns deployment to the appropriate number of replicas for your cluster's size.

  3. Verify the restoration.

    Check the kube-dns and kube-dns-autoscaler Pods to ensure they are running correctly:

    kubectl get pods -n kube-system -l k8s-app=kube-dns 

    The output should show that the GKE-managed kube-dns Pods are in the Running state.

What's next