なぜ Service 名で通信できるのか

v1.37 時点(2026年10月26日 確認)

Kubernetes 基本仕様第23回 / 全45回 ・ 第4部 ネットワーク
目次

この記事ではクラスタの中で Service の名前を IP アドレスに変える クラスタ DNS の仕組みを、図で説明します。第21回では Service の cluster IP を控えて接続しましたが、実際には my-nginx のような Service の名前だけで接続できます。その裏で CoreDNS と kubelet がそれぞれ何をしているのかがわかります。Pod の /etc/resolv.conf に書かれる search と ndots の意味と、ほかの Namespace の Service を名前で指す書き方もわかります。後半では kind のクラスタで、Service の名前を引いて確かめる手順を示します。

Service と cluster IP を扱った第21回の内容を前提にしています。まだの方は先にこちらをどうぞ。

基本仕様 ・ 第21回 Service を動かして理解するPod の集まりに変わらない入り口を与える Service の仕組みを図で説明します。ラベルセレクタで Pod を選ぶこと、cluster IP、転送先の一覧を持つ EndpointSlice、ノードで通信を Pod へ届ける kube-proxy を押さえ、kind のクラスタで Pod を増減させたときに転送先が自動で変わる様子を確かめる手順を紹介します。

以下の図は、後半の「手元で試す」で client の Pod が Service my-nginx に名前で接続するときの流れを表しています。

Pod が Service の名前を cluster IP に変えてから接続するまでの流れ

client の中のプログラムが my-nginx という名前を使うと、まず名前を IP アドレスに変える問い合わせが、クラスタ DNS の CoreDNS に送られます。プログラムが書くのは my-nginx だけですが、問い合わせの時点では、Pod の設定(後で説明する /etc/resolv.conf の search)に従って、my-nginx.default.svc.cluster.local という省略の無い名前に補われると考えられます。図の 1 に添えた長い名前はこれです。問い合わせの宛先は kube-system の Namespace にある kube-dns という Service の cluster IP です。CoreDNS は my-nginx の cluster IP を答え、client はその cluster IP に接続します。cluster IP に届いた通信が Pod へ振り向けられる仕組みは、第21回で見たとおりです。

参考:DNS for Services and Pods | Kubernetes、Customizing DNS Service | Kubernetes、Service | Kubernetes

図の 2 の矢印は、kube-dns の Service の cluster IP に送った問い合わせが CoreDNS の Pod に届くことを表しています。kube-dns も第21回の my-nginx と同じ ClusterIP の Service なので、kind のように kube-proxy を使うクラスタでは、同じ仕組みで CoreDNS の Pod に届くと考えられます(この段の説明は、確かめた範囲の公式ドキュメントにはありません)。図は答えの通り道を簡単にして描いています。図の実線は問い合わせや通信、破線は応答を表します。

参考:Debugging DNS Resolution | Kubernetes、Virtual IPs and Service Proxies | Kubernetes

クラスタ DNS とは

DNS は名前を問い合わせると IP アドレスなどを答える仕組みです(第14回)。名前から IP アドレスを調べることを、名前解決と呼びます。DNS for Services and Pods のページによると、Kubernetes は Service と Pod の DNS のレコード(名前と IP アドレスなどの対応)を作ります。そのため、IP アドレスの代わりに、一貫した(決まった形の)DNS の名前で Service に接続できます。

参考:DNS for Services and Pods | Kubernetes

この回の主題のクラスタ DNS は Kubernetes の Service の DNS のレコードを答える DNS サーバー です。第4回で見たクラスタのアドオン(クラスタの機能を足すもの)の 1 つです。公式ドキュメントはクラスタに DNS のサービスをアドオンで用意できるとし、ほぼいつも用意すべき(almost always should)だとしています。

参考:Service | Kubernetes、Cluster Architecture | Kubernetes

公式ドキュメントは名前で Service を引けるようになるまでの役割分担を次のように説明しています。Kubernetes は Pod と Service の情報を公開し、その情報が DNS の設定に使われます。kubelet は Pod の DNS を設定し、動いているコンテナが IP アドレスではなく名前で Service を引けるようにします。既定では、Pod が名前を引くときに補うドメインの一覧(search list。後で説明します)に、その Pod 自身の Namespace とクラスタの既定のドメインが入ります。

参考:DNS for Services and Pods | Kubernetes

この回に出てくる主な言葉を、公式ドキュメントでの意味に沿って次の表にまとめます。

言葉指すもの
クラスタ DNSService の DNS のレコードを答える、クラスタの中の DNS サーバー(第4回)
CoreDNSクラスタ DNS として使える、汎用の DNS サーバー。kind が使う kubeadm が入れる
kube-dns の ServiceCoreDNS の Service。kube-system の Namespace にある
/etc/resolv.confPod の中にある、名前解決の設定のファイル。kubelet が Pod ごとに用意する
クラスタのドメインクラスタの DNS の名前の末尾に付くドメイン。設定を変えていなければ cluster.local
dnsPolicyPod の DNS の方針を決める、Pod の spec のフィールド。既定は ClusterFirst

参考:Customizing DNS Service | Kubernetes、Implementation details | Kubernetes、Configuration | kind、DNS for Services and Pods | Kubernetes、StatefulSets | Kubernetes、DNS for Services and Pods | Kubernetes

なぜクラスタ DNS が必要なのか

第21回で見たとおり、Service の cluster IP は Service がある間は変わりません。それでも IP アドレスのままでは、Service を作るたびに割り当てられた値を調べて、接続する側に設定する必要が出てくると考えられます。第21回の手順でも、kubectl get svc で cluster IP を控えてから wget に渡しました。

参考:Connecting Applications with Services | Kubernetes

公式ドキュメントによると、クラスタの中のクライアントが Service を見つける主な方法は、環境変数と DNS の 2 つです。第21回で触れた環境変数の方法では、kubelet が Pod を動かすときに、動いている Service ごとの環境変数を Pod に入れます。そのため、環境変数を使うなら、Service をクライアントの Pod より先に作る必要があります。先に作った Pod には、あとから作った Service の環境変数が入らないからです。公式ドキュメントは DNS だけで Service の cluster IP を見つけるなら、この順番を気にしなくてよいと説明しています。

参考:Service | Kubernetes、Service | Kubernetes

公式のチュートリアルも環境変数の順番の問題を実際に見せています。Service より先に作った nginx の Pod の環境変数には、その Service の変数がありません。一方 DNS では、CoreDNS が名前を割り当てた Service に、クラスタのどの Pod からでも標準的な方法で接続できる、とチュートリアルは説明しています。

参考:Connecting Applications with Services | Kubernetes、Connecting Applications with Services | Kubernetes

名前に Namespace が入ることにも意味があります。Namespace は 1 つのクラスタの中でリソースをグループに分ける仕組みです(第3回。仕組みは第37回)。公式ドキュメントによると、Service の名前だけを使うコンテナは、自分と同じ Namespace の Service につながります。そのため、開発用・検証用・本番用のように Namespace を分けても、同じ設定をそのまま使えます。

参考:Namespaces | Kubernetes

クラスタ DNS の仕組み

CoreDNS と kube-dns の Service

公式ドキュメントは CoreDNS を、クラスタ DNS として使える汎用の DNS サーバーと説明しています。CoreDNS は Kubernetes の DNS の仕様に沿っています。kind はノードを kubeadm で設定し(第4回)、kubeadm は API サーバーを通してクラスタ DNS(CoreDNS)を入れます。第4回で触れたとおり、kind のクラスタの CoreDNS は、kube-system の Namespace の Deployment coredns として動いているはずです。

参考:Customizing DNS Service | Kubernetes、Implementation details | Kubernetes、Configuration | kind

CoreDNS の Service の名前は、coredns ではなく kube-dns です。公式ドキュメントによると、CoreDNS より前に使われていた kube-dns という DNS サーバーの Service の名前に頼ってきたアプリケーションと、互換を保つためです。kube-dns という共通の名前の Service を使うことで、裏でどの DNS サーバーが動いているかという実装の違いを隠せます。CoreDNS の Pod に付く k8s-app のラベルの値も、同じ理由で kube-dns です。

参考:Customizing DNS Service | Kubernetes、Debugging DNS Resolution | Kubernetes

CoreDNS を Deployment で動かしている場合、ふつうは固定の IP アドレスを持つ Service として公開されます。kubeadm で作ったクラスタ(kind も含む)では、kubelet の設定に、この DNS の Service の IP アドレス(clusterDNS)とクラスタのドメイン(clusterDomain)が書かれています。kubelet はそれをもとに、dnsPolicy が ClusterFirst の Pod の名前解決を設定します。同じ値は kubelet のフラグ(--cluster-dns、--cluster-domain)でも渡せますが、v1.37 時点ではどちらのフラグも非推奨(DEPRECATED)で、設定ファイルで指定するよう案内されています。

参考:Customizing DNS Service | Kubernetes、Kubelet Configuration (v1beta1) | Kubernetes、kubelet | Kubernetes

kubeadm の公式ドキュメントによると、kubelet が使う DNS のアドレス(clusterDNS)は、クラスタのすべての kubelet で同じにする必要があります。kubeadm は kubeadm init のときに kubelet の設定をノードの /var/lib/kubelet/config.yaml に書き出し、kube-system の ConfigMap kubelet-config にも保存します。kube-dns の Service の IP アドレスと kubelet の clusterDNS が前もって同じ値にそろうのは、kubeadm が両方を用意するからだと考えられます。ただし、その値の決め方は、確かめた範囲の公式ドキュメントには書かれていません。

参考:Configuring each kubelet in your cluster using kubeadm | Kubernetes、Configuring each kubelet in your cluster using kubeadm | Kubernetes

CoreDNS はどうやって Service の名前と cluster IP の対応を知るのでしょうか。公式ドキュメントによると、CoreDNS のようにクラスタを理解する DNS サーバーは、Kubernetes の API を監視して新しい Service を見つけ、Service ごとに DNS のレコードを作ります。CoreDNS が Service の名前を正しく答えるには、Service と EndpointSlice(第21回)を一覧できる権限が要ります。権限の仕組みは第38回で扱います。

参考:Service | Kubernetes、Debugging DNS Resolution | Kubernetes

以下の図は、Pod が名前を引けるようにするために、kubelet と CoreDNS がそれぞれ何をしているかを表しています。

Pod の /etc/resolv.conf を用意する kubelet と、Service を監視して DNS のレコードを作る CoreDNS

kubelet は Pod ごとに /etc/resolv.conf を用意し、問い合わせ先(nameserver)に kube-dns の cluster IP を書きます(「Pod の /etc/resolv.conf」で説明します)。CoreDNS は kube-apiserver を通して Kubernetes の API を監視し、Service の名前に答えられるようにしています。CoreDNS には、Service などを一覧し、変化を見張る権限が与えられています(第38回)。図では省きましたが、第4回で見たとおり kubelet も kube-apiserver から Pod の情報を受け取っています。点線は監視、破線は用意する(管理する)関係を表します。

参考:DNS for Services and Pods | Kubernetes、Debugging DNS Resolution | Kubernetes、Service | Kubernetes、Debugging DNS Resolution | Kubernetes

CoreDNS の設定は Corefile という設定ファイルに書き、kube-system の ConfigMap coredns に入れます(ConfigMap は第17回)。次の表やこのあとの説明に出てくる A レコードは IPv4 のアドレスを答えるレコード、AAAA レコードは IPv6 のアドレスを答えるレコードです。

参考:Service | Kubernetes

公式ドキュメントが既定として示す Corefile のうち、この回に関わる設定を次の表にまとめます。

Corefile の行公式ドキュメントの説明
kubernetes cluster.local in-addr.arpa ip6.arpaService と Pod の IP アドレスをもとに、DNS の問い合わせに答える
forward . /etc/resolv.confクラスタのドメインに入らない名前の問い合わせを、あらかじめ決めた DNS サーバー(/etc/resolv.conf に書かれたもの)に転送する
cache 30答えを手元に覚えておく(キャッシュする)機能を有効にする
loadbalance答えの中の A レコードなどの順番を無作為に並べ替える

参考:Customizing DNS Service | Kubernetes

forward の行の /etc/resolv.conf は、CoreDNS が動いているコンテナの中のファイルを指すと考えられます。後の「Pod の /etc/resolv.conf」で見る、ほかの Pod の /etc/resolv.conf とは別のものです。Corefile は、管理者が ConfigMap を書き換えて変えられます。公式ドキュメントは書き換えたあと反映されるまで 2 分ほど待つよう案内しています。

参考:Customizing DNS Service | Kubernetes

Service に付く DNS の名前

公式ドキュメントによると、DNS のレコードが作られるオブジェクトは Service と Pod です。ふつうの(headless ではない)Service には、my-svc.my-namespace.svc.cluster-domain.example の形の名前で、A レコードか AAAA レコード(またはその両方)が作られます。どちらになるかは Service の IP アドレスの種類(IPv4 か IPv6 か)によります。名前の形の my-svc、my-namespace、cluster-domain.example は、それぞれ Service の名前、Namespace、クラスタのドメインを表す例の値で、<Service の名前>.<Namespace>.svc.<クラスタのドメイン> の形と読めます。この名前を引くと、Service の cluster IP が返ります。

参考:DNS for Services and Pods | Kubernetes

default の Namespace にある Service my-nginx の名前を、この形に沿って分けると次のようになります。クラスタのドメインは設定を変えていないときの cluster.local とします。第14回の StatefulSet の Pod の名前(web-0.nginx.default.svc.cluster.local)は、この形の Service の名前の前に Pod の名前を付けたものでした。

部分意味
my-nginxService の名前
defaultService がある Namespace
svc形の中で決まっている部分
cluster.localクラスタのドメイン。公式ドキュメントによると、ほかの値に設定していなければ cluster.local

参考:DNS for Services and Pods | Kubernetes、StatefulSets | Kubernetes

このように最後まで省かずに書いた名前を、完全修飾ドメイン名(Fully Qualified Domain Name。以下、FQDN)と呼びます。Namespace の名前が DNS の名前の一部になるため、公式ドキュメントによると、Namespace の名前はすべて RFC 1123 の DNS のラベル(英小文字、数字、- で作る短い名前)の形でなければなりません。

参考:Namespaces | Kubernetes、Object Names and IDs | Kubernetes

Service の種類や形によって、DNS が答えるものが変わります。公式ドキュメントの説明を次の表にまとめます。

対象DNS が答えるもの
ふつうの ServiceService の cluster IP(A / AAAA レコード)
headless Service(clusterIP: None)Service が選んだすべての Pod の IP アドレスの組。クライアントはその組を使うか、順番に 1 つずつ選ぶことが想定されている(第14回)
Service の名前の付いたポートふつうの Service では、ポートの番号と Service の名前(SRV レコード。名前は _<ポートの名前>._<プロトコル>.<Service の名前>.<Namespace>.svc.<クラスタのドメイン> の形)。headless Service では、Pod ごとの答えが返る
type: ExternalName の ServiceexternalName に書いた名前(CNAME レコード。名前を別の名前に対応付けるレコード)。振り向けはプロキシではなく DNS の段で行われる

参考:DNS for Services and Pods | Kubernetes、DNS for Services and Pods | Kubernetes、Service | Kubernetes、Service | Kubernetes

Pod にも DNS の名前が付くことがあります。公式ドキュメントによると、Pod の spec.hostname と spec.subdomain を書き、subdomain と同じ名前の headless Service が同じ Namespace にあれば、クラスタの DNS サーバーは Pod の FQDN にも A / AAAA レコードを答えます。ただし、レコードができるには Pod が Ready である必要があります(Service に publishNotReadyAddresses を true で設定している場合を除く)。第14回の StatefulSet の Pod が web-0.nginx.default.svc.cluster.local のような名前を持てたのは、この仕組みによると考えられます。公式ドキュメントは、ここで説明した以外の名前の形がたまたま使えても、それは実装の細部で、予告なく変わることがあると注意しています。

参考:DNS for Services and Pods | Kubernetes、DNS for Services and Pods | Kubernetes

Pod の /etc/resolv.conf

Pod の中のプログラムは my-nginx のような短い名前を、どうやって FQDN に直すのでしょうか。その手がかりが Pod の中の /etc/resolv.conf です。公式ドキュメントによると、kubelet が Pod ごとにこのファイルを設定します。公式ドキュメントにある例は次のとおりです。

nameserver 10.32.0.10
search <namespace>.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

参考:DNS for Services and Pods | Kubernetes

<namespace> には、その Pod がある Namespace の名前が入ります。3 つの行の意味を、Linux の resolv.conf のマニュアル(公式ドキュメントが案内しているもの)に沿って次の表にまとめます。名前解決を受け持つプログラムの部品を、マニュアルはリゾルバ(resolver)と呼んでいます。

行マニュアルの説明Pod での中身
nameserverリゾルバが問い合わせる DNS サーバーの IP アドレスkube-dns の Service の cluster IP(次の段落)
search名前を引くときに、後ろに順に付けて試すドメインの一覧Pod の Namespace の <namespace>.svc.cluster.local、svc.cluster.local、cluster.local
options ndots:n名前の中のドットの数がこれより少なければ、そのままの名前より先に search のドメインを付けて試す、というしきい値ndots:5

参考:resolv.conf(5) - Linux manual page、DNS for Services and Pods | Kubernetes、Debugging DNS Resolution | Kubernetes、Debugging DNS Resolution | Kubernetes

表の nameserver の行の「Pod での中身」は DNS のトラブルを調べる公式ドキュメントの例を見比べたものです。そのページでは、Pod の /etc/resolv.conf の nameserver も kube-dns の Service の CLUSTER-IP も、同じ 10.0.0.10 になっています。kubelet が設定の clusterDNS(DNS の Service の IP アドレス)をコンテナの DNS サーバーとして使う、という説明とも合います。

参考:Debugging DNS Resolution | Kubernetes、Customizing DNS Service | Kubernetes、Kubelet Configuration (v1beta1) | Kubernetes

公式ドキュメントによると、search の値は問い合わせの名前を補うのに使われます。たとえば test の Namespace の Pod が data だけを引くと、data.test.svc.cluster.local に補われることがあります。マニュアルの説明に当てはめると、ndots:5 の Pod では、ドットが 4 つ以下の名前は、まず search のドメインを順に付けて問い合わせられる、と読めます。default の Namespace の Pod の場合、短い名前がどう補われるかを、この読み方に沿って次の表に示します。

引く名前search のドメインを付けて試す名前(順に)my-nginx の Service の FQDN と一致する名前
my-nginxmy-nginx.default.svc.cluster.local1 つ目
my-nginx.defaultmy-nginx.default.default.svc.cluster.local、my-nginx.default.svc.cluster.local2 つ目

参考:DNS for Services and Pods | Kubernetes、resolv.conf(5) - Linux manual page

どちらの名前も search のどれかのドメインを付けた段で my-nginx の Service の FQDN になり、cluster IP が返ると考えられます。マニュアルによると、一致する答えが見つかるまで search のドメインを順に試すので、FQDN になった段より後ろのドメインは試されないはずです。ただし、実際にどう補うかはコンテナの中のプログラムが使うリゾルバによって細かく違うことがあると考えられます。

参考:resolv.conf(5) - Linux manual page

名前の末尾にドット(.)を付けた場合と、FQDN をそのまま書いた場合も、マニュアルに沿って整理しておきます。Linux の hostname(7) のマニュアルによると、末尾にドットが付いた名前は、そのドットを除いたうえで、それ以上手を加えずに引かれます。つまり、search のドメインは付きません。一方、末尾にドットを付けない my-nginx.default.svc.cluster.local はドットが 4 つで、ndots:5 より少なくなります。そのため、マニュアルに当てはめると、先に search のドメインを付けた名前(my-nginx.default.svc.cluster.local.default.svc.cluster.local など)が試されると読めます。ndots は「最初に」そのままの名前で引くかどうかのしきい値と説明されていますが、search を付けた名前で見つからなかったときに、そのままの名前で引き直すかどうかはマニュアルには書かれていません。手元で my-nginx.default.svc.cluster.local を引いて cluster IP が返れば、どこかの段でこの名前に一致したことになります。

参考:hostname(7) - Linux manual page、resolv.conf(5) - Linux manual page

search の一覧の後ろには、ノードの search のドメインが続くことがあります。kubelet の設定の説明によると、クラスタのドメインを設定した kubelet は、ノード(ホスト)の search のドメインに加えて、クラスタのドメインも search に入れるよう、すべてのコンテナを設定します。公式ドキュメントの例でも、search の行の後ろに、クラウドの事業者によって違うことがあるドメインが並んでいます。

参考:Kubelet Configuration (v1beta1) | Kubernetes、Debugging DNS Resolution | Kubernetes

/etc/resolv.conf をどう作るかは Pod の spec.dnsPolicy で決まります。v1.37 時点の公式ドキュメントにある 4 つの値を、次の表にまとめます。

dnsPolicy公式ドキュメントの説明
ClusterFirstdnsPolicy を書かないときの既定。クラスタのドメインに合わない名前(www.kubernetes.io など)の問い合わせは、DNS サーバーが上流の DNS サーバーに転送する
DefaultPod が動くノードの名前解決の設定を引き継ぐ。名前に反して既定ではない
ClusterFirstWithHostNetノードのネットワークをそのまま使う(hostNetwork)Pod に、明示して設定すべき(should)値。hostNetwork の Pod が ClusterFirst のままだと、Default と同じ動きになる
NoneKubernetes の DNS の設定を使わない。設定はすべて spec.dnsConfig で渡す

参考:DNS for Services and Pods | Kubernetes

表の「上流の DNS サーバー」はクラスタの外の名前を答える、上位の DNS サーバーのことです。Corefile の forward の行で転送先にした「あらかじめ決めた DNS サーバー」にあたると考えられます。

参考:Customizing DNS Service | Kubernetes

この回の手順の Pod には dnsPolicy を書かないので、ClusterFirst になります。spec.dnsConfig では、nameservers(DNS サーバー)、searches(search のドメイン)、options(ndots など)を足せます。足した値は dnsPolicy から作られた設定にまとめられ、重なったものは除かれます。

参考:DNS for Services and Pods | Kubernetes

名前を引いてから接続するまで

ここまでの仕組みを、冒頭の図の順にまとめます。default の Namespace の client の Pod が http://my-nginx:80/ に接続する場合です。

順番起きること
1client の中のリゾルバが /etc/resolv.conf を読み、my-nginx を search のドメインで補って、nameserver の kube-dns の cluster IP に問い合わせる
2問い合わせが CoreDNS の Pod に届く(kube-proxy を使うクラスタでは、kube-proxy の規則による、と考えられる)
3CoreDNS が、監視している Service の情報をもとに、my-nginx の cluster IP を答える
4client が答えの cluster IP に接続し、kube-proxy を使うクラスタでは、kube-proxy の規則で my-nginx の Pod に届く(第21回)

参考:DNS for Services and Pods | Kubernetes、Service | Kubernetes、Virtual IPs and Service Proxies | Kubernetes

DNS が答えるのは cluster IP までです。DNS は Pod の IP アドレスを直接答えるわけではなく、Pod への振り分けは第21回の仕組みが受け持ちます(headless Service は例外で、Pod の IP アドレスの組を答えます)。Pod が入れ替わっても cluster IP は変わらないので、DNS の答えも変わらないはずです。ここまでで、タイトルの問いに答えられます。Service の名前で通信できるのは、kubelet が Pod の名前解決の行き先を CoreDNS にしておき、CoreDNS が Service の名前を cluster IP に変えて答えるから です。

参考:DNS for Services and Pods | Kubernetes、DNS for Services and Pods | Kubernetes、Connecting Applications with Services | Kubernetes

Namespace をまたいで名前を引く

公式ドキュメントによると、DNS の問い合わせの結果は、問い合わせる Pod の Namespace によって変わることがあります。Namespace を書かない問い合わせは、その Pod の Namespace の中に限られます。ほかの Namespace の Service に届けるには、問い合わせの名前に Namespace を書きます。

参考:DNS for Services and Pods | Kubernetes

公式ドキュメントの例では、test の Namespace の Pod と、prod の Namespace の Service data があります。data だけを引くと、Pod の Namespace の test を使うので、何も返りません。data.prod を引くと、Namespace を指定しているので、目的の結果が返ります。まとめると、test の Pod は data.prod でも data.prod.svc.cluster.local でも名前を引けます。

参考:DNS for Services and Pods | Kubernetes

以下の図は、後半の手順で使う dnsutils の Pod から見て、2 つの Namespace の Service をそれぞれどんな名前で引けるかを表しています。

dnsutils の Pod から見た、同じ Namespace とほかの Namespace の Service の名前

dnsutils と同じ default の Namespace の my-nginx は、Service の名前だけで引けます。kube-system の kube-dns は、kube-dns だけでは dnsutils の Namespace の中を探すことになるので引けず、kube-dns.kube-system のように Namespace を付けて引きます。

公式ドキュメントの書き方を、次の表にまとめます。

引く Pod から見た Service書き方例(Pod が default)
同じ Namespace の Service<Service の名前>my-nginx
ほかの Namespace の Service<Service の名前>.<Namespace>kube-dns.kube-system
どの Namespace の Service でも<Service の名前>.<Namespace>.svc.<クラスタのドメイン>(FQDN)kube-dns.kube-system.svc.cluster.local

参考:Service | Kubernetes、DNS for Services and Pods | Kubernetes

Service のページは、ほかの Namespace の Pod は名前を my-service.my-ns の形(<Service の名前>.<Namespace>)にしなければならない(must)としています。DNS のトラブルを調べるページも、Pod と Service の Namespace が違うなら、DNS の問い合わせに Service の Namespace を含めなければならない(must)と書いています。Namespace のページは、Namespace をまたいで届けたいなら FQDN を使う必要があると書いています。search に svc.cluster.local が入っているので、<Service の名前>.<Namespace> はそれを付けた段で FQDN になる、と読めます。一般には、同じ Namespace の Service は短い名前で、ほかの Namespace の Service は少なくとも <Service の名前>.<Namespace> まで書く、と覚えておけばよいと考えられます。

参考:Service | Kubernetes、Debugging DNS Resolution | Kubernetes、Namespaces | Kubernetes、DNS for Services and Pods | Kubernetes

手元で試す

ここまでの内容を、手元の kind のクラスタで試す手順を示します。まず CoreDNS の Pod と kube-dns の Service を確かめます。次に第21回と同じ Deployment と Service を作り、DNS を調べる Pod の /etc/resolv.conf を見ます。そのあと Service の名前を引き、Namespace をまたいで名前を引き、最後に Service の名前で nginx に接続します。

この節で引用する出力の例は、公式ドキュメントにある、ほかのクラスタのものです。表示の形を見るためのもので、名前や IP アドレスなどの値は手元とは違います。各段の最後には成功かどうかを見分ける点を短く挙げます。どれも公式ドキュメントから予想される結果で、手元で実行して確かめたものではありません。

コマンドは macOS や Linux のシェル(bash や zsh)で実行する前提で書いています。Windows では WSL(Windows の中で Linux を動かす仕組み)などを使ってください。試す環境は次のとおりです。

項目内容
kindv0.33.0
Kubernetesv1.37.0(kind v0.33.0 の既定のノードイメージ)
ノード構成マルチノード(クラスタ名 multi-node):コントロールプレーン 1、ワーカー 2
必要なものDocker、kubectl(v1.36〜v1.38)、テキストエディタ、端末(ターミナル)2 つ

参考:Release v0.33.0 · kubernetes-sigs/kind、Version Skew Policy | Kubernetes

kind でクラスタを作る手順は、以下の記事で解説しています。この回は第21回の手順とそろえるため、第20回・第21回と同じマルチノードのクラスタを使います。

基本仕様 ・ 第2回 kind で検証用のクラスタを作るDocker のコンテナをノードにして、手元のマシンに Kubernetes のクラスタを作るツール kind の仕組みを図で説明します。kind create cluster で何が起きるかを押さえ、シングルノードとマルチノードのクラスタを作って、ノードの正体が Docker のコンテナであることを確かめる手順を紹介します。

マルチノードのクラスタを用意する

第2回と同じ次の設定ファイルを使います。公式ドキュメントの例をそのまま引用しています。kind-multi-node.yaml という名前で、コマンドを実行するディレクトリに保存します。第21回までに保存したファイルが残っていれば、それを使えます。

yaml
# three node (two workers) cluster config
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker

参考:Quick Start | kind

まず、前の回のクラスタが残っていないかを確かめます。

console
$ kind get clusters

multi-node が表示されたら、作り直さずにそのまま使えるので、クラスタを作る次のコマンドは飛ばします。表示されなければ、クラスタを作ってから、もう一度一覧します。

console
$ kind create cluster --name multi-node --config kind-multi-node.yaml
$ kind get clusters

kind get clusters に multi-node が表示されれば、クラスタができています。第3回で決めたとおり、ここからのコマンドには --context kind-multi-node を付けて、操作するクラスタをはっきりさせます。

参考:Quick Start | kind

続けて、ノードを一覧します。

console
$ kubectl get nodes --context kind-multi-node

ノードが 3 つ表示され、STATUS 列が Ready になっていれば準備ができています。Ready になっていなければ、少し待ってからもう一度実行します。

参考:kubectl get | Kubernetes、Node Status | Kubernetes

前の回のクラスタを使い続けている場合は、この回で作るものと同じ名前のものが無いことを確かめます。第21回で見たとおり、my-nginx の Deployment 自身には run: my-nginx のラベルが無いので、Deployment と Service は名前を、Pod は名前とラベルを手がかりに調べます。

console
$ kubectl get deployments,services --context kind-multi-node
$ kubectl get pods --context kind-multi-node

1 つ目のコマンドの一覧に my-nginx が無く、2 つ目のコマンドの一覧に client、dnsutils、my-nginx- で始まる名前の Pod が無ければ、そのまま進めます。1 つ目のコマンドでは、kubernetes という Service が表示されると考えられます(第21回の片付けで説明しました)。残っていたら、次のコマンドで消してから進みます。--ignore-not-found は、消す相手が無くてもエラーにしない指定です。

console
$ kubectl delete deployment my-nginx --ignore-not-found --context kind-multi-node
$ kubectl delete service my-nginx --ignore-not-found --context kind-multi-node
$ kubectl delete pod client dnsutils --ignore-not-found --context kind-multi-node

Deployment を消すと、その Pod も消えます(第6回)。それでも run: my-nginx の Pod が残っていたら、kubectl delete pod -l run=my-nginx --context kind-multi-node で消します。

参考:kubectl get | Kubernetes、kubectl delete | Kubernetes、Connecting Applications with Services | Kubernetes

CoreDNS の Pod と kube-dns の Service を確かめる

kube-system の Namespace で、k8s-app=kube-dns のラベルを持つ Pod を、IP アドレスとノードの列つきで一覧します。前に書いたとおり、公式ドキュメントによると、CoreDNS の Pod の k8s-app のラベルの値は kube-dns です。-n kube-system は第4回と同じく、Namespace を指定する書き方です。

console
$ kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide --context kind-multi-node

参考:Debugging DNS Resolution | Kubernetes

公式ドキュメントの例(-o wide を付けないもの)では、出力は次のとおりです。... の行も原文のままです。

NAME                       READY     STATUS    RESTARTS   AGE
...
coredns-7b96bf9f76-5hsxb   1/1       Running   0           1h
coredns-7b96bf9f76-mvmmt   1/1       Running   0           1h
...

参考:Debugging DNS Resolution | Kubernetes

手元では、coredns- で始まる名前の Pod が並び、名前の後ろの文字列は例と違うはずです。例の ... は省略を表す印と考えられます。-o wide を付けたので、IP 列や NODE 列も加わると考えられます(第8回)。第4回では、v1.37 時点の kubeadm のソースコードから、CoreDNS の Pod の数の既定値を 2 と読み取りました。そのとおりなら、2 行表示されるはずです。STATUS 列が Running になっていることを確かめ、IP 列の IP アドレスを控えておきます。

参考:kubeadm のソースコード(CoreDNS)

続けて、kube-dns の Service を表示します。

console
$ kubectl get services kube-dns -n kube-system --context kind-multi-node

公式のチュートリアルの例では、出力は次のとおりです。

NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kube-dns   ClusterIP   10.0.0.10    <none>        53/UDP,53/TCP   8m

参考:Connecting Applications with Services | Kubernetes

TYPE 列は ClusterIP のはずです。PORT(S) 列には、UDP と TCP の 53 番のポートが並ぶはずです。53 番は一般に DNS が使うポートです。例に無いポートが加わって表示されることもあると考えられます。CLUSTER-IP 列の値は例とは違い、kind(v0.33.0 時点)の既定の Service の範囲 10.96.0.0/16 に入るはずです。この値を <kube-dns の CLUSTER-IP> として控えておきます。

参考:Configuration | kind、Debugging DNS Resolution | Kubernetes

kube-dns の Service の転送先も第21回と同じように EndpointSlice で確かめます。

console
$ kubectl get endpointslices -n kube-system -l kubernetes.io/service-name=kube-dns --context kind-multi-node

参考:Debugging DNS Resolution | Kubernetes

ENDPOINTS 列には、控えた CoreDNS の Pod の IP アドレスが並ぶと考えられます。kube-dns の Service の転送先が CoreDNS の Pod だということが、ここから読み取れます。

最後に、CoreDNS の設定(Corefile)が入った ConfigMap を表示します。

console
$ kubectl get configmap coredns -n kube-system -o yaml --context kind-multi-node

参考:Debugging DNS Resolution | Kubernetes

data の Corefile に、「CoreDNS と kube-dns の Service」で見た既定の Corefile に近い内容が表示されると考えられます。kubernetes cluster.local in-addr.arpa ip6.arpa の行に、クラスタのドメインの cluster.local が入っているかを見てください。細かい行は公式ドキュメントの例と違うことがあると考えられます。

この段では、次の 3 点が合っていれば成功です。

  • coredns- で始まる名前の Pod が並び、STATUS 列が Running
  • kube-dns の Service の TYPE 列が ClusterIP で、CLUSTER-IP 列が 10.96. で始まる
  • kube-dns の EndpointSlice の ENDPOINTS 列に、CoreDNS の Pod の IP アドレスが並ぶ

マニフェストを用意する

使うマニフェストは 4 つです。1 つ目から 3 つ目は第21回と同じものです。第21回で保存したファイルが残っていれば、それを使えます。

1 つ目は公式のチュートリアル(Connecting Applications with Services)にある Deployment です(そのまま引用しています)。run-my-nginx.yaml という名前で、コマンドを実行するディレクトリに保存します。

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80

参考:Connecting Applications with Services | Kubernetes

2 つ目は同じチュートリアルにある Service です(そのまま引用しています)。nginx-svc.yaml という名前で保存します。run: my-nginx のラベルを持つ Pod の、TCP の 80 番のポートに通信を送る ClusterIP の Service です(第21回)。

yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx

参考:Connecting Applications with Services | Kubernetes

3 つ目は第20回・第21回と同じ通信元の Pod です。busybox:1.28 のイメージで、何もせずに待ち続けるコンテナを 1 つ動かします。client.yaml という名前で保存します。

yaml
apiVersion: v1
kind: Pod
metadata:
  name: client
spec:
  containers:
  - name: busybox
    image: busybox:1.28
    command: ['sh', '-c', 'sleep 3600']

参考:Pod | Kubernetes API Reference、Using Source IP | Kubernetes

4 つ目は、DNS のトラブルを調べる公式ドキュメントが、名前を引く確かめ用に示している Pod です(そのまま引用しています)。dnsutils.yaml という名前で保存します。名前を引く確かめには client ではなくこの Pod を使います。DNS のトラブルを調べる公式の手順に合わせ、公式ドキュメントの出力例と見比べやすくするためです。

yaml
apiVersion: v1
kind: Pod
metadata:
  name: dnsutils
  namespace: default
spec:
  containers:
  - name: dnsutils
    image: registry.k8s.io/e2e-test-images/agnhost:2.39
    imagePullPolicy: IfNotPresent
  restartPolicy: Always

参考:Debugging DNS Resolution | Kubernetes

公式ドキュメントによると、この Pod は default の Namespace に作られます(metadata.namespace: default)。Service の名前解決は Pod の Namespace によって変わるので、どの Namespace の Pod から引くかが大事になります。公式ドキュメントは、この Pod が動き出したら、中で nslookup(DNS に名前を問い合わせるコマンド)を実行できると説明しています。imagePullPolicy: IfNotPresent は、イメージがノードに無いときだけ取得する方針です。どの Pod にも dnsPolicy を書いていないので、どれも ClusterFirst になります。

参考:Debugging DNS Resolution | Kubernetes、Images | Kubernetes、DNS for Services and Pods | Kubernetes

Pod の監視を始める

ここからは端末を 2 つ使います。第11回・第13回〜第21回と同じく、1 つ目の端末で変化を追い続け、2 つ目の端末でマニフェストを渡したり、Pod の中でコマンドを動かしたりします。この回で 1 つ目の端末が追うのは、default の Namespace の Pod です。2 つ目の端末を開いたら、cd でマニフェストを保存したディレクトリに移動しておきます。

1 つ目の端末で、Pod を監視します。第3回で見たとおり、--watch を付けると、一覧を表示したあとも変化を追い続けます。-o wide で Pod の IP アドレスとノードの列も表示します。この監視は片付けの前まで止めずに続けます。

console
$ kubectl get pods -o wide --watch --context kind-multi-node

参考:kubectl get | Kubernetes

まだ Pod が無いので、何も表示されないか、見つからないことを知らせる 1 行が出たあと、止まったように見えると考えられます。

Deployment、Service、Pod を作る

2 つ目の端末で、4 つのマニフェストを順に渡します。

console
$ kubectl apply -f run-my-nginx.yaml --context kind-multi-node
$ kubectl apply -f nginx-svc.yaml --context kind-multi-node
$ kubectl apply -f client.yaml --context kind-multi-node
$ kubectl apply -f dnsutils.yaml --context kind-multi-node

deployment.apps/my-nginx、service/my-nginx、pod/client、pod/dnsutils が作られたことを知らせる行が出るはずです。1 つ目の端末には、my-nginx- で始まる名前の Pod 2 つと、client、dnsutils の Pod の行が書き足されていくはずです。クラスタを作ったばかりなら、イメージの取得に時間がかかるので、ContainerCreating のまましばらく止まって見えることがあります(第9回)。

参考:kubectl apply | Kubernetes、Debugging DNS Resolution | Kubernetes

1 つ目の端末で 4 つの Pod の STATUS 列が Running になったら、2 つ目の端末で my-nginx の Service を表示します。

console
$ kubectl get svc my-nginx --context kind-multi-node

第21回と同じく、TYPE 列は ClusterIP、PORT(S) 列は 80/TCP のはずです。CLUSTER-IP 列の値を <my-nginx の CLUSTER-IP> として控えておきます。この値はあとで DNS の答えと見比べます。

参考:Connecting Applications with Services | Kubernetes

この段では、次の 2 点が合っていれば成功です。

  • 4 つの kubectl apply がどれも作られたことを知らせる行を出す
  • 1 つ目の端末で、4 つの Pod の STATUS 列が Running になる

Pod の /etc/resolv.conf を見る

2 つ目の端末で、dnsutils の Pod の中の /etc/resolv.conf を表示します。kubectl exec の -- の後ろがコンテナの中で動かすコマンドです(第10回)。cat は一般に、ファイルの中身を表示するコマンドです。公式ドキュメントの例には -ti が付いています。-i は入力(標準入力)をコンテナに渡す指定、-t はその入力を端末(TTY)として扱う指定です。この回では入力を渡さずに表示を見るだけなので、第21回と同じく付けずに実行します。

console
$ kubectl exec dnsutils --context kind-multi-node -- cat /etc/resolv.conf

参考:Debugging DNS Resolution | Kubernetes、kubectl exec | Kubernetes

公式ドキュメントの例では、出力は次のとおりです。

search default.svc.cluster.local svc.cluster.local cluster.local google.internal c.gce_project_id.internal
nameserver 10.0.0.10
options ndots:5

参考:Debugging DNS Resolution | Kubernetes

公式ドキュメントは、search の行がクラウドの事業者によって違うことがあると注意しています。例の google.internal と c.gce_project_id.internal は、その例のクラスタのノードの search のドメインだと考えられます。手元では次のように見えるはずです。

  • search の行が default.svc.cluster.local svc.cluster.local cluster.local で始まる。後ろに、例とは違うドメインが続くことがある
  • nameserver の行の IP アドレスが控えた <kube-dns の CLUSTER-IP> と同じ
  • options の行に ndots:5 がある

行の順番が例と違うことや、例に無い行が加わることもあると考えられます。search の先頭が default で始まるのは、dnsutils が default の Namespace の Pod だからです。

参考:DNS for Services and Pods | Kubernetes、Kubelet Configuration (v1beta1) | Kubernetes

client の Pod の /etc/resolv.conf も同じ中身のはずです。どちらも default の Namespace の Pod で、dnsPolicy は ClusterFirst だからです。

console
$ kubectl exec client --context kind-multi-node -- cat /etc/resolv.conf

この段では、次の 3 点が合っていれば成功です。

  • search の行が default.svc.cluster.local svc.cluster.local cluster.local で始まる
  • nameserver の行が <kube-dns の CLUSTER-IP> と同じ
  • options ndots:5 の行がある

Service の名前を引く

2 つ目の端末で、dnsutils の Pod の中で nslookup を動かします。まず、DNS が動いているかを確かめるために公式ドキュメントが使っている kubernetes.default を引きます。kubernetes は、kube-apiserver のアドレスを公開している default の Namespace の Service です(第21回)。

console
$ kubectl exec dnsutils --context kind-multi-node -- nslookup kubernetes.default

公式ドキュメントは、次のような表示が出れば DNS は正しく動いていると説明しています。

Server:    10.0.0.10
Address 1: 10.0.0.10

Name:      kubernetes.default
Address 1: 10.0.0.1

参考:Debugging DNS Resolution | Kubernetes、Accessing the Kubernetes API from a Pod | Kubernetes

Server は問い合わせた DNS サーバー、Name と Address は引いた名前と、その答えの IP アドレスを表すと考えられます。手元では、Server の IP アドレスが <kube-dns の CLUSTER-IP> になるはずです。Address の IP アドレスは kubernetes の Service の cluster IP のはずなので、kubectl get svc kubernetes --context kind-multi-node の CLUSTER-IP 列と見比べてください。表示の形はコマンドの作りによって例と違うことがあると考えられます。たとえば Address 1: の行が Address: と書かれたり、Name の行に kubernetes.default.svc.cluster.local のように補った FQDN が出たりすることが考えられます。見比べるのは IP アドレスだけで十分です。

続けて、my-nginx の Service を名前だけで引きます。

console
$ kubectl exec dnsutils --context kind-multi-node -- nslookup my-nginx

公式のチュートリアルの例(別の Pod から nslookup my-nginx を実行したもの)では、出力は次のとおりです。

Server:    10.0.0.10
Address 1: 10.0.0.10

Name:      my-nginx
Address 1: 10.0.162.149

参考:Connecting Applications with Services | Kubernetes

チュートリアルの例の 10.0.162.149 は同じチュートリアルの kubectl get svc my-nginx の例の CLUSTER-IP と同じ値です。手元でも、Address の IP アドレスが控えた <my-nginx の CLUSTER-IP> と同じになるはずです。DNS が答えるのは Pod の IP アドレスではなく、Service の cluster IP です。手元では、Name の行が my-nginx.default.svc.cluster.local のように補った名前で表示されることもあると考えられます。ここでも見比べるのは Address の IP アドレスだけで十分です。

参考:Connecting Applications with Services | Kubernetes、DNS for Services and Pods | Kubernetes

同じ Service を、FQDN で引きます。

console
$ kubectl exec dnsutils --context kind-multi-node -- nslookup my-nginx.default.svc.cluster.local

今度も Address の IP アドレスが <my-nginx の CLUSTER-IP> になるはずです。my-nginx だけで引けたのは、search の先頭の default.svc.cluster.local を付けた名前が、この FQDN と同じになるからだと考えられます。FQDN で引いた今回も、末尾にドットが無いので、先に search のドメインを付けた名前が試されると読めます。Address に cluster IP が返れば、どこかの段でこの FQDN に一致したことになります(「Pod の /etc/resolv.conf」を参照)。

参考:DNS for Services and Pods | Kubernetes

この段では、次の 3 点が合っていれば成功です。

  • kubernetes.default の答えの IP アドレスが kubernetes の Service の CLUSTER-IP と同じ
  • my-nginx の答えの IP アドレスが <my-nginx の CLUSTER-IP> と同じ
  • my-nginx.default.svc.cluster.local でも同じ IP アドレスが返る

Namespace をまたいで名前を引く

dnsutils は default の Namespace の Pod です。kube-system の Namespace にある kube-dns の Service を、まず Namespace を付けずに引きます。

console
$ kubectl exec dnsutils --context kind-multi-node -- nslookup kube-dns

公式ドキュメントの test と prod の例と同じく、Namespace を書かない問い合わせは dnsutils の Namespace の default に限られます。default には kube-dns という Service が無いので、名前を引けなかったことを知らせる表示が出るはずです。公式ドキュメントの別の例(DNS がうまく動いていないとき)では、nslookup: can't resolve '<引いた名前>' の形の行が出ています。手元の表示の形はこれと違うことがあると考えられます。この失敗は想定どおりです。名前を引けなかった nslookup は失敗として終わり、kubectl がそのことを知らせる行を続けて出すこともあると考えられます。

参考:DNS for Services and Pods | Kubernetes、Debugging DNS Resolution | Kubernetes

次に、Namespace を付けて引きます。公式ドキュメントが「Namespace が合っているか」の確かめ方として示している、<Service の名前>.<Namespace> の形です。

console
$ kubectl exec dnsutils --context kind-multi-node -- nslookup kube-dns.kube-system

参考:Debugging DNS Resolution | Kubernetes

今度は Address に、控えた <kube-dns の CLUSTER-IP> が表示されるはずです。DNS の問い合わせ先の Server と、引いた答えの Address が同じ IP アドレスになるはずです。DNS サーバー自身の Service の名前を引いたからです。FQDN の kube-dns.kube-system.svc.cluster.local でも同じ答えが返るはずなので、試してみてください。

console
$ kubectl exec dnsutils --context kind-multi-node -- nslookup kube-dns.kube-system.svc.cluster.local

参考:Service | Kubernetes、DNS for Services and Pods | Kubernetes

この段では、次の 3 点が合っていれば成功です。

  • kube-dns だけでは、名前を引けなかったことを知らせる表示が出る
  • kube-dns.kube-system の答えの IP アドレスが <kube-dns の CLUSTER-IP> と同じ
  • kube-dns.kube-system.svc.cluster.local でも同じ IP アドレスが返る

Service の名前で nginx に届ける

最後に、client の Pod の中で wget を動かし、Service の名前で nginx に接続します。第21回では <my-nginx の CLUSTER-IP> を書いた URL を、今度は Service の名前で書きます。-q と -O- は第21回と同じで、一般に、進み具合を表示せず、受け取った内容をそのまま画面に出す指定です。:80 は Service の port です。

console
$ kubectl exec client --context kind-multi-node -- wget -q -O- http://my-nginx:80/

参考:kubectl exec | Kubernetes、Connecting Applications with Services | Kubernetes

第21回と同じく、<h1>Welcome to nginx!</h1> の行を含む、nginx の初期のページの HTML が表示されれば成功です。wget はまず my-nginx の名前を CoreDNS に問い合わせて cluster IP を受け取り、その cluster IP に接続したと考えられます。冒頭の図の 1 から 4 の流れです。cluster IP を調べて控える手間が、名前を引く仕組みで置き換わったことになります。

数秒たっても何も表示されずに止まったままなら、Ctrl+C で止めます。そのうえで、「Service の名前を引く」の段の nslookup my-nginx が IP アドレスを答えるかと、my-nginx の Pod が Running かを見直します。

片付け

1 つ目の端末で Ctrl+C を押して、監視を止めます。

2 つ目の端末で、作った Pod、Service、Deployment を、マニフェストを指定して削除します。

console
$ kubectl delete -f dnsutils.yaml --context kind-multi-node
$ kubectl delete -f client.yaml --context kind-multi-node
$ kubectl delete -f nginx-svc.yaml --context kind-multi-node
$ kubectl delete -f run-my-nginx.yaml --context kind-multi-node

参考:kubectl delete | Kubernetes

Deployment を消すと、その ReplicaSet と Pod も消えます(第6回)。Pod を消すコマンドは Pod の終了までの猶予の時間(既定では 30 秒)のぶん、終わるまで少しかかることがあります(第20回)。CoreDNS の Pod や kube-dns の Service は、この回で作ったものではないので消しません。

参考:Garbage Collection | Kubernetes、Pod Lifecycle | Kubernetes

少し待ってから、残っていないかを確かめます。

console
$ kubectl get deployments,pods --context kind-multi-node
$ kubectl get services --context kind-multi-node

Pod が Terminating で表示されていたら、少し待ってからもう一度実行します。1 つ目のコマンドで、見つからないことを知らせる 1 行が出れば、削除できています。2 つ目のコマンドでは my-nginx は表示されず、前の回の Service が残っていなければ、kubernetes という Service だけが表示されると考えられます(第21回)。

最後に、クラスタを削除し、消えたことを確かめます。

console
$ kind delete cluster --name multi-node
$ kind get clusters

kind delete cluster は、存在しないクラスタを指定してもエラーを返しません。kind get clusters に multi-node が表示されなくなったことを確かめます。kubeconfig に kind-multi-node のコンテキストが残っていたら、第3回の片付けと同じく kubectl config delete-context kind-multi-node で消します。

参考:Quick Start | kind、kubectl config | Kubernetes

注意点

クラスタ DNS でつまずきやすい点と、知っておきたい決まりを、次の表にまとめます。

項目内容
短い名前は、同じ Namespace の Service だけを指すNamespace を書かない問い合わせは、Pod の Namespace の中に限られる。ほかの Namespace の Service は <Service の名前>.<Namespace> か FQDN で引く
DNS が答えるのは cluster IPふつうの Service の名前を引くと cluster IP が返る。Pod への振り分けは kube-proxy などが受け持つ(第21回)。headless Service だけは Pod の IP アドレスの組を返す
CoreDNS の Service の名前は kube-dns前の DNS サーバーの名前に頼るアプリケーションとの互換のため。CoreDNS の Pod の k8s-app のラベルの値も kube-dns
dnsPolicy の Default は既定ではない書かないときの既定は ClusterFirst。Default はノードの名前解決の設定を引き継ぐ
Pod の /etc/resolv.conf の ndots公式ドキュメントの例では ndots:5。resolv.conf のマニュアルでは、ドットがこの数より少ない名前は、先に search のドメインを付けて試すと説明されている
作ったばかりの Pod の DNS の名前は、すぐ引けないことがあるクラスタの DNS の設定によっては、Pod ができる前にその名前を問い合わせたクライアントがいると、失敗した結果が、Pod が動き出したあとも少なくとも数秒は使い回される(第14回)
Namespace の名前は DNS の名前の一部になるNamespace の名前は RFC 1123 の DNS のラベルの形にする。公開のトップレベルドメインと同じ名前の Namespace には注意する
Alpine 3.17 以前のイメージでは DNS が動かないことがあるAlpine の設計上の問題で、musl(Alpine が使うライブラリ)の 1.24 より前の版には DNS の問い合わせを TCP に切り替える仕組みが無く、512 バイトを超える DNS のやり取り(原文は DNS call)が失敗する。公式ドキュメントは、Alpine 3.18 以降に上げるよう勧めている

参考:DNS for Services and Pods | Kubernetes、DNS for Services and Pods | Kubernetes、Customizing DNS Service | Kubernetes、Debugging DNS Resolution | Kubernetes、DNS for Services and Pods | Kubernetes、resolv.conf(5) - Linux manual page、StatefulSets | Kubernetes、Namespaces | Kubernetes、Debugging DNS Resolution | Kubernetes

関連記事

ClusterIP の上に作られる NodePort と LoadBalancer の違いと、クラスタの外から Service に届ける方法については、以下の記事で解説しています。

基本仕様 ・ 第22回 NodePort と LoadBalancer の違いService をクラスタの外に公開する NodePort と LoadBalancer の違いを図で説明します。すべてのノードの同じポートで受ける NodePort と、その前に外部のロードバランサーを置く LoadBalancer の関係を押さえ、kind のクラスタで、ノードが Docker のコンテナであることによる制約と、手元のマシンから届ける方法を確かめる手順を紹介します。

headless Service の下で Pod ごとに DNS の名前を持つ StatefulSet については、以下の記事で解説しています。

基本仕様 ・ 第14回 StatefulSet を動かして理解するPod に番号付きの固定の名前を与え、番号の順に作って止める StatefulSet の仕組みを図で説明します。web-0 から順に作り、番号の大きい順に止める決まり、headless Service が受け持つ名前、Deployment との違いを押さえ、kind のクラスタで Pod を消しても同じ名前で戻ることと、起動と停止の順番を確かめる手順を紹介します。

この回で DNS の名前の一部として見た Namespace の仕組みについては、以下の記事で解説しています。

基本仕様 ・ 第37回 Namespace で分けられるもの、分けられないもの1 つのクラスタの中でリソースをグループに分ける Namespace の仕組みを図で説明します。名前の範囲になること、Namespace に属さないクラスタ全体のリソース、既定では Namespace をまたいで届く通信、Namespace を消すと中身も消える流れを押さえ、kind のクラスタで確かめる手順を紹介します。

Kubernetes 基本仕様の目次へ