前回は、ingress-nginxを使ったIngressコントローラーのインストールを試してみました。今回は、Ingressで作成したDNSレコードをKubernetesのクラスタ外からでも名前解決できるように、CoreDNSのk8s_gatewayプラグインを使って、DNSサーバーへの連携について試してみました。
構成
- vCenter 7.0 U3
- ESXi 7.0 Update 3
- Ubuntu 22.04 (テンプレートVM)
- open-vm-tools 11.3.5
- cloud-init 22.2
- Kubespray
- kubernetes v1.25.5
- MetalLB v0.12.1
- ingress-nginx v1.5.1
- CoreDNS
- EdgeRouter X
はじめに
前回、Ingressを作成し、ホスト名でアクセスできることを確認しました。利用端末で/etc/hostsに以下のように追記をすれば利用はできますが、都度hostsファイルを編集するのは大変なため、DNSサーバーへDNSレコードを連携したくなります。
Ingressで作成したDNSレコードをKubernetesのクラスタ外からでも名前解決できるようにするためには、一般的にはExternalDNSを利用されるようです。ExternalDNSは、ServiceやIngressなどのKubernetesのリソースを検知して、DNSプロバイダーへDNSレコードを連携してくれます。
ExternalDNSがサポートするDNSプロバイダーとして、クラウドのサービスやCoreDNSなどが利用できることが分かります。
CoreDNSはGoで記述されており、Kubernetesクラスタの一部で稼働しています。CoreDNSをデプロイする場合、ExternalDNSと連携するために、etcdを利用する方法もありますが、CoreDNSのhelmチャートで利用されているetcd-operatorがアーカイブされており、利用できないことが分かります。
- GitHub - coredns/helm: Helm Charts for CoreDNS
- GitHub - coreos/etcd-operator: etcd operator creates/configures/manages etcd clusters atop Kubernetes
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 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単体ではホスト名でアクセスに成功したため、Ingressとk8s_gatewayが競合していたのではと推測しています。
まとめ
k8s_gatewayプラグインを使ったDNSサーバーに連携できることで、homelabで新しいServiceをデプロイした場合でもホスト名でアクセスできるようになったため、より利便性が良くなったと思います。