mirror of
				https://github.com/coredns/coredns.git
				synced 2025-11-03 18:53:13 -05:00 
			
		
		
		
	
		
			
	
	
		
			285 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			285 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 
								 | 
							
								# kubernetes
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								`kubernetes` enables reading zone data from a kubernetes cluster. Record names
							 | 
						||
| 
								 | 
							
								are constructed as "myservice.mynamespace.coredns.local" where:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								* "myservice" is the name of the k8s service (this may include multiple DNS labels, such as "c1.myservice"),
							 | 
						||
| 
								 | 
							
								* "mynamespace" is the k8s namespace for the service, and
							 | 
						||
| 
								 | 
							
								* "coredns.local" is the zone configured for `kubernetes`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Syntax
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								kubernetes [zones...]
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								* `zones` zones kubernetes should be authorative for.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								kubernetes [zones] {
							 | 
						||
| 
								 | 
							
								    endpoint http://localhost:8080
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								* `endpoint` the kubernetes API endpoint, default to http://localhost:8080
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Examples
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This is the default kubernetes setup, with everything specified in full:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								# Serve on port 53
							 | 
						||
| 
								 | 
							
								.:53 {
							 | 
						||
| 
								 | 
							
								    # use kubernetes middleware for domain "coredns.local"
							 | 
						||
| 
								 | 
							
								    kubernetes coredns.local {
							 | 
						||
| 
								 | 
							
								        # Use url for k8s API endpoint
							 | 
						||
| 
								 | 
							
								        endpoint http://localhost:8080
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								#    cache 160 coredns.local
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Basic Setup
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#### Launch Kubernetes
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Kubernetes is launched using the commands in the following `run_k8s.sh` script:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								#!/bin/bash
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Based on instructions at: http://kubernetes.io/docs/getting-started-guides/docker/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#K8S_VERSION=$(curl -sS https://storage.googleapis.com/kubernetes-release/release/latest.txt)
							 | 
						||
| 
								 | 
							
								K8S_VERSION="v1.2.4"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								ARCH="amd64"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export K8S_VERSION
							 | 
						||
| 
								 | 
							
								export ARCH
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#DNS_ARGUMENTS="--cluster-dns=10.0.0.10 --cluster-domain=cluster.local"
							 | 
						||
| 
								 | 
							
								DNS_ARGUMENTS=""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								docker run -d \
							 | 
						||
| 
								 | 
							
								    --volume=/:/rootfs:ro \
							 | 
						||
| 
								 | 
							
								    --volume=/sys:/sys:ro \
							 | 
						||
| 
								 | 
							
								    --volume=/var/lib/docker/:/var/lib/docker:rw \
							 | 
						||
| 
								 | 
							
								    --volume=/var/lib/kubelet/:/var/lib/kubelet:rw \
							 | 
						||
| 
								 | 
							
								    --volume=/var/run:/var/run:rw \
							 | 
						||
| 
								 | 
							
								    --net=host \
							 | 
						||
| 
								 | 
							
								    --pid=host \
							 | 
						||
| 
								 | 
							
								    --privileged \
							 | 
						||
| 
								 | 
							
								    gcr.io/google_containers/hyperkube-${ARCH}:${K8S_VERSION} \
							 | 
						||
| 
								 | 
							
								    /hyperkube kubelet \
							 | 
						||
| 
								 | 
							
								    --containerized \
							 | 
						||
| 
								 | 
							
								    --hostname-override=127.0.0.1 \
							 | 
						||
| 
								 | 
							
								    --api-servers=http://localhost:8080 \
							 | 
						||
| 
								 | 
							
								    --config=/etc/kubernetes/manifests \
							 | 
						||
| 
								 | 
							
								    ${DNS_ARGUMENTS} \
							 | 
						||
| 
								 | 
							
								    --allow-privileged --v=2
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#### Configure kubectl and test
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The kubernetes control client can be downloaded from the generic URL:
							 | 
						||
| 
								 | 
							
								`http://storage.googleapis.com/kubernetes-release/release/${K8S_VERSION}/bin/${GOOS}/${GOARCH}/${K8S_BINARY}`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								For example, the kubectl client for Linux can be downloaded using the command:
							 | 
						||
| 
								 | 
							
								`curl -sSL "http://storage.googleapis.com/kubernetes-release/release/v1.2.4/bin/linux/amd64/kubectl"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The following `setup_kubectl.sh` script can be stored in the same directory as 
							 | 
						||
| 
								 | 
							
								kubectl to setup
							 | 
						||
| 
								 | 
							
								kubectl to communicate with kubernetes running on the localhost:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								#!/bin/bash
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								BASEDIR=`realpath $(dirname ${0})`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								${BASEDIR}/kubectl config set-cluster test-doc --server=http://localhost:8080
							 | 
						||
| 
								 | 
							
								${BASEDIR}/kubectl config set-context test-doc --cluster=test-doc
							 | 
						||
| 
								 | 
							
								${BASEDIR}/kubectl config use-context test-doc
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								alias kubctl="${BASEDIR}/kubectl"
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Verify that kubectl is working by querying for the kubernetes namespaces:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								$ ./kubectl get namespaces
							 | 
						||
| 
								 | 
							
								NAME      STATUS    AGE
							 | 
						||
| 
								 | 
							
								default   Active    8d
							 | 
						||
| 
								 | 
							
								test      Active    7d
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#### Launch a kubernetes service and expose the service
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The following commands will create a kubernetes namespace "demo",
							 | 
						||
| 
								 | 
							
								launch an nginx service in the namespace, and expose the service on port 80:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								$ ./kubectl create namespace demo
							 | 
						||
| 
								 | 
							
								$ ./kubectl get namespace
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								$ ./kubectl run mynginx --namespace=demo --image=nginx
							 | 
						||
| 
								 | 
							
								$ /kubectl get deployment --namespace=demo
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								$ ./kubectl expose deployment mynginx --namespace=demo --port=80
							 | 
						||
| 
								 | 
							
								$ ./kubectl get service --namespace=demo
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#### Launch CoreDNS
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Build CoreDNS and launch using the configuration file in `conf/k8sCorefile`.
							 | 
						||
| 
								 | 
							
								This configuration file sets up CoreDNS to use the zone `coredns.local` for
							 | 
						||
| 
								 | 
							
								the kubernetes services.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The command to launch CoreDNS is:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								$ ./coredns -conf conf/k8sCoreFile
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								In a separate terminal a dns query can be issued using dig:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								$ dig @localhost mynginx.demo.coredns.local
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								; <<>> DiG 9.9.4-RedHat-9.9.4-29.el7_2.3 <<>> @localhost mynginx.demo.coredns.local
							 | 
						||
| 
								 | 
							
								; (2 servers found)
							 | 
						||
| 
								 | 
							
								;; global options: +cmd
							 | 
						||
| 
								 | 
							
								;; Got answer:
							 | 
						||
| 
								 | 
							
								;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47614
							 | 
						||
| 
								 | 
							
								;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								;; OPT PSEUDOSECTION:
							 | 
						||
| 
								 | 
							
								; EDNS: version: 0, flags:; udp: 4096
							 | 
						||
| 
								 | 
							
								;; QUESTION SECTION:
							 | 
						||
| 
								 | 
							
								;mynginx.demo.coredns.local.    IN  A
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								;; ANSWER SECTION:
							 | 
						||
| 
								 | 
							
								mynginx.demo.coredns.local. 0   IN  A   10.0.0.10
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								;; Query time: 2 msec
							 | 
						||
| 
								 | 
							
								;; SERVER: ::1#53(::1)
							 | 
						||
| 
								 | 
							
								;; WHEN: Thu Jun 02 11:07:18 PDT 2016
							 | 
						||
| 
								 | 
							
								;; MSG SIZE  rcvd: 71
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Implementation Notes/Ideas
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Basic Zone Mapping (implemented)
							 | 
						||
| 
								 | 
							
								The middleware is configured with a "zone" string. For 
							 | 
						||
| 
								 | 
							
								example: "zone = coredns.local".
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The Kubernetes service "myservice" running in "mynamespace" would map 
							 | 
						||
| 
								 | 
							
								to: "myservice.mynamespace.coredns.local".
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The middleware should publish an A record for that service and a service record.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Initial implementation just performs the above simple mapping. Subsequent 
							 | 
						||
| 
								 | 
							
								revisions should allow different namespaces to be published under different zones.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								For example:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Serve on port 53
							 | 
						||
| 
								 | 
							
								    .:53 {
							 | 
						||
| 
								 | 
							
								        # use kubernetes middleware for domain "coredns.local"
							 | 
						||
| 
								 | 
							
								        kubernetes coredns.local {
							 | 
						||
| 
								 | 
							
								            # Use url for k8s API endpoint
							 | 
						||
| 
								 | 
							
								            endpoint http://localhost:8080
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        # Perform DNS response caching for the coredns.local zone
							 | 
						||
| 
								 | 
							
								        # Cache timeout is provided by the integer argument in seconds
							 | 
						||
| 
								 | 
							
								        # This works for the kubernetes middleware.)
							 | 
						||
| 
								 | 
							
								        #cache 20 coredns.local
							 | 
						||
| 
								 | 
							
								        #cache 160 coredns.local
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Internal IP or External IP?
							 | 
						||
| 
								 | 
							
								* Should the Corefile configuration allow control over whether the internal IP or external IP is exposed?
							 | 
						||
| 
								 | 
							
								* If the Corefile configuration allows control over internal IP or external IP, then the config should allow users to control the precidence.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								For example a service "myservice" running in namespace "mynamespace" with internal IP "10.0.0.100" and external IP "1.2.3.4".
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This example could be published as:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								| Corefile directive           | Result              |
							 | 
						||
| 
								 | 
							
								|------------------------------|---------------------|
							 | 
						||
| 
								 | 
							
								| iporder = internal           | 10.0.0.100          |
							 | 
						||
| 
								 | 
							
								| iporder = external           | 1.2.3.4             |
							 | 
						||
| 
								 | 
							
								| iporder = external, internal | 10.0.0.100, 1.2.3.4 |
							 | 
						||
| 
								 | 
							
								| iporder = internal, external | 1.2.3.4, 10.0.0.100 |
							 | 
						||
| 
								 | 
							
								| _no directive_               | 10.0.0.100, 1.2.3.4 |
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Wildcards
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Publishing DNS records for singleton services isn't very interesting. Service
							 | 
						||
| 
								 | 
							
								names are unique within a k8s namespace therefore multiple services will be
							 | 
						||
| 
								 | 
							
								commonly run with a structured naming scheme.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								For example, running multiple nginx services under the names:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								| Service name |
							 | 
						||
| 
								 | 
							
								|--------------|
							 | 
						||
| 
								 | 
							
								| c1.nginx     |
							 | 
						||
| 
								 | 
							
								| c2.nginx     |
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								or:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								| Service name |
							 | 
						||
| 
								 | 
							
								|--------------|
							 | 
						||
| 
								 | 
							
								| nginx.c3     |
							 | 
						||
| 
								 | 
							
								| nginx.c4     |
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								A DNS query with wildcard support for "nginx" in these examples should
							 | 
						||
| 
								 | 
							
								return the IP addresses for all services with "nginx" in the service name.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								TBD:
							 | 
						||
| 
								 | 
							
								* How does this relate the the k8s load-balancer configuration?
							 | 
						||
| 
								 | 
							
								* Do wildcards search across namespaces?
							 | 
						||
| 
								 | 
							
								* Initial implementation assumes that a namespace maps to the first DNS label below the zone managed by the kubernetes middleware. This assumption may need to be revised.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## TODO
							 | 
						||
| 
								 | 
							
								* Implement namespace filtering to different zones.
							 | 
						||
| 
								 | 
							
								* Implement IP selection and ordering (internal/external).
							 | 
						||
| 
								 | 
							
								* Implement SRV-record queries using naive lookup.
							 | 
						||
| 
								 | 
							
								* Flatten service and namespace names to valid DNS characters. (service names
							 | 
						||
| 
								 | 
							
								  and namespace names in k8s may use uppercase and non-DNS characters. Implement
							 | 
						||
| 
								 | 
							
								  flattening to lower case and mapping of non-DNS characters to DNS characters
							 | 
						||
| 
								 | 
							
								  in a standard way.)
							 | 
						||
| 
								 | 
							
								* Do we need to generate synthetic zone records for namespaces?
							 | 
						||
| 
								 | 
							
								* Implement wildcard-based lookup.
							 | 
						||
| 
								 | 
							
								* Improve lookup to reduce size of query result obtained from k8s API.
							 | 
						||
| 
								 | 
							
								  (namespace-based?, other ideas?)
							 | 
						||
| 
								 | 
							
								* How to support label specification in Corefile to allow use of labels to 
							 | 
						||
| 
								 | 
							
								  indicate zone? (Is this even useful?) For example, the following configuration
							 | 
						||
| 
								 | 
							
								  exposes all services labeled for the "staging" environment and tenant "customerB"
							 | 
						||
| 
								 | 
							
								  in the zone "customerB.stage.local":
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								kubernetes customerB.stage.local {
							 | 
						||
| 
								 | 
							
								    # Use url for k8s API endpoint
							 | 
						||
| 
								 | 
							
								    endpoint http://localhost:8080
							 | 
						||
| 
								 | 
							
								    label "environment" : "staging", "tenant" : "customerB"
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								* Test with CoreDNS caching. CoreDNS caching for DNS response is working using
							 | 
						||
| 
								 | 
							
								  the `cache` directive. Tested working using 20s cache timeout and A-record queries.
							 | 
						||
| 
								 | 
							
								* DNS response caching is good, but we should also cache at the http query 
							 | 
						||
| 
								 | 
							
								  level as well. (Take a look at https://github.com/patrickmn/go-cache as 
							 | 
						||
| 
								 | 
							
								  a potential expiring cache implementation for the http API queries.)
							 | 
						||
| 
								 | 
							
								
							 |