KubernetesのEventを見たい時にはすでに消えている件

# 背景 Kubernetesのトラブルシュートをしているときのこと
?「どうやら、アプリケーションの調子がおかしいのだけど、Kubernetesで何か起きてない？」
運用者「よっしゃ　Kubernetesのイベントを見て突き止めたるで」

という 風に、一目散にkubernetesクラスタに駆け寄ることと思います。(図1)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94861/2849d8cd-9129-42f6-e560-7a57428e4654.png)
図1. kubernetesクラスタに駆け寄る運用者

# 駆け寄った際に行うことの例
kubernetesクラスタ内で発生したイベントを取得することで、なんとなく何が起こっていたかを把握することができます。
ただし、1時間分しかEventは保持されないため、通知が遅れたり駆け寄るのが遅いと見逃してしまうことがあります。(図2)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94861/428ef436-6ba4-4b3b-ce7e-66da7a287e50.png)
図2. kubectl get eventの例


# Eventを永続化(通知先にて永続化)する仕組みを検討する(Event Exporter)

Kubecon EU 2019にて発表されている、[kubernetes-event-exporter](https://static.sched.com/hosted_files/kccncna19/d0/Exporting%20K8s%20Events.pdf)が１つのアプローチとなる。
Github: https://github.com/opsgenie/kubernetes-event-exporter

下記ページにて、Slackへの通知方法について記載があり、大変参考になりました。
kubernetes-event-exporter v0.8(2020/06リリース)にて、MS Teams向け通知もサポートされたため検証してみる。
参考元: https://qiita.com/kob-u/items/125bccf9dba5a7dd9a90

# kubernetes-event-exporterの構築
## Githubから取得

```bash
git clone https://github.com/opsgenie/kubernetes-event-exporter
```

## Teams向けの設定を記載

デフォルトの設定(deploy/01-config.yaml)が下記

```bash
apiVersion: v1
kind: ConfigMap
metadata:
  name: event-exporter-cfg
  namespace: monitoring
data:
  config.yaml: |
    logLevel: error
    logFormat: json
    route:
      routes:
        - match:
            - receiver: "dump"
    receivers:
      - name: "dump"
        file:
          path: "/dev/stdout"
```

data.config.yaml内のreceiversにTeamsのレシーバ設定をする

Teams向けの設定例は[Github](https://github.com/opsgenie/kubernetes-event-exporter#teams)の通り

下記のendpoint部分をwebhook endpointで置き換える

```bash
# ...
receivers:
  - name: "ms_teams"
    teams:
      endpoint: "https://outlook.office.com/webhook/..."
      layout: # Optional
```

## 設定例

```bash
❯ cat 01-config.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: event-exporter-cfg
  namespace: monitoring
data:
  config.yaml: |
    logLevel: error
    logFormat: json
    route:
      routes:
        - match:
            - receiver: "ms_teams"
    receivers:
      - name: "dump"
        file:
          path: "/dev/stdout"
      - name: "ms_teams"
        teams:
          endpoint: "https://outlook.office.com/webhook/..."
```

## デプロイ

```bash
❯ k apply -f 00-roles.yaml              
namespace/monitoring created
serviceaccount/event-exporter created
clusterrolebinding.rbac.authorization.k8s.io/event-exporter created

❯ k apply -f 01-config.yaml             
configmap/event-exporter-cfg created

❯ k apply -f 02-deployment.yaml         
deployment.apps/event-exporter created

❯ k get po
NAME                              READY   STATUS    RESTARTS   AGE
event-exporter-555d56c958-w9cld   1/1     Running   0          3s

❯ k logs event-exporter-555d56c958-w9cld 

❯ k run nginx --image nginx
pod/nginx created
```

## Teamsにイベント群が通知されることを確認できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94861/a7ef22c1-a256-5a66-7f88-78a5e7bb8835.png)


## 実践的な使い方

本来は全てのイベントを通知しても嬉しくないので、OOMKilledやCrashLoopBackOff, ImagePullBackOffイベントが発生した際に通知したい

試しにイベントのTYPEがWARNINGなものについて通知するようにする

config.yaml内のroute.routes[].dropにてtype: Normalを設定することで、Normalなイベントを非通知にする

```bash
apiVersion: v1
kind: ConfigMap
metadata:
  name: event-exporter-cfg
  namespace: monitoring
data:
  config.yaml: |
    logLevel: error
    logFormat: json
    route:
      routes:
        - match:
            - receiver: "ms_teams"
          drop:
            - type: "Normal"
    receivers:
      - name: "dump"
        file:
          path: "/dev/stdout"
      - name: "ms_teams"
        teams:
          endpoint: "https://outlook.office.com/webhook/..."
```

試しに、存在しないosushi imageを指定することで、ImagePullBackOffを引き起こしてみる

osushiがないと怒られてしまう

```bash
❯ k run nginx --image osushi  
pod/nginx created

❯ k get event | grep Warn
6s          Warning   Failed              pod/nginx                              Failed to pull image "osushi": rpc error: code = Unknown desc = failed to pull and unpack image "docker.io/library/osushi:latest": failed to resolve reference "docker.io/library/osushi:latest": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed
6s          Warning   Failed              pod/nginx                              Error: ErrImagePull
6s          Warning   Failed              pod/nginx                              Error: ImagePullBackOff
```

Teamsにて同様のイベントが通知されていることを確認できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94861/97018620-13bc-a6c5-2290-5a695b13eaf3.png)


# その他のevent exporter

純粋にexporterとしての役割に閉じたタイプ

通知部分は担当しない分、別途prometheus ruleで柔軟にアラート設定できる

opsgenie側は単体で動くが、こちらはメトリクスを収集するprometheusやalertmanagerなどが前提となるので、用途によるといった印象

[caicloud/event_exporter](https://github.com/caicloud/event_exporter)

# まとめ
- kubernetesのトラブルシュートのためにEventを別途保持する仕組みとして、kubernetes-event-exporterを調査した。
- 2020/06リリースのv0.8にてMS Teams向けに通知を行えるようになったので、実際に検証しうまく通知されることを確認した。
- Teams内にてEventを保持することで、普段からMS Teamsを使用している場合にシームレスにトラブル対応に移行することが期待できる