メモ。
環境
$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
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 でリクエストを受け付ける
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 へリクエストする
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 レコードを確認する
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