9
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Kubernetes の Service(ClusterIP) を検証する

Posted at

メモ。

Services

環境

$kubectl version
Client Version: version.Info{Major:"1", Minor:"10", GitVersion:"v1.10.3", GitCommit:"2bba0127d85d5a46ab4b778548be28623b32d0b0", GitTreeState:"clean", BuildDate:"2018-05-28T20:03:09Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"11+", GitVersion:"v1.11.5-eks-6bad6d", GitCommit:"6bad6d9c768dc0864dab48a11653aa53b5a47043", GitTreeState:"clean", BuildDate:"2018-12-06T23:13:14Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}

ClusterIP Serviceで Pod への負荷を分散する

「type:CluserIP」のサービスを作ると Kubernetes クラスタ内からのみアクセス可能な仮想 IP が割り振られ、これを ClusterIP という。

やってみる。

Kubernetes完全ガイド impress top gearシリーズの Github リポジトリのマニュフェストを利用させて頂く。

MasayaAoyama/kubernetes-perfect-guide

マニュフェストファイルは以下の2点を利用する。

  • sample-deployment.yaml
  • sample-clusterip.yaml
sample-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
        - name: nginx-container
          image: nginx:1.12
          ports:
            - containerPort: 80

意味としては以下

  • Deployment.これを作成すると ReplicaSet と Pod も出来る.作成される Pod は3
  • nginx コンテナでは port 80 でリクエストを受け付ける
sample-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
  name: sample-clusterip
spec:
  type: ClusterIP
  ports:
    - name: "http-port"
      protocol: "TCP"
      port: 8080
      targetPort: 80
  selector:
    app: sample-app

意味としては以下。

  • Service を作成
  • Service へのリクエストは port 8080 で可能
  • Service で受け付けたリクエストは selector で記載された Pod に対して port 80 で転送する

以下より検証。

# deployment を作成
$kubectl apply -f sample-deployment.yaml
deployment.apps "sample-deployment" created

# 問題なく Pod も3つ起動している
$ kubectl get deployment
NAME                DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
sample-deployment   3         3         3            3           48s

# 各 Pod の IP を確認
$ kubectl get pod -l app=sample-app -o custom-columns="NAME:{metadata.name},IP:{status.podIP}"
NAME                                 IP
sample-deployment-86d576464c-hnkm7   172.31.20.41
sample-deployment-86d576464c-wkhjd   172.31.29.9
sample-deployment-86d576464c-x75hx   172.31.9.21


# ClusterIP service を作成
$kubectl apply -f sample-clusterip.yaml
service "sample-clusterip" created

# 10.100.97.31:8080 でクラスター内からアクセス出来る
$kubectl get service sample-clusterip
NAME               TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
sample-clusterip   ClusterIP   10.100.97.31   <none>        8080/TCP   14s

# 各 Pod の IP が Service の Endpoints で確認できる
$kubectl describe service sample-clusterip
Name:              sample-clusterip
Namespace:         default
Labels:            <none>
Annotations:       kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"sample-clusterip","namespace":"default"},"spec":{"ports":[{"name":"http-port",...
Selector:          app=sample-app
Type:              ClusterIP
IP:                10.100.97.31
Port:              http-port  8080/TCP
TargetPort:        80/TCP
Endpoints:         172.31.20.41:80,172.31.29.9:80,172.31.9.21:80
Session Affinity:  None
Events:            <none>

# 各 Pod で"hostname ファイルを /usr/share/nginx/html/index.html"にコピー
$for PODNAME in `kubectl get pod -l app=sample-app -o jsonpath='{.items[*].metadata.name}'`;
do
   kubectl exec -it ${PODNAME} -- cp /etc/hostname /usr/share/nginx/html/index.html
done

# ファイル確認 OK
$for PODNAME in `kubectl get pod -l app=sample-app -o jsonpath='{.items[*].metadata.name}'`;
do
 kubectl exec -it ${PODNAME} -- cat /usr/share/nginx/html/index.html
done
sample-deployment-86d576464c-hnkm7
sample-deployment-86d576464c-wkhjd
sample-deployment-86d576464c-x75hx


# kubectl run を使って service に curl する.以下のようなオプションを利用して Pod を起動しつつ終わったらすぐに削除する
$kubectl run testpod --image=centos:6 --restart=Never -i --rm -- curl -s http://10.100.97.31:8080/
sample-deployment-86d576464c-wkhjd

# 何回かやってみると Service へのリクエストが各 Pod に分散されているのが分かる
$kubectl run testpod --image=centos:6 --restart=Never -i --rm -- curl -s http://10.100.97.31:8080/
sample-deployment-86d576464c-hnkm7

$kubectl run testpod --image=centos:6 --restart=Never -i --rm -- curl -s http://10.100.97.31:8080/
sample-deployment-86d576464c-x75hx

A レコードを使って Service へリクエストする

Service-DNS

For example, if you have a Service called "my-service" in a Kubernetes Namespace called "my-ns", a DNS record for "my-service.my-ns" is created

Service へのリクエスト時に IP 以外に A レコードに登録された DNS 名を利用することが出来る。

Service 名を使った http://sample-clusterip:8080/ で接続してみる。

$ kubectl run testpod --image=centos:6 --restart=Never -i --rm -- curl -s http://sample-clusterip:8080/
sample-deployment-86d576464c-x75hx

A レコードは Service 名と Namespace を使って構成され、実際には[service name].[namespace].svc.cluser.local という FQDN で登録されている。
名前解決を行うと Service の ClusterIP が返却されることが分かる。

# 名前解決を実施
$kubectl run testpod --image=centos:6 --restart=Never -i --rm -- dig sample-clusterip.default.svc.cluster.local

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.68.rc1.el6_10.1 <<>> sample-clusterip.default.svc.cluster.local
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61959
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;sample-clusterip.default.svc.cluster.local. IN A

;; ANSWER SECTION:
sample-clusterip.default.svc.cluster.local. 5 IN A 10.100.97.31

;; Query time: 4 msec
;; SERVER: 10.100.0.10#53(10.100.0.10)
;; WHEN: Fri Dec 28 07:27:56 2018
;; MSG SIZE  rcvd: 118

Service 名のみでアクセス出来るのは /etc/resolv.conf の search に「default.svc.cluster.local」がある為。

$ kubectl run testpod --image=centos:6 --restart=Never -i --rm -- cat /etc/resolv.conf
nameserver 10.100.0.10
search default.svc.cluster.local svc.cluster.local cluster.local ap-northeast-1.compute.internal us-west-2.compute.internal
options ndots:5

SRV レコードを確認する

Service-DNS

Kubernetes also supports DNS SRV (service) records for named ports. If the "my-service.my-ns" Service has a port named "http" with protocol TCP, you can do a DNS SRV query for "_http._tcp.my-service.my-ns" to discover the port number for "http".

A レコードだけではなく、Service を作成すると SRV レコードも作成される。
SRV レコードではポート番号も定義できるため、クライアントが SRV レコードに対応している場合、こちらを使うことでポート番号情報を設定する必要がなくなる。

SRV レコードの登録を確認する。
Service で設定した Port 名とプロトコル(TCP/UDP)の情報が必要。
今回、Service の Port 名は「http-port」となっており、プロトコルは TCP となっている。
上記場合、先程の A レコードの前に「_http-port._tcp」を付与して名前解決を行うことで IP に加えポート番号も分かる。

$ kubectl run testpod --image=centos:6 --restart=Never -i --rm -- dig _http-port._tcp.sample-clusterip.default.svc.cluster.local SRV
If you don't see a command prompt, try pressing enter.
Error attaching, falling back to logs: unable to upgrade connection: container testpod not found in pod testpod_default

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.68.rc1.el6_10.1 <<>> _http-port._tcp.sample-clusterip.default.svc.cluster.local SRV
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12229
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; QUESTION SECTION:
;_http-port._tcp.sample-clusterip.default.svc.cluster.local. IN SRV

;; ANSWER SECTION:
_http-port._tcp.sample-clusterip.default.svc.cluster.local. 5 IN SRV 0 100 8080 sample-clusterip.default.svc.cluster.local.

;; ADDITIONAL SECTION:
sample-clusterip.default.svc.cluster.local. 5 IN A 10.100.97.31

;; Query time: 4 msec
;; SERVER: 10.100.0.10#53(10.100.0.10)
;; WHEN: Fri Dec 28 07:34:56 2018
;; MSG SIZE  rcvd: 254
9
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?