Featured image of post [반려 서버 키우기 사전 작업] Core DNS를 홈랩의 커스텀 DNS 서버로 이용하기

[반려 서버 키우기 사전 작업] Core DNS를 홈랩의 커스텀 DNS 서버로 이용하기

시작하며

“반려 서버 키우기”라는 건전한 취미 생활을 본격적으로 시작하기 전에 그 사전 작업 중 하나로 Core DNS를 찍먹해보려한다.

현재 나의 홈랩 상황은 다음과 같다.

  • (서버 및 장난감) 라즈베리파이 4대
  • (서버 및 장난감) 랩탑 1대 + 그 위의 VM 3대
  • (서버 관리용) PC 2대
  • 핸드폰 2개

즉 나의 반려 서버는 8대, 반려 서버에 접속하는 장비는 4대(PC + 핸드폰) 정도라고 볼 수 있다.

기존에는 매번 사용하는 PC의 /etc/hosts 를 편집해서 도메인 네임을 이용하곤 했는데 한 대의 PC로만 접속하는 게 아니라 여러 장비로 서버에 접속하게 될 수 있다보니 매번 /etc/hosts를 편집하는 것이 그닥 유쾌하진 않았고, 심지어 모바일에서는 /etc/hosts 를 제어할 수 없어 IP로 직접 접근해야했다.

이에 대해 고민하던 차에 지인으로부터 Core DNS가 그렇게 사용하기 편하다는 얘기를 듣고 한 번 Core DNS를 통해 홈랩에서 사용할 프라이빗한 DNS 서버를 구축해보려한다.

Core DNS가 그렇게 편한지 Getting Started

Core DNS는 간단히 컨테이너로 띄울 수 있었다.

아무런 Corefile 설정을 정의하지 않는 경우 기본적으로는 whoami 플러그인을 통해 아주 간단한 fake dns server처럼 동작하는 듯하다. 다음과 같이 정말 간단하게 coredns를 띄울 수 있고, dig를 통해 직접 띄운 core dns가 fake dns server로라도 동작은 하는지 확인해볼 수 있다.

fake dns server는 DNS 질의에 대해 단순히 자기 IP로만 응답하는 그런 dns server라는 의미로 사용한 명칭이다.

docker run --rm --name coredns -p 53:53/udp coredns/coredns
$ dig @127.0.0.1 -p 53 jinsu.com | grep -C 2 'jinsu\.com'

; <<>> DiG 9.18.1-1ubuntu1.2-Ubuntu <<>> @127.0.0.1 -p 53 jinsu.com
; (1 server found)
;; global options: +cmd
--
; COOKIE: c79167ab937cb4d2 (echoed)
;; QUESTION SECTION:
;jinsu.com.			IN	A

;; ADDITIONAL SECTION:
jinsu.com.		0	IN	A	172.17.0.1
_udp.jinsu.com.		0	IN	SRV	0 0 46738 .

;; Query time: 4 msec

docker을 통해 기본 옵션으로 core-dns 컨테이너를 실행하면 어떤 hostname(e.g. jinsu.com)으로 쿼리하든 위와 같이 172.17.0.1 이 조회된다. jinsu.com 을 조회하든 jinsu.me를 조회하든 foo.bar을 조회하든 결과는 똑같다. whoami plugin만 활성화된 fake dns server이기 때문이다.

(참고) 172.17.0.1 라는 IP가 낯익을 수 있다. 이는 Docker의 bridge network interface의 IP이다.

$ ifconfig docker0 | grep inet
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:b9ff:feb4:d995  prefixlen 64  scopeid 0x20<link>
$ docker inspect coredns | jq '.[0]["NetworkSettings"]["Networks"]'
{
  "bridge": {
    "Gateway": "172.17.0.1",
    "IPAddress": "172.17.0.3",
    ...(생략)
  }
}

위와 같이 172.17.0.1 은 docker의 brige network interface의 IP임을 확인해볼 수 있다. 그리고 $ docker run 명령어에 --net host 인자를 전달해 bridge network가 아닌 host network을 이용하면 DNS 질의 시 172.17.0.1 이 아닌 127.0.0.1 를 응답으로 받을 수 있을 것이다. (OSX에서는 동일하게 브릿지 IP인듯 함.)

Configuration을 정의하기

우선 나의 홈랩 상황과 목표는 다음과 같다.

  • 보유한 공유기: LG U+에서 임대해준 평범한 공유기. 192.168.219.0/24 네트워크를 이용.
  • lab. Zone에 Raspberry Pi 4대, DNS 서버로 사용할 Laptop 1대에 대한 A 레코드를 생성할 것임.
    • 공유기에 연결된 장비로 laptop.lab 혹은 vm[19[0-3]\.lab, pi20[0-3]\.lab에 접속했을 때 올바르게 해당하는 장비에 접속.
      • laptop.lab - 192.168.219.180
      • vm190.lab - 1902.168.219.190
      • pi203.lab - 192.168.219.203
  • 코드를 통해 직관적이고 수월하고 멱등적이게 작업할 수 있도록 하기.
    • 추후에 장비가 추가될 때에도 손쉽게 레코드를 추가할 수 있기를 바람.

그럼. Core DNS 설정을 한 번 시작해보겠다.

mkdir -p ${HOME}/coredns-config

${HOME}/coredns-config 에 core dns에 대한 설정을 담을 directory를 생성해준다.

cat << EOF > ${HOME}/coredns-config/Corefile
.:53 {
  hosts /etc/coredns/config/lab lab. {
    fallthrough
  }
  forward . 8.8.8.8
  log
}
EOF

Core DNS은 위와 같이 Corefile 파일을 통해 설정해줄 수 있다.

lab. Zone이 아닌 다른 Zone에 대한 질의는 모두 기본적으로 8.8.8.8로 forward하도록했다. 이제 lab. Zone에 대해 좀 더 자세히 설정해보겠다.

cat <<EOF > ${HOME}/coredns-config/lab
192.168.219.180 laptop.lab
EOF

위와 같이 ${HOME}/coredns-config/lab 파일에 lab. Zone에 대한 레코드 정보를 정의해줬다.

lab_zone_file=${HOME}/coredns-config/lab

for name in vm{190..192} pi{200..203}; do
  # e.g. If name is "vm190", id should be "190"
  id=$(echo ${name} | sed 's/[a-z]*//g')
  cat ${lab_zone_file} | grep "192.168.219.${id}"
  if [[ $? -eq 0 ]]; then
    echo "Record about ${name} has already exists."
  else
    echo "192.168.219.${id} ${name}.lab # Generated by a script" >> ${lab_zone_file} && \
    echo "Added a record about ${name}."
  fi
done; 

200~203번 raspberry Pi에 대한 레코드도 zone file에 추가해줬다.

docker run --rm --name coredns -p 53:53/udp \
  -v ${HOME}/coredns-config:/etc/coredns/config coredns/coredns \
  -conf /etc/coredns/config/Corefile

위에서 작성한 설정들을 bind mount 해서 coredns를 실행시켜보자.

echo -n "laptop.lab: "
dig +short @127.0.0.1 -p 53 laptop.lab

for name in vm{190..192} pi{200..203}; do
  echo -n "${name}.lab: "
  dig +short @127.0.0.1 -p 53 ${name}.lab
done;

# Expected output:
laptop.lab: 192.168.219.180
vm190.lab: 192.168.219.190
vm191.lab: 192.168.219.191
vm192.lab: 192.168.219.192
pi200.lab: 192.168.219.200
pi201.lab: 192.168.219.201
pi202.lab: 192.168.219.202
pi203.lab: 192.168.219.203

dig를 통해 조회했을 때 잘 조회되는지 확인해봤다.

위와 같이 응답이 온다면 결과적으로 coredns 서버가 제대로 뜬 것이다!

오호라. 녀석 쓸만하다~ 편하다~!

그럼 이제 우리 공유기를 이용하는 경우 기본적으로 랩탑에 띄운 DNS 서버를 이용하도록 설정해보도록 하겠다.

docker run --name coredns -p 53:53/udp \
  --restart always -d \
  -v ${HOME}/coredns-config:/etc/coredns/config coredns/coredns \
  -conf /etc/coredns/config/Corefile

이제는 계속 이 컨테이너를 홈랩의 DNS 서버로 이용할 것이므로 --rm 인자를 지우고 --restart always -d 인자를 추가적으로 전달해줬다.

이제 공유기의 설정에서 DNS 서버를 설정해주자. 주 DNS 서버는 랩탑의 core dns 서버로, 부 DNS 서버는 기존에 통신사가 제공해주던 DNS 서버를 이용하려한다.

나는 LG U+가 제공해준 공유기를 그대로 사용중이기 때문에 공유기의 관리자 페이지인 http://192.168.219.1 에 들어가서 설정을 해줘야한다. 앞서 말한대로 랩탑의 주소인 192.168.219.180 과 U+의 보조 DNS 주소인 164.124.101.2 를 적어줬다. 이상하게도 “유선 네트워크 설정” 탭에만 DNS 설정이 있던데 이 설정이 무선 네트워크에도 동일하게 적용되는 듯하다. (다행..)

끝으로 PC에서는 자신의 DNS 설정이 공유기가 전달해주는 값으로 잘 사용 중인지 확인해본다. 이전에 내가 내 맥북에게 8.8.8.8 을 강제한 적이 있었는지 8.8.8.8으로 설정이 고정되어있었고 /etc/hosts 에서 레코드 설정을 지웠을 때 도메인 네임을 원활히 이용할 수 없었다. 위와 같이 고정값을 제거해주니 도메인 네임을 잘 이용할 수 있었다.

for domain in "laptop.lab" "pi"{200..204}".lab"; do
  ping $domain -c 1
  echo ''
done;

# Expected output:
PING laptop.lab (192.168.219.180): 56 data bytes
64 bytes from 192.168.219.180: icmp_seq=0 ttl=64 time=6.245 ms

--- laptop.lab ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 6.245/6.245/6.245/0.000 ms

PING pi200.lab (192.168.219.200): 56 data bytes
64 bytes from 192.168.219.200: icmp_seq=0 ttl=64 time=5.037 ms

--- pi200.lab ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 5.037/5.037/5.037/0.000 ms

...(생략)

PING pi203.lab (192.168.219.203): 56 data bytes
64 bytes from 192.168.219.203: icmp_seq=0 ttl=64 time=4.532 ms

--- pi203.lab ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 4.532/4.532/4.236/0.000 ms

끝으로 실제로 접속이 가능한지도 ping을 통해 확인해봤다.잘 되는 듯하다. (vm19[0-2]는 편의상 생략함.)

혹시 다른 dns server에게 질의하고서 다른 엔드포인트에게 ping을 날린 것은 아닐까 걱정됐다. 그럴 땐 로그를 확인하면 된다.

$ docker logs coredns --tail 100 -f

# Exptected output
...(생략)
[INFO] 192.168.219.103:60949 - 45524 "A IN laptop.lab. udp 27 false 512" NOERROR qr,aa,rd 52 0.000251775s
[INFO] 192.168.219.103:63828 - 32218 "A IN pi200.lab. udp 26 false 512" NOERROR qr,aa,rd 50 0.000233695s
[INFO] 192.168.219.103:52154 - 19774 "A IN pi201.lab. udp 26 false 512" NOERROR qr,aa,rd 50 0.000224735s
[INFO] 192.168.219.103:49555 - 29706 "A IN pi202.lab. udp 26 false 512" NOERROR qr,aa,rd 50 0.000230596s
[INFO] 192.168.219.103:53338 - 47975 "A IN pi203.lab. udp 26 false 512" NOERROR qr,aa,rd 50 0.000225897s

로그도 나의 dns server가 잘 동작한다는 것을 보여준다. 🙂 얏호~!

TODO

앞으로 반려 서버 키우기를 진행하게 되면 몇 가지 수정사항들이 있을 수 있을 것 같고, 그에 맞춰 이 글에도 수정사항들이 반영될 수 있을 것 같다. 예상되는 TODO는 다음과 같다.

  • Record 관리 개선 - 현재는 bash script로 레코드를 관리하는 셈인데 Git을 이용하고 자동으로 sync를 맞추든 다른 방안을 찾아보든 하면 좋겠다.
  • 공유기 구비 - U+의 기본 제공 공유기로는 기능이 좀 부족한 면이 있다. DNS 서버 뿐만 아니라 공유기 자체도 코딩이 가능한 나만의 장비를 쓰면 좋을 듯한데 그 이유는 각 장치에게 DHCP static lease를 좀 더 잘 해주고싶기 때문이다. 현재는 공유기 관리 페이지에서 장치별로 MAC address에 따라 static lease해주고 있다. 그리고 공유기 설정 뭐만 바꾸면 몇 십초 동안 중단되어버림…
  • DNS 서버용 장치 구비 - 현재 CoreDNS가 laptop에 떠있는데 laptop이 뻗는다거나하면 U+의 보조 DNS 서버를 이용하게 된다. 따라서 이건 저렴한 장치(e.g. Raspberry Pi 3)를 DNS server dedicated로 사용하면 어떨까싶다.

Change log

  • [rev 3] 2022-12-11
    • OSX에서는 자꾸만 DNS가 캐시되어버려서 public한 TLD인 .me가 아닌 private한 TLD인 .lab으로 TLD를 변경함
    • laptop과 pi뿐만 아니라 vm도 추가함
  • [rev 2] 2022-11-29 - file plugin이 아닌 hosts plugin을 이용하도록 개선함
    • file plugin에는 fallthrough 기능이 없었음. 따라서 CoreDNS선에서 NXDOMAIN이 발생하는 경우 다음 plugin인 forward로 8.8.8.8에 질의할 수 없었다. 이를 바로 깨닫지는 못했는데 그 이유는 초반에는 OS와 브라우저의 캐시 때문에 잘 동작했었기 때문이다.
  • [rev 1] 2022-11-29 - file plugin으로 me. Zone에 대한 레코드 정보 제공

참고

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Hugo로 만듦
JimmyStack 테마 사용 중