Kubernetes でのイベント監視マイクロサービスとクラウドネイティブの発展に伴い、Kubernetes の拡張性、スケーラビリティ、自動化、高い安定性に依存してビジネスの安定性を確保するため、Kubernetes にビジネスを展開する企業がますます増えています。 ただし、Kubernetes 自体は複雑な管理システムです。企業ビジネスのインフラストラクチャであるため、クラスタ内で実行されるビジネス システムとクラスタは企業にとって非常に重要になっています。そのため、実際の業務では、Kubernetes自体とビジネスの可観測性を向上させるために必要な監視方法を使用します。一般的なものは次のとおりです。 - cAdvisor を使用して、CPU やメモリなどのコンテナ リソース メトリックを取得します。
- kube-state-metrics を使用して、Deployment や Pod のステータスなど、リソース オブジェクトのステータス インジケーターを取得します。
- metrics-server を使用して、クラスター全体のリソース データ インジケーターを取得します。
- 特定のコンポーネントのメトリックを取得するには、node-exporter などのさまざまな公式および非公式のエクスポーターを使用します。
ほとんどの監視シナリオでは、Pod、Node などの特定のリソースを監視します。ただし、Kubernetes には、Pod のスケジュール設定や再起動など、リソースでは表現できない、つまり特定のリソースではないシナリオもあります。 Kubernetes では、このようなシナリオは主に事件 と呼ばれます。 Kubernetes には、次の 2 種類のイベントがあります。 - 警告イベント、予期しない状態間でイベントの状態遷移が発生します。
- 通常のイベント: 予想される状態は現在の状態と一致しています。
ここでは、説明のために Pod を使用します。 Pod を作成すると、最初に Pending 状態になり、次に Creating 状態 (主にイメージのプル) になり、次に NotReady 状態 (主にアプリケーションの起動とヘルスチェックの合格を待機) になり、最後に Running 状態になります。このプロセス全体で通常のイベントが生成されます。ただし、実行プロセス中に、ノードの削除、OOM などの何らかの異常な理由により Pod が他の状態になった場合、この状態遷移中に警告イベントが生成されます。 Kubernetes では、他の方法を使用してビジネスの安定性を確保できます。たとえば、アフィニティ スケジューリングとアンチアフィニティ スケジューリングを使用して、ポッドをノードまたは同じアベイラビリティ ゾーンにスケジュールすることを回避し、PDB を使用して、ノードの削除によって単一のポッドが使用できなくなることを回避できます。警告イベントがビジネス全体の安定性に致命的な影響を与えることはないかもしれませんが、イベントを監視することでクラスターの状態変化を認識できれば、ギャップを見つけるのに役立ち、見落としがちな問題を認識するのにも役立ちます。 Kubernetes では、すべてのイベントはイベント システムを通じて API サーバーに記録され、最終的に Etcd に保存されます。これらは、API または kubectl を通じて表示できます。次に例を示します。 次のようなオブジェクトのイベントを表示することもできます。 イベントには、時間、タイプ、オブジェクト、原因、説明が含まれます。イベントを通じて、デプロイメント、スケジュール、実行、停止など、アプリケーションのライフサイクル全体を理解できます。イベントを使用して、システム内で発生する例外を把握することもできます。各 Kubernetes コンポーネントのソース コードは、コンポーネントがトリガーする可能性のあるイベント タイプを定義します。たとえば、kubelet ソース コードでは、次のように多くのイベント タイプが定義されています。 package events // Container event reason list const ( CreatedContainer = "Created" StartedContainer = "Started" FailedToCreateContainer = "Failed" FailedToStartContainer = "Failed" KillingContainer = "Killing" PreemptContainer = "Preempting" BackOffStartContainer = "BackOff" ExceededGracePeriod = "ExceededGracePeriod" ) // Pod event reason list const ( FailedToKillPod = "FailedKillPod" FailedToCreatePodContainer = "FailedCreatePodContainer" FailedToMakePodDataDirectories = "Failed" NetworkNotReady = "NetworkNotReady" ) ...... Kubernetes イベントは最終的に Etcd に保存され、デフォルトでは 1 時間のみ保存されます。 Etcd 自体はいくつかの複雑な分析操作をサポートしていないため、それらの操作は Etcd に受動的に保存することしかできず、他のシステムへのアクティブなプッシュはサポートされません。通常、手動でのみ表示できます。 実際には、Kubernetes イベントには次のような他の要件があります。 - 異常事態が発生した場合にはアラートを発報したいと考えています。
- より長いイベントの歴史的なイベントを照会したい。
- クラスターイベントの柔軟な統計分析を実行したい。
このため、クエリやアラートに使用できるように、Kubernetes イベントを個別に収集する必要があります。 コミュニティには、イベントの収集とアラートのためのツールが多数あります。私がよく使う 2 つのツールは次のとおりです。 - kube-eventer: Alibaba Cloud がリリースしたイベント収集ツール。
- kube-event-exporter: Github 上の別のイベント収集作業。
実際の作業では、基本的に収集機能とアラーム機能を満たすことができるいずれかを選択できます。ここでは、アラーム用に kube-eventer を使用し、表示および分析のために ES にイベントを収集するために kube-event-exporter を使用して、上記の 2 つのプラグインを同時に使用します。 イベントアラートにはkube-eventerを使用するkube-eventer のアラーム チャネルには、WeChat for Business、DingTalk、および webhook を使用できます。ニーズに合わせてお選びいただけます。各コンポーネントの具体的な使用方法は、プロジェクトのdocs/en ディレクトリにあります。ここでは、Webhook を使用して WeChat for Enterprise にアラームを送信することを選択します。 (1)まず、企業のWeChatグループにWebhookロボットを作成し、Webhookアドレスを取得する必要があります。 (2)Kubernetesクラスターにkube-eventerをデプロイします。 # cat kube-eventer.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: name: kube-eventer name: kube-eventer namespace: monitoring spec: replicas: 1 selector: matchLabels: app: kube-eventer template: metadata: labels: app: kube-eventer annotations: scheduler.alpha.kubernetes.io/critical-pod: '' spec: dnsPolicy: ClusterFirstWithHostNet serviceAccount: kube-eventer containers: - image: registry.aliyuncs.com/acs/kube-eventer:v1.2.7-ca03be0-aliyun name: kube-eventer command: - "/kube-eventer" - "--source=kubernetes:https://kubernetes.default.svc.cluster.local" ## .eg,dingtalk sink demo #- --sink=dingtalk:[your_webhook_url]&label=[your_cluster_id]&level=[Normal or Warning(default)] #- --sink=webhook:https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=07055f32-a04e-4ad7-9cb1-d22352769e1c&level=Warning&label=oa-k8s - --sink=webhook:http://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=888888-888-8888-8888-d35c52ff2e0b&level=Warning&header=Content-Type=application/json&custom_body_cnotallow=custom-webhook-body&custom_body_configmap_namespace=monitoring&method=POST env: # If TZ is assigned, set the TZ value as the time zone - name: TZ value: "Asia/Shanghai" volumeMounts: - name: localtime mountPath: /etc/localtime readOnly: true - name: zoneinfo mountPath: /usr/share/zoneinfo readOnly: true resources: requests: cpu: 100m memory: 100Mi limits: cpu: 500m memory: 250Mi volumes: - name: localtime hostPath: path: /etc/localtime - name: zoneinfo hostPath: path: /usr/share/zoneinfo --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: kube-eventer rules: - apiGroups: - "" resources: - events - configmaps verbs: - get - list - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kube-eventer roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: kube-eventer subjects: - kind: ServiceAccount name: kube-eventer namespace: monitoring --- apiVersion: v1 kind: ServiceAccount metadata: name: kube-eventer namespace: monitoring --- apiVersion: v1 data: content: >- {"msgtype": "text","text": {"content": "集群事件告警\n事件级别: {{ .Type }}\n名称空间: {{ .InvolvedObject.Namespace }}\n事件类型: {{ .InvolvedObject.Kind }}\n事件对象: {{ .InvolvedObject.Name }}\n事件原因: {{ .Reason }}\n发生时间: {{ .LastTimestamp }}\n详细信息: {{ .Message }}"}} kind: ConfigMap metadata: name: custom-webhook-body namespace: monitoring Webhook 構成では、level=Warning が追加されます。これは、警告イベントのみが通知されることを意味します。さらに、namespaces フィールドを使用して、アラートする必要がある名前空間を渡すことができ、kinds フィールドを使用して、アラートする必要があるオブジェクトをフィルター処理することができます。たとえば、Node の Warning イベントのみを送信する必要がある場合は、level=warning&kinds=Node と記述できます。たとえば、アラーム ストームをあまり生成せず、システム OOM イベントなどの特定の理由でのみアラームを送信する場合は、 reasnotallow=SystemOOM 待機を追加できます。 kube-eventer Pod が起動すると、Enterprise WeChat は次のような条件を満たすイベントアラートを受信できます。 kube-event-exporter を使用してクラスター イベントを収集する上記では、イベントアラームに kube-eventer を使用していますが、これは基本的に履歴イベントを保存しません。実際には、過去のイベントを照会し、それらに対して何らかのイベント分析を行う必要がある場合があります。 ES は、Kibana を介したコンテンツの収集と表示および分析によく使用されるため、ここでは kube-event-exporter を使用して Kubernetes イベントを ES に収集します。 kube-event-exporter は、イベントを ES に直接保存することも、イベントを Kafka に送信して、Logstash を介して Kafka のデータを使用して ES に保存することもできます。ここでは、環境の現在の状態に基づいて、イベントを Kafka に送信し、それらを消費して ES に収集します。 (1) kube-event-exporterをデプロイする apiVersion: v1 kind: ServiceAccount metadata: namespace: monitoring name: event-exporter --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: event-exporter roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: view subjects: - kind: ServiceAccount namespace: monitoring name: event-exporter --- apiVersion: v1 kind: ConfigMap metadata: name: event-exporter-cfg namespace: monitoring data: config.yaml: | logLevel: error logFormat: json route: routes: - match: - receiver: "kafka" drop: - kind: "Service" receivers: - name: "kafka" kafka: clientId: "kubernetes" topic: "kubenetes-event" brokers: - "192.168.100.50:9092" - "192.168.100.51:9092" - "192.168.100.52:9092" compressionCodec: "snappy" layout: #optional kind: "{{ .InvolvedObject.Kind }}" namespace: "{{ .InvolvedObject.Namespace }}" name: "{{ .InvolvedObject.Name }}" reason: "{{ .Reason }}" message: "{{ .Message }}" type: "{{ .Type }}" timestamp: "{{ .GetTimestampISO8601 }}" cluster: "sda-pre-center" --- apiVersion: apps/v1 kind: Deployment metadata: name: event-exporter namespace: monitoring spec: replicas: 1 template: metadata: labels: app: event-exporter version: v1 spec: serviceAccountName: event-exporter containers: - name: event-exporter image: ghcr.io/resmoio/kubernetes-event-exporter:latest imagePullPolicy: IfNotPresent args: - -cnotallow=/data/config.yaml volumeMounts: - mountPath: /data name: cfg volumes: - name: cfg configMap: name: event-exporter-cfg selector: matchLabels: app: event-exporter version: v1
kube-event-exporter Pod が起動すると、収集されたイベントは次のように Kafka で表示できます。 (2)logstashを導入してESにイベントを保存する kind: Deployment apiVersion: apps/v1 metadata: name: kube-event-logstash namespace: log labels: app: kube-event-logstash spec: replicas: 1 selector: matchLabels: app: kube-event-logstash template: metadata: creationTimestamp: null labels: app: kube-event-logstash annotations: kubesphere.io/restartedAt: '2024-02-22T09:03:36.215Z' spec: volumes: - name: kube-event-logstash-pipeline-config configMap: name: kube-event-logstash-pipeline-config defaultMode: 420 containers: - name: kube-event-logstash image: 'logstash:7.8.0' env: - name: XPACK_MONITORING_ELASTICSEARCH_HOSTS value: 'http://192.168.100.100:8200' - name: XPACK_MONITORING_ELASTICSEARCH_USERNAME value: jokerbai - name: XPACK_MONITORING_ELASTICSEARCH_PASSWORD value: JeA9BiAgnNRzVrp5JRVQ4vYX - name: PIPELINE_ID value: kube-event-logstash - name: KAFKA_SERVER value: '192.168.100.50:9092,192.168.100.51:9092,192.168.100.52:9092' - name: ES_SERVER value: 'http://192.168.100.100:8200' - name: ES_USER_NAME value: jokerbai - name: ES_USER_PASSWORD value: JeA9BiAgnNRzVrp5JRVQ4vYX - name: NODE_NAME valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.name - name: PIPELINE_BATCH_SIZE value: '4000' - name: PIPELINE_BATCH_DELAY value: '100' - name: PIPELINE_WORKERS value: '4' - name: LS_JAVA_OPTS value: '-Xms2g -Xmx3500m' resources: limits: cpu: '2' memory: 4Gi requests: cpu: '2' memory: 4Gi volumeMounts: - name: kube-event-logstash-pipeline-config mountPath: /usr/share/logstash/pipeline livenessProbe: tcpSocket: port: 9600 initialDelaySeconds: 39 timeoutSeconds: 5 periodSeconds: 30 successThreshold: 1 failureThreshold: 2 readinessProbe: tcpSocket: port: 9600 initialDelaySeconds: 39 timeoutSeconds: 5 periodSeconds: 30 successThreshold: 1 failureThreshold: 2 terminationMessagePath: /dev/termination-log terminationMessagePolicy: File imagePullPolicy: IfNotPresent restartPolicy: Always terminationGracePeriodSeconds: 30 dnsPolicy: ClusterFirst securityContext: {} affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: node/category operator: In values: - app schedulerName: default-scheduler strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 25% maxSurge: 25% revisionHistoryLimit: 10 progressDeadlineSeconds: 600 --- kind: ConfigMap apiVersion: v1 metadata: name: kube-event-logstash-pipeline-config namespace: log data: logstash.conf: |- input { kafka { id => "kafka_plugin_id" bootstrap_servers => "${KAFKA_SERVER}" client_id => "logstash" group_id => "logstash" decorate_events => true topics => ["kubenetes-event"] codec => json { charset => "UTF-8" } } } output { elasticsearch { hosts => "${ES_SERVER}" user => "${ES_USER_NAME}" password => "${ES_USER_PASSWORD}" index => "kubernetes-event-%{+YYYY.MM}" manage_template => false template_name => "kubernetes-event" } }
デプロイする前に、ES でテンプレートを作成します。 Kibanaの開発ツールで操作できます。声明は次のとおりです。 PUT _template/kubernetes-event { "index_patterns" : [ "*kubernetes-event*" ], "settings": { "index": { "highlight": { "max_analyzed_offset": "10000000" }, "number_of_shards": "2", "number_of_replicas": "0" } }, "mappings": { "properties": { "cluster": { "type": "keyword" }, "kind": { "type": "keyword" }, "message": { "type": "text" }, "name": { "type": "keyword" }, "namespace": { "type": "keyword" }, "reason": { "type": "keyword" }, "type": { "type": "keyword" }, "timestamp": { "type": "keyword" } } }, "aliases": {} } 次に、Kubernetes クラスターに Logstash をデプロイします。次に、次のように Kibana で収集されたイベントを表示できます。 データが利用可能であれば、クエリと分析はシンプルで簡単になります。たとえば、今日のイベントの原因が「Unhealthy」である合計回数をカウントする最も簡単な方法は、次のように Kibana でチャートを作成することです。 上記は、Kubernetes でクラスター イベントを収集してアラートを送信する方法です。これは巨人の肩を直接使用しています。また、イベントアラームのスイッチの追加をサポートし、イベントアラームを任意にオン/オフにできるなど、企業内で再度開放して機能を充実させることもできます。 リンク[1] https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/events/event.go?spm=a2c6h.12873639.article-detail.7.c8585c576FGh7o&file=event.go。 [2] https://github.com/AliyunContainerService/kube-eventer。 [3] https://github.com/resmoio/kubernetes-event-exporter。 |