Mac で minikube を試す (2) ラベル付けとサービス公開まで

[入門Kubernetes](https://www.oreilly.co.jp/books/9784873118406/) の [メモ1](https://qiita.com/sunadorinekop/items/a317b4095bfcf2449b92) の続きです。
ラベル付けとサービス公開まで行います。Mac で minikube で動かしています。

## ラベル
### 仕様など
- key=value で複数表記できる。
- キーも値も最大 63 文字。
- キーにスラッシュ区切りでプレフィックスを指定できる  
  - 例: example.com/app-version  
example.com がプレフィックス。プレフィックスは DNS サブドメインである必要があり、最大 253 文字

### ラベルを追加して起動
※`--labels=` 内で、カンマの後にスペースを入れるとエラーになるので注意

~~~sh
$ kubectl run alpaca-prod \
--image=gcr.io/kuar-demo/kuard-amd64:1 \
--replicas=2 \
--labels="ver=1,app=alpaca,env=prod"

$ kubectl run alpaca-test
--image=gcr.io/kuar-demo/kuard-amd64:1
--replicas=2
--labels="ver=2,app=alpaca,env=test"
~~~

### ラベルを表示

~~~sh
$ kubectl get deployments --show-labels
NAME                READY   UP-TO-DATE   AVAILABLE   AGE   LABELS
alpaca-prod         2/2     2            2           94s   app=alpaca,env=prod,ver=1
alpaca-test         1/1     1            1           60s   app=alpaca,env=test,ver=2
~~~

### ラベル env=test を検索

~~~sh
$ kubectl get deployments --selector="env=test"
NAME          READY   UP-TO-DATE   AVAILABLE   AGE
alpaca-test   1/1     1            1           12m
~~~

### ラベル env=test を削除

~~~sh
$ kubectl delete deployment --selector="env=test"
deployment.extensions "alpaca-test" deleted

$ kubectl get deployments
NAME                READY   UP-TO-DATE   AVAILABLE   AGE
alpaca-prod         2/2     2            2           16m
~~~

## サービスディスカバリ

### Service 作成
expose で Service を作成

~~~sh
$ kubectl run alpaca-prod \
--image=gcr.io/kuar-demo/kuard-amd64:1 \
--replicas=3 \
--port=8080 --labels="ver=1,app=alpaca,env=prod"

$ kubectl expose deployment alpaca-prod
service/alpaca-prod exposed
~~~

kubernetes というサービスも自動で作成される。
**Service は クラスタ IP と呼ばれる仮想 IP アドレスが割当られる。**

~~~sh
$ kubectl get services -o wide
NAME          TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE   SELECTOR
alpaca-prod   ClusterIP      10.104.169.174   <none>        8080/TCP         8s    app=alpaca,env=prod,ver=1
kubernetes    ClusterIP      10.96.0.1        <none>        443/TCP          32d   <none>
~~~

### ポートフォワード

~~~sh
$ ALPACA_POD=$(kubectl get pods -l app=alpaca \
-o jsonpath='{.items[0].metadata.name}')

$ kubectl port-forward $ALPACA_POD 48858:8080
~~~

[localhost:48858](localhost:48858) を開くと alpaca にアクセスできる。
DNS Query メニューをクリックし、Name: alpaca-prod を入力して QUERY をクリック。
DNS レコードが返ってくることを確認します。
kubernetes は内部でこのような DNS サーバーを持っているのですね。

<img width="1436" alt="Screen Shot 2019-06-30 at 10.07.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106789/ce5d5d6f-e91f-f752-11b7-9b35987872f3.png">


### DNS Query が動かない時

`$ minicube delete && minicube start` すると直るかもです。
[restart: waiting for k8s-app=kube-proxy: timed out waiting for the condition](https://github.com/kubernetes/minikube/issues/3843)

<img width="1440" alt="Screen Shot 2019-06-26 at 6.36.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106789/73965e2a-f251-b8e4-9965-b8356dbb671a.png">

レスポンスに下記が返ってくる。
`read udp 172.17.0.7:50306->10.96.0.10:53: read: no route to host`
その結果 JSON パースエラー。
`Uncaught (in promise) SyntaxError: Unexpected token r in JSON at position 0`

### 起動中の Pod の YAML を編集する

~~~sh
$ kubectl edit deployment/alpaca-prod
~~~

vim が立ち上がる。

### Service を公開

~~~sh
$ kubectl edit service alpaca-prod
~~~

~~~yaml
spec:
  clusterIP: 10.104.169.174
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    app: alpaca
    env: prod
    ver: "1"
  sessionAffinity: None
  type: NodePort // ClusterIp -> NodePort に変更する
~~~

今回だとポート 32315 が alpaca-prod Service に割り当てられました。

~~~sh
AkihisanoMacBook-Pro:kuard$ kubectl describe service alpaca-prod | grep NodePort
Type:                     NodePort
NodePort:                 <unset>  32315/TCP
~~~

### Service を公開 (クラウドのみ)

~~~sh
$ kubectl edit service alpaca-prod
~~~

~~~yaml
spec:
  clusterIP: 10.104.169.174
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    app: alpaca
    env: prod
    ver: "1"
  sessionAffinity: None
  type: LoadBalancer // LoadBalancer に変更する
~~~

IP らしきものが振られました。

~~~sh
$ kubectl describe service alpaca-prod | grep IP
IP:                       10.104.169.174
~~~

私は minikube でローカルで動かしているので上記は無効ですが、
サポートされているクラウドで動かしている場合はアクセスできるのだと思います。すごいですね。

### クラスタ IP はどうやって実現している？

クラスタ内に kube-proxy と呼ばれるコンポーネントがいて、API サーバを通じてクラスタ内の Service を監視し、 ホストのカーネルの **iptables** を書き換えることで実現しているみたいです。

## 出典

Kubernetes: Up and Running, by Kelsey Hightower, Brendan Burns,  and Joe Beda (O'Reilly), 978-1-491-93567-5. (日本語版「入門 Kubernetes」 Kelsey Hightower, Brendan Burns, Joe Beda 著、オライリー・ジャパン、ISBN 978-4-87311-840-6)