Kubernetes上でAlertmanagerがちゃんと通知できるか、どんな内容が通知されているのか確認してみようとすると、連携するためのSlackが必要であったり、Emailを送信するにもメールサーバが必要だったりと、意外と気軽に試せないということがありました。

なので、今回はwebhookの機能を使ってNginxにリクエストを飛ばし、リクエストの内容をログから確認してみようと思います。

webhookとは?

Alertmanagerのreceiverには以下が指定できます。

Webhookとは特定のエンドポイントに対してHTTP POSTリクエストでアラートの情報を送信するというものです。 外部サービスではないので、自分自身でエンドポイントを用意し、自分自身で後続の処理を実装する必要があります。

例えば、以下のように設定します。

receivers:
- name: "nginx"
  webhook_configs:
  - url: 'http://nginx-svc.default:8080/'

webhookの連携先としてnginxを使う

今回はwebhookの連携先としてnginxを使用します。

nginxを使って実現したいことは以下のとおりです。

  • エンドポイントを用意する
  • リクエスト内容を確認する

nginx.confの初期設定をベースにしていますが、そのままだとリクエスト内容を確認することができないので、設定を追加しました。 log_format$request_bodyを指定し、/にアクセスした時に$request_bodyがログとして標準出力に出るように設定しています。

しかし、$request_bodyを有効化するにはproxy_passなどの後続処理が必要になります。なので、proxy_pass/trashというエンドポイントにリクエストを転送し、/trashで特に意味のない処理(1x1ピクセルのgifを返す)をしています。

The variable’s value is made available in locations processed by the proxy_pass, fastcgi_pass, uwsgi_pass, and scgi_pass directives when the request body was read to a memory buffer.

http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    # -------------------追加設定---------------------
    log_format  postdata escape=none $request_body;

    server {
        listen   8080;
        location / {
            access_log /dev/stdout postdata;
            proxy_pass http://127.0.0.1:8080/trash;
        }
        location /trash {
            access_log off;
            empty_gif;
            break;
        }
    }
    # ----------------------------------------------

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

上記の設定をConfigMapとして作成し、nginxのPodに対してConfigMapをマウントしてあげます。nginx-svcというServiceも作成します。

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-configmap
  labels:
    app: nginx
data:
  nginx.conf: |

    user  nginx;
    worker_processes  auto;

    error_log  /var/log/nginx/error.log notice;
    pid        /var/run/nginx.pid;

    events {
        worker_connections  1024;
    }


    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;

        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';

        access_log  /var/log/nginx/access.log  main;

        # -------------------追加設定---------------------
        log_format  postdata escape=none $request_body;

        server {
            listen   8080;
            location / {
                access_log /dev/stdout postdata;
                proxy_pass http://127.0.0.1:8080/trash;
            }
            location /trash {
                access_log off;
                empty_gif;
                break;
            }
        }
        # ----------------------------------------------
        
        sendfile        on;
        #tcp_nopush     on;

        keepalive_timeout  65;

        #gzip  on;

        include /etc/nginx/conf.d/*.conf;
    }
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  labels:
    app: nginx
spec:
  selector:
    app: nginx
  ports:
  - name: nginx-http
    protocol: TCP
    port: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: nginx-conf
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
      volumes:
      - name: nginx-conf
        configMap:
          name: nginx-configmap
          items:
          - key: nginx.conf
            path: nginx.conf

先程例にあったように、nginx-svcをエンドポイントしてAlertmanagerのWebhookを設定します。 そうすると、以下のようにリクエストボディとして送られたアラートの情報を確認することができます。(本来は以下のようにフォーマットされないです。ブログ用にフォーマットしています。)

$ k logs nginx-6dcc55fd49-7kbpd 
...()...
{
   "receiver":"nginx",
   "status":"firing",
   "alerts":[
      {
         "status":"firing",
         "labels":{
            "alertname":"TargetDown",
            "job":"kube-proxy",
            "namespace":"kube-system",
            "prometheus":"monitoring/kube-prometheus-kube-prome-prometheus",
            "service":"kube-prometheus-kube-prome-kube-proxy",
            "severity":"warning"
         },
         "annotations":{
            "description":"100% of the kube-proxy/kube-prometheus-kube-prome-kube-proxy targets in kube-system namespace are down.",
            "runbook_url":"https://runbooks.prometheus-operator.dev/runbooks/general/targetdown",
            "summary":"One or more targets are unreachable."
         },
         "startsAt":"2023-08-13T03:48:56.603Z",
         "endsAt":"0001-01-01T00:00:00Z",
         "generatorURL":"http://kube-prometheus-kube-prome-prometheus.monitoring:9090/graph?g0.expr=100+%2A+%28count+by+%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by+%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\u0026g0.tab=1",
         "fingerprint":"65b77eed2fe8b9c7"
      }
   ],
   "groupLabels":{
      "namespace":"kube-system"
   },
   "commonLabels":{
      "alertname":"TargetDown",
      "job":"kube-proxy",
      "namespace":"kube-system",
      "prometheus":"monitoring/kube-prometheus-kube-prome-prometheus",
      "service":"kube-prometheus-kube-prome-kube-proxy",
      "severity":"warning"
   },
   "commonAnnotations":{
      "description":"100% of the kube-proxy/kube-prometheus-kube-prome-kube-proxy targets in kube-system namespace are down.",
      "runbook_url":"https://runbooks.prometheus-operator.dev/runbooks/general/targetdown",
      "summary":"One or more targets are unreachable."
   },
   "externalURL":"http://kube-prometheus-kube-prome-alertmanager.monitoring:9093",
   "version":"4",
   "groupKey":"{}:{namespace=\"kube-system\"}",
   "truncatedAlerts":0
}

まとめ

Alertmanagerのwebhookをnginxに連携して、アラートの内容をログから確認できるようにしてみました。