Kubernetes こと始め (2) - Service
続きです。
事前準備
ここからDockerイメージを2つ用意する。
gcr.io/<project-id>/test-app1
は GET /
でtest-1 OK
gcr.io/<project-id>/test-app2
は GET /
でtest-2 OK
が返ってくるとする。
それを使ってPodをふたつ立てておく。
dev-pod1.yml
apiVersion: v1 kind: Pod metadata: name: test-app1 labels: run: test spec: containers: - name: test-app1 image: gcr.io/<project-id>/test-app1:latest ports: - containerPort: 80
dev-pod2.yml
apiVersion: v1 kind: Pod metadata: name: test-app2 labels: run: test spec: containers: - name: test-app1 image: gcr.io/<project-id>/test-app2:latest ports: - containerPort: 80
それぞれPodを作成しておく。
$ kubectl create -f dev-pod1.yml $ kubectl create -f dev-pod2.yml
(ここから先 kubectl create
の記述は省きます )
Serviceとネットワーク
Docker で必要となるのは
- Docker内のコンテナ間のやりとり
- 外部とのやりとり
これらを設定していくのにServiceというのを用意していく。
Service
http://kubernetes.io/docs/user-guide/services/
minion 上で動作するNetwork Proxy の設定単位。
いくつかのTypeがあり、それらを組み合わせて構成していく。
NodePort
内部ネットワークの設定時に使う。
selector でどのPodに紐づけるかを決める。
dev-np.yml
apiVersion: v1 kind: Service metadata: name: dev-np spec: selector: run: test type: NodePort ports: - protocol: TCP port: 80 targetPort: 80 nodePort: 31707 name: http
selectorで対象となるPodが含まれるようにしておく。
Podsには run=test
が設定されているので、それを指定。
ちなみに、Serviceを作成するとfirewall についてのWarningが出る。
$ kubectl create -f dev-np.yml You have exposed your service on an external port on all nodes in your cluster. If you want to expose this service to the external internet, you may need to set up firewall rules for the service port(s) (tcp:31707) to serve traffic. See http://releases.k8s.io/release-1.3/docs/user-guide/services-firewalls.md for more details. service "dev-np" created
直接自分のPCから動作を確認するには、GCPのfirewall を設定すれば、nodePort経由でアクセスできるようになる。
$ gcloud compute firewall-rules create my-rule --allow=tcp:31707
と、firewallに新しいルールを追加。 あとは各nodeの外部IPを確認して、そこにアクセスをして確認ができる。
$ kubectl get nodes -o json | jq ".items[]|{name: .metadata.name, externalIP: .status.addresses[1].address}" { "name": "gke-kube-test-cluster-default-pool-771fd355-34h9", "externalIP": "104.199.214.47" } { "name": "gke-kube-test-cluster-default-pool-771fd355-6ejb", "externalIP": "104.199.206.123" } { "name": "gke-kube-test-cluster-default-pool-771fd355-dleq", "externalIP": "104.199.156.133" }
$ curl http://104.199.156.133:31707 test-1 OK
LoadBalancer
わざわざfirewallの設定を入れたように、通常は外からServiceへのアクセスはできない。
internet | ------------ [ Services ]
NodePortを使った場合、firewallの設定をいじったが、LoadBalancerやIngressを使えば良きようにやってくれる。
internet | [ Ingress, LoadBalancer ] --|-----|-- [ Services ]
外部からのアクセスを負荷分散させたい場合は、そのままの名前のLoadBalancerというタイプがある。
dev-lb.yml
apiVersion: v1 kind: Service metadata: name: dev-lb spec: selector: run: test type: LoadBalancer ports: - protocol: TCP port: 80 targetPort: 80
これで80ポートにアクセスがあった場合に、label が run=test
と指定されているPodの80にアクセスできるようになる。
podsを取得したときに --show-labels
で確認できる。
$ kubectl get pods --show-labels NAME READY STATUS RESTARTS AGE LABELS test-app1 1/1 Running 0 54s run=test test-app2 1/1 Running 0 50s run=test
$ kubectl get svc dev-svc NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE dev-lb 10.3.251.63 104.199.223.53 80/TCP 3m $ kubectl describe svc dev-lb Name: dev-lb Namespace: default Labels: <none> Selector: run=test Type: LoadBalancer IP: 10.3.251.63 LoadBalancer Ingress: 104.199.223.53 Port: <unset> 80/TCP NodePort: <unset> 32134/TCP Endpoints: 10.0.0.5:80,10.0.2.5:80 Session Affinity: None Events: FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 4m 4m 1 {service-controller } Normal CreatingLoadBalancer Creating load balancer 3m 3m 1 {service-controller } Normal CreatedLoadBalancer Created load balancer
LoadBalancer Ingress: 104.199.223.53
というものができて、そこにアクセスできるようになる。
Ingress
SSLでLoadBalancerを使いたかったりパスで制御したい場合は、細かい設定が必要な場合は Ingress を利用する。
Serviceがレイヤ3(TCP/UDP over IP)。Ingressがレイヤ7(HTTPS)の取り扱い担当。
Ingressは、外部からのURLアクセスはもちろん、パスでの振り分け、LoadBalancer、SSLの設定などいろいろできる。
ただこのIngress,ベータ。apiVersion: v1beta1
になっている。
試すために、まずは NodePort を作る
dev-np.yml
apiVersion: v1 kind: Service metadata: name: dev-np spec: selector: run: test type: NodePort ports: - protocol: TCP port: 80 targetPort: 80 name: http
次にそのNodePortをbackendにしたIngressを作成する
dev-ingress.yml
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: dev-ingress spec: backend: serviceName: dev-np servicePort: 80
/
にきたら、dev-np
serviceに送る設定。
作成して最初はGlobalIPが振られない。
$ kubectl get ing NAME HOSTS ADDRESS PORTS AGE dev-ingress * 80 12s
作成してしばらくするとADDRESSが振られる。
$ kubectl get ingress dev-ingress NAME HOSTS ADDRESS PORTS AGE dev-ingress * 130.211.20.6 80 1m
まだ設定完了ではなく、Annotations.backendsにあるBackendnの値が変わるのを待つ必要がある。
$ kubectl describe ing Name: dev-ingress Namespace: default Address: 130.211.20.6 Default backend: dev-np:80 (10.0.0.5:80,10.0.2.5:80) Rules: Host Path Backends ---- ---- -------- * * dev-np:80 (10.0.0.5:80,10.0.2.5:80) Annotations: backends: {"k8s-be-31291--b0f63256b44dff5c":"Unknown"} forwarding-rule: k8s-fw-default-dev-ingress--b0f63256b44dff5c target-proxy: k8s-tp-default-dev-ingress--b0f63256b44dff5c url-map: k8s-um-default-dev-ingress--b0f63256b44dff5c Events: FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 2m 2m 1 {loadbalancer-controller } Normal ADD default/dev-ingress 1m 1m 1 {loadbalancer-controller } Normal CREATE ip: 130.211.20.6
5分くらいすると Unknown
が HEALTY
に切り替わる。
Annotations: backends: {"k8s-be-31291--b0f63256b44dff5c":"HEALTY"}
するとLoadBalancerのときと同じようにアクセスができるようになる。
$ curl http://130.211.20.6 test-1 OK
まとめ
Serviceの設定はかなり簡単でいろいろな組み合わせができる。
次はちょっと時間置いてから、kubectl apply
を使った設定更新周りの話を書く。