こんにちは。
株式会社クラスアクト インフラストラクチャ事業部の大塚です。
今回はKubernetesのDNSについて勉強がてら動作の確認をしてみましたので
それを書き記しておこうと思います。
環境
環境はいつも通り、Proxmox VEというハイパーバイザ上にubuntu22.04のVMを4台立ち上げ、そこにmicrok8sをインストール。master×1台 + worker×3台というKubernetesクラスタ構成となります。
root@k8s-master:~/yaml# kubectl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-worker01 Ready <none> 3m58s v1.26.4 192.168.2.31 <none> Ubuntu 22.04.2 LTS 5.15.0-71-generic containerd://1.6.15
k8s-worker03 Ready <none> 2m37s v1.26.4 192.168.2.33 <none> Ubuntu 22.04.2 LTS 5.15.0-71-generic containerd://1.6.15
k8s-master Ready <none> 47h v1.26.4 192.168.2.30 <none> Ubuntu 22.04.2 LTS 5.15.0-71-generic containerd://1.6.15
k8s-worker02 Ready <none> 47h v1.26.4 192.168.2.32 <none> Ubuntu 22.04.2 LTS 5.15.0-71-generic containerd://1.6.15
またdefaultのnamespaceには何もデプロイしておりません。
出力はされていますがデフォルトで作成されるものになりますので、気にしないでください。
root@k8s-master:~/yaml# kubectl get pod,svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 47h <none>
用語
namespace
Kubernetesは、同一の物理クラスター上で複数の仮想クラスターの動作をサポートします。 この仮想クラスターをNamespaceと呼びます。
私の今回の環境でいうと物理クラスタ:4台のnodeで構成されたもの。仮想クラスタ:default namespaceとかkube-system namespaceのこと。ということですね。物理的には1つのクラスタしかないけれど、仮想的にはそれ以上のクラスタが存在している。それを実現するためにnamespaceという技術・概念がある。ということになるかと。
今回私の検証は最終的に3つのnsが絡んできますが、仮想クラスタと物理クラスタをイメージに落とし込むと次のようになると思います。私の認識が違くなければ。
default namespaceに検証用のpod,ds,svcをデプロイして名前解決の動作確認をする
まずは検証用のpodをデプロイします。今回用意したyamlファイルは以下となります。
apiVersion: v1
kind: Pod
metadata:
name: deb-ubuntu
spec:
containers:
- name: deb-ubuntu-con
image: shotaohtsuka/deb-ubuntu-image:latest
command: ['tail', '-f', '/dev/null']
yamlについて
- imageですが、私が自分で用意したものとなります。
ざっくり記載しますが、ubuntu:22.04のdocker imageをベースにping,ip,vi,traceroute,nslookup,curl,systemctlコマンドをインストールしたdocker imageになります。今回はこのimageをもとにデプロイしたpodにアクセスし、そこからnslookupやcurlを使ってDNSの名前解決ができるかを確認していきます。
- commandでtail -f /dev/nullを実行するようにしておりますが、これを実行しないと以下の記事に書いている通り、pod内の稼働中のプロセスが無いことが原因で、podが勝手に停止をしてしまうので、その対策となります。
このyamlファイルをもとにデプロイします。
今回はk8s-worker03 nodeにデプロイされましたね。
root@k8s-master:~/yaml# kubectl create -f pod-deb-ubuntu.yaml
pod/deb-ubuntu created
root@k8s-master:~/yaml# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deb-ubuntu 1/1 Running 0 67s 10.1.39.193 k8s-worker03 <none> <none>
続いてnginxのDeamonSetとそれに関連したClusterIPをデプロイしていきます。
yamlファイルは以下となります。
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-ds
spec:
selector:
matchLabels:
name: nginx
template:
metadata:
labels:
name: nginx
spec:
tolerations:
- key: "env"
operator: "Equal"
value: "master"
effect: NoSchedule
containers:
- name: nginx-container
image: nginx:latest
apiVersion: v1
kind: Service
metadata:
name: clusterip-nginx-ds
spec:
selector:
name: nginx
type: ClusterIP
ports:
- name: nginx
port: 80
protocol: TCP
targetPort: 80
デプロイはいつも通り、kubectl create -fです。
デプロイした結果が以下となります。
root@k8s-master:~/yaml# kubectl get pod,svc -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/deb-ubuntu 1/1 Running 0 4m6s 10.1.39.193 k8s-worker03 <none> <none>
pod/nginx-ds-jfzxv 1/1 Running 0 40s 10.1.235.213 k8s-master <none> <none>
pod/nginx-ds-v2qf5 1/1 Running 0 40s 10.1.39.194 k8s-worker03 <none> <none>
pod/nginx-ds-xmmfq 1/1 Running 0 40s 10.1.79.65 k8s-worker01 <none> <none>
pod/nginx-ds-pdl4d 1/1 Running 0 40s 10.1.69.196 k8s-worker02 <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 47h <none>
service/clusterip-nginx-ds ClusterIP 10.152.183.117 <none> 80/TCP 32s name=nginx
上記出力結果をイメージに落とし込むと以下となります。
緑の枠線で囲われている部分はdefault namespaceになります。
名前解決を検証していきます。まずdebug用のubuntu-pod/containerに接続し、/etc/hosts及び/etc/resolv.confを確認してみます。
デフォルトで10.152.183.10というIPアドレスがDNSサーバとして設定されており、どこに紐づいているかが気になるところです。
root@k8s-master:~/yaml# kubectl exec -it deb-ubuntu -c deb-ubuntu-con -- /bin/bash
root@deb-ubuntu:/# cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.1.39.193 deb-ubuntu
root@deb-ubuntu:/# cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.152.183.10
options ndots:5
k8sのDNS周りの情報を調べてみます。
どうやら上記のIPアドレスはDNSのClusterIP serviceに関連づいている様ですね。
root@k8s-master:~# kubectl get all -o wide --namespace=kube-system | grep dns
pod/coredns-6f5f9b5d74-pf4ld 1/1 Running 2 (38h ago) 47h 10.1.235.206 k8s-master <none> <none>
service/kube-dns ClusterIP 10.152.183.10 <none> 53/UDP,53/TCP,9153/TCP 47h k8s-app=kube-dns
deployment.apps/coredns 1/1 1 1 47h coredns coredns/coredns:1.9.3 k8s-app=kube-dns
replicaset.apps/coredns-6f5f9b5d74 1 1 1 47h coredns coredns/coredns:1.9.3 k8s-app=kube-dns,pod-template-hash=6f5f9b5d74
イメージに落とし込みます。
赤枠内がkube-system namespaceになります。このnamespaceの中にDNSのpod(正確にはdeplolyment)とそれに関連したClusterIP serviceがデプロイされています。
ubuntuのpodに戻ります。このpodから名前解決できるか確認していきます。
具体的にはubuntuのpodと同一ns内にあるnginxのClustrIP serviceのドメイン名を名前解決できるかをnslookup及びcurlで確認していきます。
まずはnslookip。Addressの欄にnginxのClusterIP serviceのIPが出力されていることから問題ないように見られます。
root@deb-ubuntu:/# nslookup clusterip-nginx-ds
Server: 10.152.183.10
Address: 10.152.183.10#53
Name: clusterip-nginx-ds.default.svc.cluster.local
Address: 10.152.183.117
curlを実行してみます。nginxのhtmlファイルを取得できていることから、併せて問題なさそうです。
root@deb-ubuntu:/# curl clusterip-nginx-ds:80
<!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>
ubuntu podの名前解決のフローをイメージに落とし込むと以下のようになります。
default namespaceではないnsにpod,ds,svcをデプロイして名前解決の動作確認をする
nsが違う場合の名前解決を試してみます。
現状のnsは以下となります。
root@k8s-master:~/yaml# kubectl get ns
NAME STATUS AGE
kube-system Active 2d
kube-public Active 2d
kube-node-lease Active 2d
default Active 2d
metallb-system Active 47h
以下のyamlを用意し、nsを新規作成します。
このnsは作成したばかりのため、当たり前ですがなにもデプロイされていませんね。
apiVersion: v1
kind: Namespace
metadata:
name: myns
root@k8s-master:~/yaml# kubectl create -f ns-myns.yaml
root@k8s-master:~/yaml# kubectl get ns
NAME STATUS AGE
kube-system Active 2d
kube-public Active 2d
kube-node-lease Active 2d
default Active 2d
metallb-system Active 47h
myns Active 4s
root@k8s-master:~/yaml# kubectl get all --namespace=myns
No resources found in myns namespace.
新規作成したmynsにapacheのDeamonSetとそれに関連したClusterIP serviceをデプロイしていきたいと思います。用意したyamlファイルは以下2点です。
注意点としては、今回はdefault namespaceではなく、作成したmyns namespaceにデプロイしたいのでそれぞれのyamlファイルのmetadata.namespaceでnsを指定している点位かと思います。
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: apache-ds-myns
namespace: myns
spec:
selector:
matchLabels:
name: apache
template:
metadata:
labels:
name: apache
spec:
tolerations:
- key: "env"
operator: "Equal"
value: "master"
effect: NoSchedule
containers:
- name: apache-container
image: shotaohtsuka/my-httpd-image
apiVersion: v1
kind: Service
metadata:
name: clusterip-apache2-ds-myns
namespace: myns
spec:
selector:
name: apache
type: ClusterIP
ports:
- name: apache
port: 90
protocol: TCP
targetPort: 90
これらのyamlを使いデプロイします。
root@k8s-master:~/yaml# kubectl create -f apache2-ds-myns.yaml
daemonset.apps/apache-ds-myns created
root@k8s-master:~/yaml# kubectl create -f clusterip-apache2-ds-myns.yaml
service/clusterip-apache2-ds-myns created
デプロイ結果を確認します。pod,svc共に正常にデプロイできていそうです。
root@k8s-master:~/yaml# kubectl get pod --namespace=myns -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
apache-ds-myns-9785z 1/1 Running 0 81m 10.1.235.214 k8s-master <none> <none>
apache-ds-myns-5tjrr 1/1 Running 0 81m 10.1.79.66 k8s-worker01 <none> <none>
apache-ds-myns-d4f2h 1/1 Running 0 81m 10.1.39.195 k8s-worker03 <none> <none>
apache-ds-myns-k8qfv 1/1 Running 0 81m 10.1.69.197 k8s-worker02 <none> <none>
root@k8s-master:~/yaml# kubectl get svc --namespace=myns
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
clusterip-apache2-ds-myns ClusterIP 10.152.183.115 <none> 90/TCP 54s
この時のイメージは以下となります。
ピンクの枠線内がここで新規に作成したnsであるmynsになります。このns内にapache関連のdsとClusterIP serviceをデプロイしています。
ubuntuのpodにおいて同一ns内と同じ様に、ドメイン名だけで名前解決できないことを確認します。
具体的にはdefault namespace内のubuntu podからmyns namespaceのapacheのClusterIP serviceのドメイン名で名前解決できないことを確認します。
catn't findの出力より、名前解決に失敗していることがわかりますね。
root@k8s-master:~/yaml# kubectl exec -it deb-ubuntu -c deb-ubuntu-con -- /bin/bash
root@deb-ubuntu:/# nslookup clusterip-apache2-ds-myns
Server: 10.152.183.10
Address: 10.152.183.10#53
** server can't find clusterip-apache2-ds-myns: NXDOMAIN
一方でドメインに対して".myns"のようにnsを指定してあげると名前解決ができることを確認します。
nslookupもcurlも成功していることからうまくいっていることがわかるかと思います。
root@deb-ubuntu:/# nslookup clusterip-apache2-ds-myns.myns
Server: 10.152.183.10
Address: 10.152.183.10#53
Name: clusterip-apache2-ds-myns.myns.svc.cluster.local
Address: 10.152.183.115
root@deb-ubuntu:/# curl clusterip-apache2-ds-myns.myns:90
<html><body><h1>It works!</h1></body></html>
ちなみにnsが違うpodの疎通って出来るんだろうか?
過去、同一のns内であればpod同士の疎通が取れる。xvlan上にpodがデプロイされるからnodeが違っても関係なく疎通が取れることは検証できた。
だが、今回はnsが異なる。この時どうなるのだろうか?ネットワーク的には同じ様に見えるため通信はできそうであるが確認してみることにする。ubuntuのpodからmynsのk8s-master上のpodとk8s-worker01上のpodにpingを試みる。
結果として疎通が取れた。名前解決が絡んでくるときだけ、nsが影響してくるのかな。。。?
root@k8s-master:~# kubectl exec -it deb-ubuntu -c deb-ubuntu-con -- /bin/bash
root@deb-ubuntu:/# ping 10.152.183.115
PING 10.152.183.115 (10.152.183.115) 56(84) bytes of data.
^C
--- 10.152.183.115 ping statistics ---
8 packets transmitted, 0 received, 100% packet loss, time 7150ms
root@deb-ubuntu:/# ping 10.1.235.214
PING 10.1.235.214 (10.1.235.214) 56(84) bytes of data.
64 bytes from 10.1.235.214: icmp_seq=1 ttl=62 time=1.39 ms
64 bytes from 10.1.235.214: icmp_seq=2 ttl=62 time=0.643 ms
64 bytes from 10.1.235.214: icmp_seq=3 ttl=62 time=0.522 ms
64 bytes from 10.1.235.214: icmp_seq=4 ttl=62 time=0.579 ms
64 bytes from 10.1.235.214: icmp_seq=5 ttl=62 time=0.547 ms
^C
--- 10.1.235.214 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4060ms
rtt min/avg/max/mdev = 0.522/0.735/1.385/0.327 ms
root@deb-ubuntu:/# ping 10.1.79.66
PING 10.1.79.66 (10.1.79.66) 56(84) bytes of data.
64 bytes from 10.1.79.66: icmp_seq=1 ttl=62 time=1.07 ms
64 bytes from 10.1.79.66: icmp_seq=2 ttl=62 time=0.636 ms
64 bytes from 10.1.79.66: icmp_seq=3 ttl=62 time=0.550 ms
64 bytes from 10.1.79.66: icmp_seq=4 ttl=62 time=0.498 ms
64 bytes from 10.1.79.66: icmp_seq=5 ttl=62 time=0.639 ms
^C
--- 10.1.79.66 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4078ms
rtt min/avg/max/mdev = 0.498/0.679/1.072/0.203 ms