#はじめに
前回ClusterIPの動作を確認しました。
その際、動作確認用のPodにはClusterIPのIPアドレスを設定していました。しかし、Kubernetesで実現するマイクロサービスでは、頻繁にリソースを追加削除します。各リソースにはKubernetesが自動でIPアドレスを割り当てますので、IPアドレスはデプロイの度に変わります。そのため、アプリケーション内ではIPアドレスではなく、DNS名を使用するのが望ましいでしょう。
そこで今回は、クラスタ内でのDNSの動作を確認したいと思います。
#クラスタ内のDNS
マニュアルには以下のような記載があります。クラスタ内では、kubernetesがDNSのサービスを提供しています。
KubernetesのDNSはクラスター上でDNS PodとServiceをスケジュールし、DNSの名前解決をするために各コンテナに対してDNS ServiceのIPを使うようにKubeletを設定します。
kubernetes.io
提供されるサービスは以下の2つがあります。
- Aレコード
- SRVレコード
##Aレコード
Serviceには、「[サービス名].[ネームスペース名].svc.cluster.local」という形式のDNS Aレコードが割り当てられています。
前回作成したClusterIPを例にすると、「cluster-ip.default.svc.cluster.local」になります。
###動作確認
前回の環境で、動作確認用のPodに指定したClusterIPのIPアドレスをFQDNに書き換えました。
これで同様に動作確認してみたいと思います。
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: centos
image: centos:latest
command:
- sh
- -c
args:
- for i in 1 2 3 4 5 ; do curl -s http://cluster-ip.default.svc.cluster.local:8080 ; sleep 5; done ;exit 0
このマニフェストをapplyして、30秒ほど待ってlogを確認します。
$ kubectl apply -f test_pod.yaml
pod/test-pod created
$ kubectl logs test-pod | grep pod
pod1
pod2
pod2
pod1
pod2
IPアドレスを指定した時と同様にClusterIPに対してリクエストが送られていますね。
なお、今回は正式なFQDNを指定しましたが、Podとサービスが同じネームスペースの場合には、[サービス名]だけでも名前解決ができます。
これは、デプロイされるコンテナの/etc/resolve.confにsearchから始まる一行があるため、[サービス名]だけ、ネームスペースが異なる場合には、「[サービス名].[ネームスペース名]」だけでも名前解決ができます。
$ kubectl exec -it test-pod /bin/bash
[root@test-pod /]# cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
##SRVレコード
SRVレコードは、一言で言うとポート番号を含めたDNSです(と私は理解しました)。SRVレコードは以下の形式になります。
[_Serviceのポート名].[_ポートのプロトコル].[サービス名].[ネームスペース名].svc.cluster.local
前回作成したClusterIPの詳細を確認します。
$ kubectl describe svc cluster-ip
Name: cluster-ip
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"cluster-ip","namespace":"default"},"spec":{"ports":[{"name":"clus...
Selector: app=nginx-dep
Type: ClusterIP
IP: 10.101.47.213
Port: cluster-port 8080/TCP
TargetPort: 80/TCP
Endpoints: 192.168.69.234:80,192.168.79.98:80
Session Affinity: None
Events: <none>
上記の結果から、このClusterIPのSVRレコードは、以下になります。
_cluster-port._TCP.cluster-ip.default.svc.cluster.local
###動作確認
動作確認用のPodとして、以下のマニフェストのPodをデプロイします。
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: centos
image: centos:latest
command:
- sh
- -c
args:
- tail -f /dev/null
$ kubectl apply -f test_pod2.yaml
pod/test-pod created
Podにログインします。
$ kubectl exec -it test-pod /bin/bash
[root@test-pod /]#
デフォルトでは、nslookupやdigコマンドがないため、インストールします。
[root@test-pod /]# yum install -y bind-utils
Failed to set locale, defaulting to C.UTF-8
CentOS-8 - AppStream 1.7 MB/s | 6.6 MB 00:03
CentOS-8 - Base 1.8 MB/s | 5.0 MB 00:02
CentOS-8 - Extras 6.1 kB/s | 4.9 kB 00:00
Dependencies resolved.
・・・
Installed:
bind-utils-32:9.11.4-26.P2.el8.x86_64 bind-libs-32:9.11.4-26.P2.el8.x86_64 bind-libs-lite-32:9.11.4-26.P2.el8.x86_64 bind-license-32:9.11.4-26.P2.el8.noarch python3-bind-32:9.11.4-26.P2.el8.noarch
python3-ply-3.9-7.el8.noarch
Complete!
nslookupとdigで確認します。
[root@test-pod /]]# nslookup -type=srv _cluster-port._TCP.cluster-ip.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
_cluster-port._TCP.cluster-ip.default.svc.cluster.local service = 0 100 8080 cluster-ip.default.svc.cluster.local.
[root@test-pod /]# dig _cluster-port._TCP.cluster-ip.default.svc.cluster.local SRV
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el8 <<>> _cluster-port._TCP.cluster-ip.default.svc.cluster.local SRV
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8930
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 2
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 3127dac7c4b7e34a (echoed)
;; QUESTION SECTION:
;_cluster-port._TCP.cluster-ip.default.svc.cluster.local. IN SRV
;; ANSWER SECTION:
_cluster-port._TCP.cluster-ip.default.svc.cluster.local. 30 IN SRV 0 100 8080 cluster-ip.default.svc.cluster.local.
;; ADDITIONAL SECTION:
cluster-ip.default.svc.cluster.local. 30 IN A 10.101.47.213
;; Query time: 1 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Sat Apr 04 12:37:15 UTC 2020
;; MSG SIZE rcvd: 259
どちらの結果でも、cluster-ipサービスのポート「8080」とホスト名「cluster-ip.default.svc.cluster.local」が解決できていますね。
#まとめ
KubernetesではIPアドレスは自動で割り当てられるため、IPアドレスではなくDNS名を指定して各リソース間で通信をするのが望ましいです。マイクロサービスを開発するには、今回確認したDNSの設定と動作を理解しておく必要がありますね。
#補足
ClusterIPに割り当てられるIPアドレスをユーザーが指定することができます。指定する場合は、「spec.clusterIP」フィールドに指定するIPアドレスを記載します。
指定できるIPアドレスは、APIサーバに設定されている「service-cluster-ip-range」内のアドレスである必要があります。
$ kubectl -n kube-system describe pod/kube-apiserver-k8s-master | grep range
--service-cluster-ip-range=10.96.0.0/12
ユーザー所有のIPアドレスを選択する
kubernetes.io