はじめに
前回の実験では、Service が Pod に対してクラスター内で安定したエントリポイントを提供する方法を学びました。Kubernetes は各 Service に DNS 名も割り当てます。通常、同じ名前空間内の Pod は短い Service 名(ショートネーム)を使用できますが、異なる名前空間にある Pod は、Service の名前空間を含む長い名前(FQDN)を使用する必要があります。
この実験では、Web Service を作成し、同一名前空間での DNS アクセスをテストします。次に、名前空間を跨いだショートネームによるアクセス失敗を再現し、Service の FQDN を使用して解決します。最後に、DNS の問題が Service、エンドポイント、あるいは CoreDNS のどこにあるのかを診断するためのオブジェクトの確認方法を学びます。
Web Service の準備
このステップでは、後の DNS テストで名前解決の対象となる Service を作成します。今回の主なトピックは DNS の命名規則であり、アプリケーションのデプロイ自体ではないため、ワークロードはシンプルなものを使用します。
/home/labex/project に移動して開始します:
mkdir -p /home/labex/project
cd /home/labex/project
Kubernetes API サーバーに接続できるか確認します。VM が起動した直後でノードの準備ができていない場合は、数秒待ってから再度コマンドを実行してください。
kubectl get nodes --request-timeout=5s
期待される出力:
NAME STATUS ROLES AGE VERSION
labex-v135 Ready control-plane ... v1.35...
クラスターのネットワークが Ready になるまで待ちます。この実験では Pod 間でトラフィックを送信するため、DNS アクセスのテストを行う前に Pod ネットワークが正常である必要があります。
kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s
期待される出力:
pod/calico-node-... condition met
ckad-prep-dns という名前空間を作成し、現在の名前空間として設定します:
kubectl create namespace ckad-prep-dns
kubectl config set-context --current --namespace=ckad-prep-dns
Deployment を作成し、dns-web という名前の Service として公開します:
kubectl create deployment dns-web --image=nginx:1.25 --port=80
kubectl expose deployment dns-web --port=80 --target-port=80
Web Pod が利用可能になるまで待ちます:
kubectl rollout status deployment/dns-web --timeout=120s
Service とその EndpointSlice を確認します。Service は安定した DNS のターゲットであり、EndpointSlice は Service によって選択された現在のバックエンド Pod のアドレスを示します。
kubectl get service dns-web
kubectl get endpointslice -l kubernetes.io/service-name=dns-web
期待される出力:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dns-web ClusterIP ... <none> 80/TCP ...
NAME ADDRESSTYPE PORTS ENDPOINTS AGE
dns-web-... IPv4 80 ... ...
同一名前空間からの Service 名前解決
このステップでは、Service と同じ名前空間にクライアント Pod を作成し、短い Service 名を使用してアクセスします。これは最も単純な Service DNS のケースです。
実行し続けるクライアント Pod を作成します:
kubectl run same-ns-client --image=busybox:1.36 --restart=Never --command -- sleep 3600
クライアント Pod が Ready になるまで待ちます:
kubectl wait --for=condition=Ready pod/same-ns-client --timeout=120s
期待される出力:
pod/same-ns-client condition met
クライアント Pod 内で nslookup を使用し、短い Service 名 dns-web を解決します。クライアント Pod と Service が同じ名前空間にあるため、ショートネームで解決できます。BusyBox の nslookup は、他の検索サフィックスに対して NXDOMAIN を出力したり、正しいアドレスを表示した後にゼロ以外の終了コードを返したりすることがあるため、コマンドでは || true を使用しています。Name と Address の行を確認してください。
kubectl exec same-ns-client -- sh -c 'nslookup dns-web || true'
期待される出力:
Name: dns-web.ckad-prep-dns.svc.cluster.local
Address: ...
次に、Service のショートネームに対して HTTP リクエストを送信します:
kubectl exec same-ns-client -- wget -qO- http://dns-web | grep '<title>Welcome to nginx'
期待される出力:
<title>Welcome to nginx!</title>
名前空間を跨ぐショートネームの失敗を診断する
このステップでは、異なる名前空間にクライアント Pod を作成し、よくある DNS の間違いを再現します。短い Service 名はまずクライアント Pod の名前空間を基準に解決されるため、クライアントが別の名前空間で実行されている場合、dns-web は ckad-prep-dns 内の Service を見つけることができません。
2 つ目の名前空間を作成し、そこにクライアント Pod を作成します:
kubectl create namespace ckad-prep-dns-client
kubectl run remote-client --namespace ckad-prep-dns-client --image=busybox:1.36 --restart=Never --command -- sleep 3600
kubectl wait --namespace ckad-prep-dns-client --for=condition=Ready pod/remote-client --timeout=120s
期待される出力:
namespace/ckad-prep-dns-client created
pod/remote-client created
pod/remote-client condition met
リモートの名前空間からショートネームを解決してみます。この失敗は想定通りであるため、|| true を使用して実験を続行します。
kubectl exec --namespace ckad-prep-dns-client remote-client -- nslookup dns-web || true
期待される出力(失敗例):
** server can't find dns-web...
次に、完全修飾ドメイン名(FQDN)で解決します。完全なパターンは <service>.<namespace>.svc.cluster.local です。
kubectl exec --namespace ckad-prep-dns-client remote-client -- nslookup dns-web.ckad-prep-dns.svc.cluster.local
期待される出力:
Name: dns-web.ckad-prep-dns.svc.cluster.local
Address 1: ...
HTTP アクセスにも同じ FQDN を使用します:
kubectl exec --namespace ckad-prep-dns-client remote-client -- wget -qO- http://dns-web.ckad-prep-dns.svc.cluster.local | grep '<title>Welcome to nginx'
期待される出力:
<title>Welcome to nginx!</title>
DNS トラブルシューティングの経路を確認する
このステップでは、DNS の命名問題と Service やバックエンドの問題を切り分けるために役立つオブジェクトを調査します。実用的なトラブルシューティングの順序は、「Service 名と名前空間の確認」→「エンドポイントの存在確認」→「CoreDNS の可用性確認」です。
まず、実際の名前空間にある Service を確認します:
kubectl get service dns-web --namespace ckad-prep-dns
期待される出力:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dns-web ClusterIP ... <none> 80/TCP ...
次に、EndpointSlice を確認します。DNS は解決できるのに HTTP トラフィックが失敗する場合、エンドポイントの欠落が一般的な原因です。
kubectl get endpointslice --namespace ckad-prep-dns -l kubernetes.io/service-name=dns-web
期待される出力(少なくとも 1 つのエンドポイントが表示されます):
NAME ADDRESSTYPE PORTS ENDPOINTS AGE
dns-web-... IPv4 80 ... ...
CoreDNS Pod を確認します。CoreDNS は Pod からの DNS クエリに応答するクラスター DNS サービスです。
kubectl get pods --namespace kube-system -l k8s-app=kube-dns
期待される出力(CoreDNS Pod が Running であること):
NAME READY STATUS RESTARTS AGE
coredns-... 1/1 Running ... ...
最後に、リモートクライアントの DNS 検索設定を確認します。search 行は、フルネームを使用する前にショートネーム dns-web がクライアントの名前空間で検索された理由を説明しています。
kubectl exec --namespace ckad-prep-dns-client remote-client -- cat /etc/resolv.conf
期待される出力(検索パスの例):
search ckad-prep-dns-client.svc.cluster.local svc.cluster.local cluster.local
nameserver ...
まとめ
この実験では、初心者向けのステップを通じて Kubernetes Service の DNS アクセス診断を実践しました。Service を作成し、同一名前空間のクライアントがショートネームを使用できることを確認し、名前空間を跨ぐショートネームの失敗を再現し、完全な Service DNS 名で解決しました。また、Service、EndpointSlice、CoreDNS Pod、およびクライアントの DNS 検索パスを調査することで、DNS アクセスの問題がどこから発生するのかを理解しました。


