I'm usually involved in the development and operation of DNS servers, but I'm studying Docker while working. I tried BIND with Docker, so I'll share it as a memorandum.
I am also trying to configure the cache and authoritative DNS.
The environment I tried is as follows.
If you have Docker installed, it should work on both Mac and Linux.
The directory structure is as follows.
bind/
├ Dockerfile
├ named.conf
└ example.com
Dockerfile
FROM centos:7
RUN yum -y update
RUN yum install -y bind
RUN /usr/sbin/rndc-confgen -a -b 512 -k rndc-key
RUN chmod 755 /etc/rndc.key
EXPOSE 53/UDP
EXPOSE 53/TCP
COPY named.conf /etc/bind/
COPY example.com /etc/bind/master/
CMD ["/usr/sbin/named", "-c", "/etc/bind/named.conf", "-g", "-u", "named"]
named.conf
include "/etc/rndc.key";
controls {
inet 127.0.0.1 allow { 127.0.0.1; } keys { "rndc-key"; };
};
acl "access-list" {
127.0.0.1;
172.17.0.0/16;
};
options {
directory "/etc/named/";
pid-file "/run/named/";
dump-file "/var/named/named_dump.db";
statistics-file "/var/named/named.stats.log";
zone-statistics yes;
version "";
masterfile-format text;
recursive-clients 10000;
tcp-clients 10000;
allow-recursion { access-list; };
allow-query { access-list; };
allow-query-cache { access-list; };
};
view "internal" {
recursion yes;
zone "example.com" IN {
type master;
file "/etc/bind/master/example.com";
};
};
example.com
$TTL 900
@ IN SOA example.com. postmaster.example.com. (
2020062101 ; Serial Number
1800 ; Refresh
900 ; Retry
1209600 ; expire
900 ; minimum
)
;
IN NS example.com.
IN A 1.2.3.4
www IN A 5.6.7.8
The settings in named.conf are almost minimal.
--BIND package
This time BIND is installed with yum. It's an old version, but it's okay because you just try it.
--EXPOSE in Dockerfile
Specify the port for which communication is expected. DNS uses port 53.
--Copying files such as named.conf, example.com
Add the files needed to configure BIND to the image. For the file to be copied, specify the file in the directory where the Dockerfile is placed.
--Start BIND
Normally, it is started using systemctl, but unfortunately it seems that it can not be started with a container, so directly specify named
and start it.
$ docker build -t bind .
You may get a warning on the way, but you don't have to worry about it.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
bind latest b634adb26126 About an hour ago 412MB
Confirm that the image is created.
docker run -dit -p 53:53 -p 53:53/udp --name bind bind:latest
Here, the port mapping is set with -p
.
$ docker ps
b81999d14571 bind:latest "/usr/sbin/named -c …" About an hour ago Up About an hour 0.0.0.0:53->53/tcp, 0.0.0.0:53->53/udp bind
If you can confirm that the container can be started, it is successful.
The dig command is a command that asks the DNS server for the domain and tells you the IP address. I would like to check the operation using this command.
Try typing the following command on the host side
$ dig @localhost example.com
; <<>> DiG 9.16.1-Ubuntu <<>> @localhost example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58542
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 95bb6b3867347d2a659e18f05fa40fa7705d1af930ac0b3b (good)
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 900 IN A 1.2.3.4
;; AUTHORITY SECTION:
example.com. 900 IN NS example.com.
;; Query time: 10 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Nov 05 23:43:51 JST 2020
;; MSG SIZE rcvd: 98
You can see that the IP address 1.2.3.4
set in example.com
is displayed.
By the way, even if you inquire about www.example.com
, the set address 5.6.7.8
is displayed.
$ dig @localhost www.example.com
; <<>> DiG 9.16.1-Ubuntu <<>> @localhost www.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 17044
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: fc8594f5fe0fda2a5b28b3f65fa41035d0243f359a253da7 (good)
;; QUESTION SECTION:
;www.example.com. IN A
;; ANSWER SECTION:
www.example.com. 900 IN A 5.6.7.8
;; AUTHORITY SECTION:
example.com. 758 IN NS example.com.
;; ADDITIONAL SECTION:
example.com. 758 IN A 1.2.3.4
;; Query time: 10 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Nov 05 23:46:13 JST 2020
;; MSG SIZE rcvd: 118
Previously, there was only one DNS server, but in actual operation, a DNS that receives inquiries from the client and makes inquiries on behalf of the client, and an authoritative DNS that manages zone information. Use the server.
I would like to try this configuration with Docker as well.
First, let's delete the container created earlier
$ docker rm bind
Now create two containers.
$ docker run -dit -p 53:53 -p 53:53/udp --name bind_cache bind:latest
$ docker run -dit --name bind_auth bind:latest
Since only the cache DNS receives the response from the client, put the port mapping setting in the cache DNS. Authoritative DNS is not set because it does not communicate directly with the client.
Check the IP addresses of bind_cache
and bind_auth
once.
$ docker inspect bind_cache | grep IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "172.17.0.2",
"IPAddress": "172.17.0.2",
$ docker inspect bind_auth | grep IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "172.17.0.3",
"IPAddress": "172.17.0.3",
It turns out that bind_cache
has an IP address of 172.17.0.2
and bind_auth
has an IP address of 172.17.0.3
.
Enter the container by entering the following command to edit the cache DNS named.conf
.
$ docker exec -it bind_cache /bin/bash
Edit the view internal
part with vi etc. as follows
/etc/bind/named.conf
・
・
・
view "internal" {
recursion yes;
zone "." {
type forward;
forwarders { 172.17.0.3; };
forward only;
};
};
Enter the IP address of the authoritative DNS you confirmed earlier in forwarders
.
Now let's take a look at the authoritative DNS named.conf
.
$ docker exec -it bind_auth /bin/bash
Similarly, edit named.conf
with vi etc.
Notice the acl access-list
.
/etc/bind/named.conf
include "/etc/rndc.key";
controls {
inet 127.0.0.1 allow { 127.0.0.1; } keys { "rndc-key"; };
};
acl "access-list" {
127.0.0.1;
172.17.0.0/16;
};
・
・
acl access-list
specifies the IP addresses that are allowed to communicate.
The IP address of the cache DNS I checked earlier was 172.17.0.2
. This time, 172.17.0.0/16
is allowed by default, so there is no problem as it is, but let's specify the IP address of the cache DNS.
/etc/bind/named.conf
include "/etc/rndc.key";
controls {
inet 127.0.0.1 allow { 127.0.0.1; } keys { "rndc-key"; };
};
acl "access-list" {
127.0.0.1;
172.17.0.2; // 172.17.0.Change to 2
};
・
・
This completes the settings.
Let's reboot for the settings to take effect. If you can confirm that two containers are running, it is successful.
$ docker restart bind_auth
$ docker restart bind_cache
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
NAMES
f0b2f14e26f2 bind:latest "/usr/sbin/named -c …" About an hour ago Up 6 minutes 53/tcp, 53/udp bind_auth
b81999d14571 bind:latest "/usr/sbin/named -c …" 2 days ago Up 6 minutes 0.0.0.0:53->53/tcp, 0.0.0.0:53->53/udp bind_cache
If it is not running, it is likely that the named.conf
settings are not working properly. (If you use docker logs
, such as forgetting to add;, you can see the contents of the error.)
In that case, it may be easier to delete the container that could not be started with the following command and create the container.
$ docker logs bind_XXX
$ docker rm bind_XXX or docker rm[Container ID]
Check the operation using the dig command as before.
$ dig @localhost example.com
; <<>> DiG 9.16.1-Ubuntu <<>> @localhost example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58542
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 95bb6b3867347d2a659e18f05fa40fa7705d1af930ac0b3b (good)
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 900 IN A 1.2.3.4
;; AUTHORITY SECTION:
example.com. 900 IN NS example.com.
;; Query time: 10 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Nov 05 23:43:51 JST 2020
;; MSG SIZE rcvd: 98
You can see that the IP address set in example.com
is displayed.
By the way, you can also pull domains that are not defined in the authoritative DNS.
$ dig @localhost www.google.com
; <<>> DiG 9.16.1-Ubuntu <<>> @localhost www.google.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53253
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 9
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 3181d4115c9c0426b42bd02e5fa6a8a6a04cb4d481be1221 (good)
;; QUESTION SECTION:
;www.google.com. IN A
;; ANSWER SECTION:
www.google.com. 300 IN A 172.217.26.36
;; AUTHORITY SECTION:
google.com. 171777 IN NS ns1.google.com.
google.com. 171777 IN NS ns4.google.com.
google.com. 171777 IN NS ns3.google.com.
google.com. 171777 IN NS ns2.google.com.
;; ADDITIONAL SECTION:
ns4.google.com. 171777 IN A 216.239.38.10
ns2.google.com. 171777 IN A 216.239.34.10
ns1.google.com. 171777 IN A 216.239.32.10
ns3.google.com. 171777 IN A 216.239.36.10
ns4.google.com. 171777 IN AAAA 2001:4860:4802:38::a
ns2.google.com. 171777 IN AAAA 2001:4860:4802:34::a
ns1.google.com. 171777 IN AAAA 2001:4860:4802:32::a
ns3.google.com. 171777 IN AAAA 2001:4860:4802:36::a
;; Query time: 120 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sat Nov 07 23:01:10 JST 2020
;; MSG SIZE rcvd: 335
It was easier than I expected. I don't know if it can be used in actual operation, but I would like to try various things. Next, I'll try using Unbound for cache DNS.
Recommended Posts