動かざることバグの如し

近づきたいよ 君の理想に

KubernetesのServiceリソースとは

環境

KubernetesのServiceリソースとは

難しい。公式ドキュメントだと

Podの集合で実行されているアプリケーションをネットワークサービスとして公開する抽象的な方法

としか書かれていない。自分としては「複数のPodに共通のIPアドレス提供するなど、ロードバランサとDNSを設定するためのリソース」で落ち着いた。

ServiceのIPアドレス確認

まずはNginxのDeploymentを作成してみる

kubectl create deploy nginx --image=nginx

そしてServiceリソースを作成

kubectl expose deploy nginx --port=80 --target-port=80

諸々割り当てられたIPアドレスを確認してみる

❯ kubectl get svc nginx
NAME    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
nginx   ClusterIP   10.96.184.249   <none>        80/TCP    13s

~
❯ kubectl get ep nginx
NAME    ENDPOINTS        AGE
nginx   10.244.0.77:80   30s

~
❯ kubectl get pods --selector=app=nginx -o wide
NAME                    READY   STATUS    RESTARTS   AGE     IP            NODE       NOMINATED NODE   READINESS GATES
nginx-8f458dc5b-qr65w   1/1     Running   0          3m16s   10.244.0.77   ubuntu01   <none>           <none>
  • ServiceのClusterIP: 10.96.184.249
  • PodのIPアドレス: 10.244.0.77

つまり10.96.184.249へアクセスすると、ロードバランサによって10.244.0.77へルーティングされるということになる

DNSでアクセスする

IPアドレスわかるんだからこれでOK、とはならない。KubernetesではIPアドレスの変化が激しいからいつ 10.96.184.249 が変わってもおかしくない。

そこで標準でDNSサービスが提供されている。

同じNamespace内に適当なPodを立てて中に入って検証する

kubectl create deploy debugger --image=thr3a/debugger -- sleep infinity

サービス名である「nginx」で名前を引ける。ちゃんとnginx ServiceのClusterIPである 10.96.184.249 が返ってきている。

/ # nslookup nginx
Server:     10.96.0.10
Address:    10.96.0.10#53

Name:   nginx.test.svc.cluster.local
Address: 10.96.184.249

なんで出来るのかっていうとKubernetes内にDNSサーバーがあるから。コンテナ内の /etc/resolv.conf を見てみる

/ # cat /etc/resolv.conf
search test.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5

もちろんcurlでアクセス可能

/ # curl nginx
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
....(略

サービス名だけでアクセス出来るのは同一Namespace内のみ。それ以外は「..svc.」のようにフルパスでアクセスしなくてはいけない。

# namespaceがtest以外の場合
nslookup nginx.test.svc.cluster.local

スケールしてみるとどうなるのか

nginx Deploymentをスケールアウトさせてみるとどうなるのか。試しにレプリカセットを2に増やしてみる。

$ kubectl scale deploy nginx --replicas=2

するとエンドポイントのIPが増える。Nginxのログ見てるとわかるが、均一にアクセスが負荷分散されている。

❯ kubectl get ep nginx
NAME    ENDPOINTS                        AGE
nginx   10.244.0.205:80,10.244.0.77:80   5m46s

Headless Serviceを試す

ServiceのclusterIP(.spec.clusterIP)の値を None に設定すると、Headless Serviceになる。つまりService自体にロードバランサー機能は持たず、IPアドレスも持たなくなる。

物は試しに一度Serviceを削除してから --cluster-ip=None を追加して再作成してみる。

kubectl expose deploy nginx --port=80 --target-port=80 --cluster-ip=None

epは変わらず

❯ kubectl get ep nginx
NAME    ENDPOINTS                        AGE
nginx   10.244.0.205:80,10.244.0.77:80   5m46s

が、DNSで名前を引くとIPがPodの数だけ返ってくる。

/ # nslookup nginx
Server:     10.96.0.10
Address:    10.96.0.10#53

Name:   nginx.test.svc.cluster.local
Address: 10.244.0.205
Name:   nginx.test.svc.cluster.local
Address: 10.244.0.77

digコマンドだとIPアドレスが解決できない

digコマンドはデフォルトでは resolv.confのsearchを考慮しない。よってnslookup相当のことがしたければ

dig nginx +search

と明示的にsearchオプションを付ける必要がある。

参考リンク