CoreDNS: File Plugin for Lab Testing
Author: Brandon B. Jozsa
Sometimes you need a quick, real DNS server for testing and you don't want to always have to edit your own home-lab DNS server. Well, have you ever thought to use CoreDNS? If you're interested in how to set up CoreDNS, using a Docker container (of course), then I'll cover two flexible options which may come in handy for your lab testing scenarios. You may even want to use these methods to replace your current BIND 9 deployment.
This blog post will cover some quick and easy-to-use methods for configuring CoreDNS for lab use. You may even want to explore using CoreDNS for your longer standing home lab like I have. Each example below will include a Corefile
and other requirements. Finally, with each plugin example I will include a script that you can copy/paste for a direct, out-of-the-box, working example.
Let's get started.
Corefile: The Brains of the Operation
In order to get CoreDNS working properly, you must configure a Corefile
. The Corefile
is where all of the magic occurs. It's where you configure any plugins, which we'll get into, zone information, and how the server operates (ports, protocols, etc). This file is parsed like a Caddyfile. For each of the plugin examples I cover, I will also give any changes that are required in the Corefile
.
Plugin: File
One of the quickest and easiest ways to get CoreDNS running for most people is by using the file
plugin. The file
plugin uses an RFC 1035-style master file. If you have ever configured a Berkeley Internet Name Domain (BIND) DNS server, then this approach should look familiar to you.
What's really nice about this option is that you can run it with very little resources, as it just takes a single container to run without any additional requirements. There is one downside; however, in that you will need to restart the service or container whenever you want to update your Corefile
or example.com
CoreDNS files. Let's discuss how to get this type of deployment working.
Corefile (File)
Here's an example of the Corefile
when using the file
plugin:
This Corefile
has a few things that may be interesting. The first is that we're logging to stdout
, which means that if you want to run this service as a long standing Docker container, I would suggest you collect that logging data via Fluentd or Fluent Bit. Otherwise, for lab purposes just use docker log
commands to retrieve any errors or lookup requests.
I'm also telling CoreDNS where my RFC-1035 file is located. If you're using Docker, make sure to mount this volume correctly.
I'm also using the proxy
option. I'm not going to get into all the things you can use proxy for, as CoreDNS has great documentation on this. I will say that in this case, I wanted any records that are not associated with jinkit.io to be sent to Google DNS servers (8.8.8.8
), which is the reason why this is configured in this example. Basically, I want to be authoritative for jinkit.io
, because my testing examples will be part of this domain.
Domain File (File)
Below is an example of the RFC-1035-based domain file for a domain I own: jinkit.io
.
I am including a broad set of examples within this file. Again, if you're familiar with configuring a BIND server, I would suggest you try to play with these settings until you find what you're looking for.
Example
Putting this all together, you can create a script called coreup.sh
and run this on any Linux system. I have a couple of suggestions though.
- If you're using an ARM-based device, like a Raspberry Pi, make sure to look for the appropriate CoreDNS image (tag) that matches your system.
- If you're running this on macOS, be sure to configure your volumes correctly before running this script.
- Edit the variables used at the top of the script. They're important. They will automatically configure the domain, and some additional examples for you.
- Make sure to read the script carefully. Don't just run things you find on the internet unless you know what you're doing.
- Be sure to restart the container if you change your domain file. CoreDNS will not automatically pick up changes for the
file
plugin. If you want changes to be picked up automatically, take a look at theetcd
plugin below.
This script will do the following:
- Set useful variables for the script (read through the top part of the script)
- Create the directory for the
Corefile
andexample.com
domain files tee
input ofCorefile
andexample.com
and redirects them to files- Stops the running CoreDNS container (if one has been created/running already)
- Tests the running container
- Adds additional
SRV
records as a test - Restarts the container
- Tests the additional
SRV
records
Please feel free to modify and use this script for your own environment. I have not made many changes to mine. Please take note of the name of the running container as an example of this.
#!/bin/bash
## Prepare any variables used for this script:
export network_endpoints_dns_coredir="$(pwd)/scripts/deployments/coredns"
export network_endpoints_dns_fqdn="jinkit.io"
export network_endpoints_dns_forewarder="8.8.8.8"
export network_endpoints_dns_kubernetes_api="kubernetes"
export node_bootstrap_addr=("192.168.3.21")
export network_endpoints_dns_bootstrap_name="kubetcd01"
export node_master_addr0=("192.168.3.21")
export node_master_addr1=("192.168.3.22")
export node_master_addr2=("192.168.3.23")
export node_master_addr3=("192.168.3.24")
export node_master_addr4=("192.168.3.25")
export node_master_dns_name0=("fs-etcd01")
export node_master_dns_name1=("fs-etcd02")
export node_master_dns_name2=("fs-etcd03")
export node_master_dns_name3=("fs-etcd04")
export node_master_dns_name4=("fs-etcd05")
export node_registry_addr0=("172.29.248.34")
export node_sample1_name=("galvatron")
export node_sample2_name=("openstack")
export node_sample1_addr0=("192.168.70.25")
export node_sample2_addr0=("192.168.70.21")
# Prepare directories for Coredns Corefile and custom domain files:
mkdir -p ${network_endpoints_dns_coredir}
# Write out CoreDNS Domain file:
rm -rf ${network_endpoints_dns_coredir}/Corefile
cat << EOF | tee -a ${network_endpoints_dns_coredir}/Corefile
${network_endpoints_dns_fqdn}:53 {
log stdout
file /data/${network_endpoints_dns_fqdn}
}
.:53 {
proxy . ${network_endpoints_dns_forewarder}:53
log stdout
}
EOF
# Write out CoreDNS Domain file:
rm -rf ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
cat << EOF | tee -a ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
\$TTL 1M
\$ORIGIN ${network_endpoints_dns_fqdn}.
${network_endpoints_dns_fqdn}. IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600
${network_endpoints_dns_fqdn}. IN NS b.iana-servers.net.
${network_endpoints_dns_fqdn}. IN NS a.iana-servers.net.
${network_endpoints_dns_fqdn}. IN A 127.0.0.1
; Flagship: Test A Record
test.${network_endpoints_dns_fqdn}. IN A ${node_bootstrap_addr}
; Flagship: Test TXT Record
text.${network_endpoints_dns_fqdn}. IN TXT "This is a test text record"
; Flagship: Test CNAME Record
cname.${network_endpoints_dns_fqdn}. IN CNAME www.jinkit.net.
; Flagship: Test SRV Record
service.${network_endpoints_dns_fqdn}. IN SRV 8080 10 10 ${network_endpoints_dns_fqdn}.
; Flagship: Kubernetes ETCD Server SRV Records
_etcd-server._tcp.${network_endpoints_dns_fqdn}. 300 IN SRV 0 0 2380 ${network_endpoints_dns_bootstrap_name}.${network_endpoints_dns_fqdn}.
; Flagship: Kubernetes ETCD Client SRV Records
_etcd-client._tcp.${network_endpoints_dns_fqdn}. 300 IN SRV 0 0 2379 ${network_endpoints_dns_bootstrap_name}.${network_endpoints_dns_fqdn}.
; Flagship: ETCD Member A Records
${network_endpoints_dns_bootstrap_name} IN A ${node_bootstrap_addr}
; Flagship: Kubernetes Member A Records
${network_endpoints_dns_kubernetes_api} IN A ${node_bootstrap_addr}
; Flagship: Kubernetes/ETCD Member A Records
*.apps IN CNAME master
; Flagship: Custom User Provided Entries
openshift IN A 192.168.1.40
master IN A 192.168.1.40
${node_sample1_name} IN A ${node_sample1_addr0}
${node_sample2_name} IN A ${node_sample2_addr0}
quay IN A ${node_registry_addr0}
kubenode01 IN A ${node_master_addr0}
kubenode02 IN A ${node_master_addr1}
kubenode03 IN A ${node_master_addr2}
kubenode04 IN A ${node_master_addr3}
kubenode05 IN A ${node_master_addr4}
EOF
# Run docker command:
docker stop flagship_coredns && docker rm flagship_coredns
docker run -d \
--restart=always \
--name flagship_coredns \
--privileged \
-v ${network_endpoints_dns_coredir}:/data:ro \
-p "53:53/udp" -p "53:53/tcp" -p "9153:9153/tcp" \
--cap-drop=all --cap-add=net_bind_service \
coredns/coredns:1.2.5 -conf /data/Corefile
## Testing:
dig ${network_endpoints_dns_kubernetes_api}.${network_endpoints_dns_fqdn} @127.0.0.1
dig ${node_master_addr3} @127.0.0.1
dig srv _etcd-server._tcp.${network_endpoints_dns_fqdn}. @127.0.0.1
## Changes:
### A Records:
sed -i 's/.*Flagship: Kubernetes Member A Records.*/&\n'${node_master_dns_name0}' IN A '${node_master_addr0}'/' ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
sed -i 's/.*Flagship: Kubernetes Member A Records.*/&\n'${node_master_dns_name1}' IN A '${node_master_addr1}'/' ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
sed -i 's/.*Flagship: Kubernetes Member A Records.*/&\n'${node_master_dns_name2}' IN A '${node_master_addr2}'/' ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
sed -i 's/.*Flagship: Kubernetes Member A Records.*/&\n'${node_master_dns_name3}' IN A '${node_master_addr3}'/' ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
sed -i 's/.*Flagship: Kubernetes Member A Records.*/&\n'${node_master_dns_name4}' IN A '${node_master_addr4}'/' ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
### SRV Server Records:
sed -i 's/.*Flagship: Kubernetes ETCD Server SRV Records.*/&\n_etcd-server._tcp.'${network_endpoints_dns_fqdn}'. 300 IN SRV 0 0 2380 '${node_master_dns_name0}'.'${network_endpoints_dns_fqdn}.'/' ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
sed -i 's/.*Flagship: Kubernetes ETCD Server SRV Records.*/&\n_etcd-server._tcp.'${network_endpoints_dns_fqdn}'. 300 IN SRV 0 0 2380 '${node_master_dns_name1}'.'${network_endpoints_dns_fqdn}.'/' ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
sed -i 's/.*Flagship: Kubernetes ETCD Server SRV Records.*/&\n_etcd-server._tcp.'${network_endpoints_dns_fqdn}'. 300 IN SRV 0 0 2380 '${node_master_dns_name2}'.'${network_endpoints_dns_fqdn}.'/' ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
sed -i 's/.*Flagship: Kubernetes ETCD Server SRV Records.*/&\n_etcd-server._tcp.'${network_endpoints_dns_fqdn}'. 300 IN SRV 0 0 2380 '${node_master_dns_name3}'.'${network_endpoints_dns_fqdn}.'/' ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
sed -i 's/.*Flagship: Kubernetes ETCD Server SRV Records.*/&\n_etcd-server._tcp.'${network_endpoints_dns_fqdn}'. 300 IN SRV 0 0 2380 '${node_master_dns_name4}'.'${network_endpoints_dns_fqdn}.'/' ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
### SRV Client Records:
sed -i 's/.*Flagship: Kubernetes ETCD Client SRV Records.*/&\n_etcd-server._tcp.'${network_endpoints_dns_fqdn}'. 300 IN SRV 0 0 2379 '${node_master_dns_name0}'.'${network_endpoints_dns_fqdn}.'/' ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
sed -i 's/.*Flagship: Kubernetes ETCD Client SRV Records.*/&\n_etcd-server._tcp.'${network_endpoints_dns_fqdn}'. 300 IN SRV 0 0 2379 '${node_master_dns_name1}'.'${network_endpoints_dns_fqdn}.'/' ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
sed -i 's/.*Flagship: Kubernetes ETCD Client SRV Records.*/&\n_etcd-server._tcp.'${network_endpoints_dns_fqdn}'. 300 IN SRV 0 0 2379 '${node_master_dns_name2}'.'${network_endpoints_dns_fqdn}.'/' ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
sed -i 's/.*Flagship: Kubernetes ETCD Client SRV Records.*/&\n_etcd-server._tcp.'${network_endpoints_dns_fqdn}'. 300 IN SRV 0 0 2379 '${node_master_dns_name3}'.'${network_endpoints_dns_fqdn}.'/' ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
sed -i 's/.*Flagship: Kubernetes ETCD Client SRV Records.*/&\n_etcd-server._tcp.'${network_endpoints_dns_fqdn}'. 300 IN SRV 0 0 2379 '${node_master_dns_name4}'.'${network_endpoints_dns_fqdn}.'/' ${network_endpoints_dns_coredir}/${network_endpoints_dns_fqdn}
## Now restart the container:
docker restart flagship_coredns
## Testing:
dig ${network_endpoints_dns_kubernetes_api}.${network_endpoints_dns_fqdn} @127.0.0.1
dig ${node_master_addr3} @127.0.0.1
dig srv _etcd-server._tcp.${network_endpoints_dns_fqdn}. @127.0.0.1
I will add another section in the near future on how to use an etcd backed CoreDNS implementation very soon (probably next week). For now...have fun!
Let me know what you think in the comments section. Any thoughts, suggestions, corrections, or just general information is super helpful and very welcome!