「おじいちゃん kubernetesってなに？」「...それはコスモスじゃよ」(3) -運用編-

おはこんばんにちは
zerobillbank株式会社のインフラエンジニアtomatoことtomatoです。

今回はkubernetesシリーズの最終回ということで、
構築時のトラブルシューティングから運用・監視についてお話していきたいと思いまうす:rolling_eyes:

ちなみに前回の記事はこちらです:kissing:
[「おじいちゃん kubernetesってなに？」「...それはコスモスじゃよ」(1) -概要編-](https://qiita.com/Veritas666777/items/408f405028699d1b5cdd)
[「おじいちゃん kubernetesってなに？」「...それはコスモスじゃよ」(2) -構築編-](https://qiita.com/Veritas666777/items/d5f1bdc0fbbe0984add8)


## 構築のトラブルシューティング
構築時のエラーに対応として、まずPodで起こっているエラーか、
それ以外で起こっているエラーかを分類するといいと思います。

### Podのエラー
Podでエラーが起こっているかを確認するのは簡単です。
`kubectl get po`で`Pod`を確認した時に、正常時の場合は`STATUS`が`Runnning`、`STATUS`が`1/1`のように分母と分子が等しくなっているはずです。

```bash
$ kubectl get po
NAME                          READY   STATUS               RESTARTS   AGE
sample-775487cf8-d5czn        0/1     ImagePullBackOff     2          15m
```

それ以外の場合はエラーが出ていますので、
`describe`コマンドを使ってエラーの原因を確認します。

```bash
$ kubectl describe po sample-775487cf8-d5czn

---省略
Events:
  Type     Reason     Age               From                      Message
  ----     ------     ----              ----                      -------
  Normal   BackOff    28s (x4 over 1m)  kubelet, ip-xxx.internal  Back-off pulling image "nginx:1.123"
  Warning  Failed     28s (x4 over 1m)  kubelet, ip-xxx.internal  Error: ImagePullBackOff
```

`describe`コマンドで対象の`Pod`を調べると、`Events`の欄にエラーイベントが出力されます。
上記の例では存在しない`nginx`のバージョンを指定したため、イメージがpullできないエラーが出ていました。

### 調査系コマンド

上記の`describe`コマンドでも調査は可能ですが、
多くのケースでは下記の2つのコマンドのどちらかを打てば
エラー原因を見つけることができます。

#### logsコマンド

```
kubectl logs [deployment名]
```

#### get events

```
kubetctl get events | grep [deployment名]
```

### アクセスできないエラー
上記以外で`Pod`は正常に稼働しているにも関わらず
Webページなどが上手くアクセスできない場合についての対処方法についてです。

この場合、どこでアクセスが途切れているかを下記のステップで特定します。

1. Podでのアクセス確認
2. Service経由でのアクセス確認
3. Ingress経由でのアクセス確認


#### Podでのアクセス確認

```bash
$ kubectl exec -it [Pod名] -- /bin/sh
```

alpineなどは操作系のツールが入っていないことが多いため、
その場合は下記のコマンドでインストールします。

```bash
# update
apt update
# curlのインストール
apt install -y curl
# netstatのインストール
apt install -y net-tools

# aptがない場合
apk -U add curl
apk add net-tools
```

動いているプロセスの確認

```bash
$ netstat -pant
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:3000              0.0.0.0:*               LISTEN      1/nginx: master pro
```

上記コマンドで、対象のアプリケーションが動作している事と
動いているPort番号を確認します。

```bash
$ curl http://localhost:3000
welcome nginx!!
```

これで表示されれば `1. Podでのアクセス確認` は問題なしです。

#### Service経由でのアクセス確認

```bash
$ curl http://nginx:3000
welcome nginx!!
```
これで表示されれば `2. Service経由でのアクセス確認` は問題なしです。

よくあるミスとしては、`service.yaml`の中の`ports`の項目の
`port`と`targetPort`の記載ミスです。

```yaml:nginx/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: sample
  labels:
    app: nginx
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
    - port: 80 # Default port for image
      targetPort: 80
```

<b>`port`</b>... image内でのPort番号。上記のPod内で`netstat`した場合のPort番号になる。
<b>`targetPort`</b>... kubernetes上のPort番号。`Service`に紐付く。

この場合、image内でのPort番号は`3000`なので、`port`は`80`ではなく`3000`と記載します。

また`deployment.yaml`内にも`containerPort`という項目があり
こちらは`service.yaml`の`targetPort`と合わせる必要があります。

#### Ingress経由でのアクセス確認

上記までで問題がなくてアクセスできない場合は、ドメイン周りの問題が考えられます。
実際にページにアクセスした際のエラーメッセージを基に
ドメインやSSL証明書周りを確認してみてください。


## 運用
kubernetesでは`yaml`で管理することで冪等性を担保していますが
運用に置いてyamlの取り扱いで気をつけたほうがいいなーと思う点をあげてみます。

### applyの前にはdiffを取る

`apply`コマンドで適用をする前に、必ず`diff`コマンドで差分確認をしましょう。
想定外の`yaml`を当ててしまう事故を防げます。

```bash
# 想定の差分が出ることを確認
$ kubectl diff -f nginx/deployment.yaml
# 適用
$ kubectl apply -f nginx/deployment.yaml
# 差分が出ないことを確認
$ kubectl diff -f nginx/deployment.yaml
```

### 更新の際にはrolloutコマンドを用いる
`Pod`の更新の際は`delete`コマンドではなく、`rollout restart`コマンドを使用します。
`delete`コマンドで`Pod`を削除しても、`deployment`が存在していれば`Pod`は再起動されますが
削除してから再起動する間にサービスダウンが発生します。
`rollout restart`コマンドであれば、古い`Pod`を残しつつ、新しい`Pod`に順次移行してくれるため、サービスダウンなく再起動をすることができます。

`config`や`secret`などのリソースのみを更新する場合、`Pod`が再起動されないと
新しい定義が読み込まれませんので、その際も`rollout restart`コマンドを忘れずに実行しましょう。

```bash
$ kubectl rollout restart deploy/nginx
deployment.apps/nginx restarted
```

### おまけ
`kubectl api-resources`と打つと、利用できるリソースの一覧を表示できます。
さらにリソースごとのショートカットの名前と、`yaml`に記載する`apiVersion`も確認できるので
何かあった時に覚えておくと便利なコマンドです。

```bash
$ kubectl api-resources

NAME                              SHORTNAMES   APIGROUP                       NAMESPACED   KIND
bindings                                                                      true         Binding
componentstatuses                 cs                                          false        ComponentStatus
configmaps                        cm                                          true         ConfigMap
endpoints                         ep                                          true         Endpoints
events                            ev                                          true         Event
limitranges                       limits                                      true         LimitRange
namespaces                        ns                                          false        Namespace
nodes                             no                                          false        Node
persistentvolumeclaims            pvc                                         true         PersistentVolumeClaim
persistentvolumes                 pv                                          false        PersistentVolume
pods                              po                                          true         Pod
...
```

## 監視
監視については色々なツールがあると思いますが、
まず手軽にやるのなら下記のツールと相性が良いと思います。
無料でUIによるログ表示から、アラート発報まで一通り必要なことができちゃいます:heart_eyes:

![スクリーンショット 2021-03-30 9.34.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274405/3d01fcbf-7764-5f2b-27d0-513e3748aa33.png)

また`helm`(パッケージ管理ツール)が3系になり、とても導入が楽になりました。
ただし、デフォルト設定のまま適用すると、どんな値なのかの認識や管理ができないため
一旦ローカルに`fetch`してから`install`するのが良いのではと思います。

各設定値については`values.yaml`に記載されてますので
変更したい項目を見つけて値をいじると`install`もしくは`upgrade`の際に適用されます。

### インストール

helmのインストールについては下記を参照してください。
https://helm.sh/ja/docs/intro/install/

#### fetchする
```bash
$ helm repo update

$ helm fetch stable/filebeat
$ helm fetch stable/logstash
$ helm fetch stable/elasticsearch
$ helm fetch stable/kibana
$ helm fetch grafana/grafana

$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
$ helm repo update
$ helm fetch prometheus-community/kube-prometheus-stack
```

#### installする

```bash
$ helm install -name filebeat -n monitoring -f filebeat/values.yaml stable/filebeat
$ helm install -name logstash -n monitoring -f logstash/values.yaml stable/logstash
$ helm install -name elasticsearch -n monitoring -f elasticsearch/values.yaml stable/elasticsearch
$ helm install -name kibana -n monitoring -f kibana/values.yaml stable/kibana
$ helm install -name grafana -n monitoring -f grafana/values.yaml grafana/grafana
$ helm install -name prometheus -n monitoring -f kube-prometheus-stack/values.yaml prometheus-community/kube-prometheus-stack
```

インストールはこれだけですのでとても簡単！
ちなみに更新したいときは`install`の部分を`upgrade`に変えるだけです。

Grafanaは設定周りがちょっとややこしいので、以前に書いた下記の記事を参考にしていただければと。
[helm3を使用して超簡単にkubernetesにGrafanaをデプロイする方法がまるでtomato](
https://qiita.com/Veritas666777/items/9137df5467c688fb0a33)

## おわり
というわけで全3回に渡ってkubernetesについて解説していきました。
気づいた点があれば随時加筆していきたいと思います。
一人でも多くkubernetes沼にハマってくれるエンジニアが増えてくれればいいなと思っております。
みなさま良いkubernetesライフを！！

ではまた🙋‍♂️

## さいごに

ZEROBILLBANKでは一緒に働く仲間を募集中です。
なんとかjsとか、ブロックチェーンとか、kubernetesとかでいろんなAPIを作るお仕事。
今のところエンジニアは5人くらい。スタートアップだけど、結構ホワイトで働きやすいです。

[ZEROBILLBANK JAPAN Inc.](https://zerobillbank.com)