hidemium's blog

日々学んだことをアウトプットする。

CoreDNSのk8s_gatewayプラグインを使ったDNSサーバーへの連携

前回は、ingress-nginxを使ったIngressコントローラーのインストールを試してみました。今回は、Ingressで作成したDNSレコードをKubernetesクラスタ外からでも名前解決できるように、CoreDNSのk8s_gatewayプラグインを使って、DNSサーバーへの連携について試してみました。

hidemium.hatenablog.com

構成

はじめに

前回、Ingressを作成し、ホスト名でアクセスできることを確認しました。利用端末で/etc/hostsに以下のように追記をすれば利用はできますが、都度hostsファイルを編集するのは大変なため、DNSサーバーへDNSレコードを連携したくなります。

Ingressで作成したDNSレコードをKubernetesクラスタ外からでも名前解決できるようにするためには、一般的にはExternalDNSを利用されるようです。ExternalDNSは、ServiceやIngressなどのKubernetesのリソースを検知して、DNSプロバイダーへDNSレコードを連携してくれます。

GitHub - kubernetes-sigs/external-dns: Configure external DNS servers (AWS Route53, Google CloudDNS and others) for Kubernetes Ingresses and Services

ExternalDNSがサポートするDNSプロバイダーとして、クラウドのサービスやCoreDNSなどが利用できることが分かります。

CoreDNSはGoで記述されており、Kubernetesクラスタの一部で稼働しています。CoreDNSをデプロイする場合、ExternalDNSと連携するために、etcdを利用する方法もありますが、CoreDNSのhelmチャートで利用されているetcd-operatorがアーカイブされており、利用できないことが分かります。

CoreDNSとetcdのマニフェストファイルを書くか、docker-composeを使って構築し、ExternalDNSと連携することもできますが、労力がかかりそうなため、ExternalDNSは使わずにCoreDNSのk8s_gatewayプラグインを利用しました。

k8s_gatewayプラグインは、内部のkube-dnsとは別のインスタンスとしてデプロイでき、Kubernetesクラスタの外部DNSインターフェースとして機能します。

k8s_gatewayは、nginxinc kubernetes-ingressをサポートしていますが、今回は、ingress-nginxで動作確認をしています。

k8s_gatewayのインストール

k8s_gatewayのインストールは、helmチャートを提供してくれているため、以下のようにhelmをインストールします。

$ curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
$ sudo apt-get install apt-transport-https --yes
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
$ sudo apt-get update
$ sudo apt-get install helm

Helm | Helm のインストール

以下のように、k8s_gatewayをインストールします。

$ helm repo add k8s_gateway https://ori-edge.github.io/k8s_gateway/
$ helm install exdns --set domain=kube.home.lab k8s_gateway/k8s-gateway

便利なことに、k8s_gatewayがLoadBalancerで公開され、EXTERNAL-IPにMetalLBで設定したIPアドレスが付与されていることが分かります。

$ kubectl get pod,svc,ingress
NAME                                     READY   STATUS    RESTARTS   AGE
pod/exdns-k8s-gateway-58bf7c6c75-qksjm   0/1     Running   0          7s

NAME                        TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
service/exdns-k8s-gateway   LoadBalancer   10.233.13.50   10.0.50.202   53:30273/UDP   7s
service/kubernetes          ClusterIP      10.233.0.1     <none>        443/TCP        14d

k8s_gatewayの動作確認

nginxサーバーをデプロイし、 nginx.kube.home.lab というホスト名でIngressを作成し、ホスト名でアクセスできることを確認します。

$ kubectl create deployment nginx --image=nginx --port=80
$ kubectl expose deployment nginx
$ kubectl create ingress nginx --class=nginx --rule nginx.kube.home.lab/=nginx:80
$ kubectl get pod,svc,ingress
NAME                                     READY   STATUS    RESTARTS   AGE
pod/exdns-k8s-gateway-58bf7c6c75-qksjm   1/1     Running   0          14m
pod/nginx-ff6774dc6-kx9mr                1/1     Running   0          15s

NAME                        TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
service/exdns-k8s-gateway   LoadBalancer   10.233.13.50   10.0.50.202   53:30273/UDP   14m
service/kubernetes          ClusterIP      10.233.0.1     <none>        443/TCP        14d
service/nginx               ClusterIP      10.233.50.84   <none>        80/TCP         11s

NAME                              CLASS   HOSTS                 ADDRESS   PORTS   AGE
ingress.networking.k8s.io/nginx   nginx   nginx.kube.home.lab             80      5s

nginxサーバーに対してホスト名でアクセスできるか確認します。

$ INGRESS_EXTERNAL_IP=`kubectl get svc --namespace=ingress-nginx ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}'`
$ echo $INGRESS_EXTERNAL_IP
10.0.50.201
$ curl $INGRESS_EXTERNAL_IP -H "Host: nginx.kube.home.lab"
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

digでk8s_gatewayのEXTERNAL-IPに対して、名前解決ができるか確認します。

$ dig @10.0.50.202 nginx.kube.home.lab
; <<>> DiG 9.16.1-Ubuntu <<>> @10.0.50.202 nginx.kube.home.lab
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5905
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 1e039be809cc823c (echoed)
;; QUESTION SECTION:
;nginx.kube.home.lab.           IN      A

;; ANSWER SECTION:
nginx.kube.home.lab.    300     IN      A       10.0.50.201

;; Query time: 4 msec
;; SERVER: 10.0.50.202#53(10.0.50.202)
;; WHEN: Sun Jan 08 12:16:48 JST 2023
;; MSG SIZE  rcvd: 95

EdgeRouterの設定

EdgeRouterを利用端末のDNSサーバーとして利用しています。EdgeRouterは外部のDNSサーバーへDNS forwardingできる機能があるため、k8s_gatewayのEXTERNAL-IPに対して、DNS forwardingできるように以下のように設定を行います。

set service dns forwarding options server=/kube.home.lab/10.0.50.202

https://help.ui.com/hc/en-us/articles/115010913367-EdgeRouter-DNS-Forwarding-Setup-and-Options

それでは、利用端末から名前解決ができるか確認します。手元の環境は、Windows OSを利用しているため、以下のコマンドで確認します。

> nslookup nginx.kube.home.lab
サーバー:  UnKnown
Address:  10.0.1.1

名前:    nginx.kube.home.lab
Address:  10.0.50.201

curlでもアクセスできることを確認します。

> curl nginx.kube.home.lab


StatusCode        : 200
StatusDescription : OK
Content           : <!DOCTYPE html>
                    <html>
                    <head>
                    <title>Welcome to nginx!</title>
                    <style>
                    html { color-scheme: light dark; }
                    body { width: 35em; margin: 0 auto;
                    font-family: Tahoma, Verdana, Arial, sans-serif; }
                    </style...
RawContent        : HTTP/1.1 200 OK
                    Connection: keep-alive
                    Accept-Ranges: bytes
                    Content-Length: 615
                    Content-Type: text/html
                    Date: Sun, 08 Jan 2023 04:18:23 GMT
                    ETag: "6398a011-267"
                    Last-Modified: Tue, 13 Dec 2022 ...
Forms             : {}
Headers           : {[Connection, keep-alive], [Accept-Ranges, bytes], [Content-Length, 615], [Content-Type, text/html]
                    ...}
Images            : {}
InputFields       : {}
Links             : {@{innerHTML=nginx.org; innerText=nginx.org; outerHTML=<A href="http://nginx.org/">nginx.org</A>; o
                    uterText=nginx.org; tagName=A; href=http://nginx.org/}, @{innerHTML=nginx.com; innerText=nginx.com;
                     outerHTML=<A href="http://nginx.com/">nginx.com</A>; outerText=nginx.com; tagName=A; href=http://n
                    ginx.com/}}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 615

最後にブラウザから https://nginx.kube.home.lab にアクセスできることを確認します。信頼されない証明書が発行されるので、ブラウザでHTTPSで接続して確認します。信頼されない証明書の警告がでるので、詳細設定からアクセスすると、Welcome to nginx!のページが表示されます。証明書のCommon Nameは Kubernetes Ingress Controller Fake Certificateになっていました。

リソースの削除

動作確認ができたので、リソースを削除しておきます。

$ kubectl delete deployment nginx
$ kubectl delete svc nginx
$ kubectl delete ingress nginx

発生した事象について

helmチャートでk8s_gatewayをインストール後に、nginxサーバーをデプロイし、 nginx.kube.home.lab というホスト名でIngressを作成後に、ホスト名でアクセスが失敗し、以下のエラーが発生することがありました。

$ curl $INGRESS_EXTERNAL_IP -H "Host: nginx.kube.home.lab"
<html>
<head><title>504 Gateway Time-out</title></head>
<body>
<center><h1>504 Gateway Time-out</h1></center>
<hr><center>nginx</center>
</body>
</html>

k8s_gatewayの再インストールや、nginxサーバーの再デプロイで解消しましたが、詳細なログを確認できていないため、原因は不明ですが、Ingress単体ではホスト名でアクセスに成功したため、Ingressk8s_gatewayが競合していたのではと推測しています。

まとめ

k8s_gatewayプラグインを使ったDNSサーバーに連携できることで、homelabで新しいServiceをデプロイした場合でもホスト名でアクセスできるようになったため、より利便性が良くなったと思います。

参考