I recently needed to setup a Kubernetes cluster without an external DNS and without Internet access. In the old days, static IPs could be mapped to FQDNs by creating entries in the hosts file, but that won’t work with Kubernetes. With Internet access, the typical solution would be to use a wildcard DNS like xip.io or nip.io. Instead, the workaround is by hardcoding the mapping in the CoreDNS configuration.

This post is much more technical than my usual - assumes you have a running Kubernetes 1.10.x cluster with CoreDNS, which in this example is in the kube-system namespace. Don’t trust what I say below, I’m a total novice.

First, we will need to edit the default CoreDNS ConfigMap.

  • Either edit it directly with kubectl -n kube-system edit cm coredns, or
  • Export the config map kubectl -n kube-system get cm/coredns --export -o yaml > coredns.yaml, edit the yaml, and then replace it with kubectl -n kube-system replace -f coredns.yaml

If you’d rather test the change temporarily, then don’t use kubectl replace but instead just kubectl apply so the change won’t stick.

The ConfigMap looks something like this, you’ll need to edit the .:53 section and add the lines dummy.example.com:53 onwards:

apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        log
        health
        kubernetes cluster.local 127.17.0.0/16
        prometheus
        proxy . /etc/resolv.conf
    }
    dummy.example.com:53 {
      file /etc/coredns/dummy.example.com
      errors
      log . {
        class denial
        class sucess
      }
    }
  dummy.example.com: |
    $ORIGIN dummy.example.com.
    @ 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. (
        2017042745 ; serial
        7200 ; refresh (2 hours)
        3600 ; retry (1 hour)
        1209600 ; expire (2 weeks)
        3600 ; minimum (1 hour)
    )

    3600 IN NS a.iana-servers.net.
    3600 IN NS b.iana-servers.net.

    www IN A 10.10.10.90
    mail IN A 10.10.10.90

    10.10.10.90.in-addr.arpa. IN PTR dummy.example.com.

This will configure CoreDNS such that:

  • CoreDNS will not lookup a real DNS - by removing fallback from the .:53 section.
  • CoreDNS will instead lookup a matching static file for dummy.example.com.
  • And, the static file’s contents (below the line dummy.example.com: |) will be the result of the DNS lookup. o Here, the FQDN is www.dummy.example.com or mail.dummy.example.com, o And a reverse lookup (PTR) by IP address should return dummy.example.com`.

Now that’s done, we need to edit the CoreDNS deployment to add the static file volume. One way is to edit the deployment live, kubectl -n kube-system edit deployment coredns which then opens the file in vim. Once the file is edited and saved, CoreDNS will restart.

It’s a large file, but look for the volumes: section with the name coredns. The key and path to Corefile will already exist, so just below that add the same for dummy.example.com:

      volumes:
      - configMap:
          defaultMode: 420
          items:
          - key: Corefile
            path: Corefile
          - key: dummy.example.com
            path: dummy.example.com
          name: coredns
        name: config-volume

Follow the indents in your file, what I show here will not match yours.

Finally, test it by running a dig (if you have it) in running container - run kubectl exec -it [pod] -- /bin/sh and in the shell:

  • Run dig www.dummy.example.com - if the returned ANSWER is the specified IP address, then all is good.
  • Then do a reverse lookup with dig -x 10.10.10.90 - if you get your FQDN, then well done.

To add more FQDNs - for every hostname, repeat all steps above. As far as I know, each one will be a separate file.