I tried BIND with Docker

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.

Execution environment

The environment I tried is as follows.

If you have Docker installed, it should work on both Mac and Linux.

First of all, the configuration of one unit

Preparation of Dockerfile

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.

Description of the prepared file

--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.

Build image

$ 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.

Start the container using the built image

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.

Operation check with dig

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

Try to configure cache, authoritative DNS

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.

Container startup

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.

Cache DNS settings

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.

Authoritative DNS settings

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]

Operation check with dig

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

Impressions

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

I tried BIND with Docker
I tried using Scalar DL with Docker
I tried to verify AdoptOpenJDK 11 (11.0.2) with Docker image
I tried DI with Ruby
I tried the Docker tutorial!
I tried UPSERT with PostgreSQL.
I tried using JOOQ with Gradle
I tried morphological analysis with MeCab
I tried to interact with Java
I tried UDP communication with Java
I tried Flyway with Spring Boot
I tried customizing slim with Scaffold
I tried to make an introduction to PHP + MySQL with Docker
I tried running WordPress with docker preview on M1 Mac.
I tried to create a padrino development environment with Docker
I tried using Realm with Swift UI
I tried running Docker on Windows Server 2019
I tried to get started with WebAssembly
I tried to build the environment of PlantUML Server with Docker
I tried using OnlineConverter with SpringBoot + JODConverter
I tried Spring.
I tried time-saving management learning with Studyplus.
I tried Lazy Initialization with Spring Boot 2.2.0
I tried deploying a Docker container on Lambda with Serverless Framework
I tried youtubeDataApi.
Microservices 101-I tried putting Docker on Ubuntu-
I tried refactoring ①
What is Docker? I tried to summarize
I tried FizzBuzz.
I tried to implement ModanShogi with Kinx
I tried JHipster 5.1
I tried running the Angular sample in Auth0 Quick Start with Docker
I tried to build a Firebase application development environment with Docker in 2020
I tried using Docker for the first time
I tried to make Basic authentication with Java
I tried to manage struts configuration with Coggle
I tried to manage login information with JMX
I tried writing CRUD with Rails + Vue + devise_token_auth
I also tried WebAssembly with Nim and C
I couldn't install docker with raspberry pi2 b +.
I tried touching Docker for the first time
I tried Eclipse MicroProfile OpenAPI with WildFly Swarm
I tried running Ansible on a Docker container
I tried installing docker on an EC2 instance
I can't do docker-compose up -d with docker
I tried to break a block with java (1)
I tried Getting Started with Gradle on Heroku
I tried to create a portfolio with AWS, Docker, CircleCI, Laravel [with reference link]
I tried to make a machine learning application with Dash (+ Docker) part3 ~ Practice ~
I tried running Autoware
I tried using Gson
Launch MariaDB with Docker
Rails deploy with Docker
Run Pico with docker
Explode Docker with WSL2
I tried QUARKUS immediately
Use Puphpeteer with Docker
I tried using TestNG
Operate Emby with Docker
Try WildFly with Docker
I tried using Galasa