---
title: Tanzu Kubernetes GridのPrometheus Packageでremote-write-receiverとagent modeをセットアップして複数のKubernetesクラスタを監視する
tags: ["Kubernetes", "TKG", "Tanzu", "Prometheus", "TAP"]
categories: ["Dev", "CaaS", "Kubernetes", "TKG"]
date: 2023-09-01T09:51:31Z
updated: 2023-09-02T08:54:57Z
---

複数のKubernetesをPrometheusで監視したい時、見る側は一箇所に集約したいと思うことが多いと思います。

[Federation](https://prometheus.io/docs/prometheus/latest/federation/)だと、次の図のように、各Prometheusが自分のクラスタのデータを貯めつつ、集約Prometheusで全クラスタのデータを貯めることになるのでデータサイズ的に無駄が多くなります。

<img width="1171" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/4434c237-eaa2-4fe0-bc09-380e54b64396">


下の図のように、集約側のPrometheusで[remote-write](https://prometheus.io/docs/prometheus/latest/storage/#overview)を受付け、その他のPrometheusは[agent mode](https://prometheus.io/docs/prometheus/latest/feature_flags/#prometheus-agent)でデータを貯めずに集約側に送るようにすれば無駄なく複数Prometheusを監視できます。Federationにもメリットはあると思いますが、複数クラスタを監視する場合はこちらの構成をイメージすることが多いと思います。

<img width="1165" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/dc0babb3-3ebb-4190-9a0c-d952f167a63f">

この構成を[Tanzu Kubernetes Gridのパッケージ](https://docs.vmware.com/en/VMware-Tanzu-Kubernetes-Grid/2.3/using-tkg/workload-packages-prometheus.html)を使って構築します。

### 集約Prometheusのセットアップ
まずは共有Kubernetesクラスタで集約Prometheusをセットアップします。

以下のパッケージがインストールされていることが前提です

* [cert-manager パッケージ](https://docs.vmware.com/en/VMware-Tanzu-Kubernetes-Grid/2.3/using-tkg/workload-packages-cert-mgr.html)
* [contour パッケージ](https://docs.vmware.com/en/VMware-Tanzu-Kubernetes-Grid/2.3/using-tkg/workload-packages-contour.html)

> ℹ️ TKG以外のkubernetesで試したい場合は[こちらの記事](/entries/760)を参考にしてください


次のYAMLを作成します。Prometheusの起動オプションに`--web.enable-remote-write-receiver`を追加するところがポイントです。
各メトリクスがどのクラスタから送られてきたかを区別するために`cluster`というラベルを追加しています。次の設定ファイルでは`orbstack`となっているので、自環境に合わせて置換してください。
また`ingress.virtual_host_fqdn`も自環境の値に変更してください。

```yaml
cat <<'EOF' > prometheus-values.yaml
---
ingress:
  enabled: true
  virtual_host_fqdn: prometheus.192-168-194-146.sslip.io
prometheus:
  deployment:
    containers:
      args:
      - --storage.tsdb.retention.time=42d
      - --config.file=/etc/config/prometheus.yml
      - --storage.tsdb.path=/data
      - --web.console.libraries=/etc/prometheus/console_libraries
      - --web.console.templates=/etc/prometheus/consoles
      - --web.enable-lifecycle
      - --enable-feature=exemplar-storage
      - --web.enable-remote-write-receiver
  config:
    prometheus_yml: |
      global:
        evaluation_interval: 1m
        scrape_interval: 1m
        scrape_timeout: 10s
      rule_files:
      - /etc/config/alerting_rules.yml
      - /etc/config/recording_rules.yml
      - /etc/config/alerts
      - /etc/config/rules
      scrape_configs:
      - job_name: 'prometheus'
        scrape_interval: 5s
        static_configs:
        - targets: [ 'localhost:9090' ]
          labels:
            cluster: orbstack
      - job_name: 'kube-state-metrics'
        static_configs:
        - targets: [ 'prometheus-kube-state-metrics.tanzu-system-monitoring.svc.cluster.local:8080' ]
          labels:
            cluster: orbstack
      - job_name: 'kubernetes-pods'
        kubernetes_sd_configs:
        - role: pod
        relabel_configs:
        - source_labels: [ __meta_kubernetes_pod_annotation_prometheus_io_scrape ]
          action: keep
          regex: true
        - source_labels: [ __meta_kubernetes_pod_annotation_prometheus_io_path ]
          action: replace
          target_label: __metrics_path__
          regex: (.+)
        - source_labels: [ __address__, __meta_kubernetes_pod_annotation_prometheus_io_port ]
          action: replace
          regex: ([^:]+)(?::\d+)?;(\d+)
          replacement: $1:$2
          target_label: __address__
        - action: labelmap
          regex: __meta_kubernetes_pod_label_(.+)
        - source_labels: [ __meta_kubernetes_namespace ]
          action: replace
          target_label: kubernetes_namespace
        - source_labels: [ __meta_kubernetes_pod_name ]
          action: replace
          target_label: kubernetes_pod_name
        - source_labels: [ ]
          target_label: cluster
          replacement: orbstack
      - job_name: kubernetes-nodes-cadvisor
        kubernetes_sd_configs:
        - role: node
        relabel_configs:
        - action: labelmap
          regex: __meta_kubernetes_node_label_(.+)
        - replacement: kubernetes.default.svc:443
          target_label: __address__
        - regex: (.+)
          replacement: /api/v1/nodes/$1/proxy/metrics/cadvisor
          source_labels:
          - __meta_kubernetes_node_name
          target_label: __metrics_path__
        - source_labels: [ ]
          target_label: cluster
          replacement: orbstack
        scheme: https
        tls_config:
          ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
          insecure_skip_verify: true
        bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
      - job_name: kubernetes-apiservers
        kubernetes_sd_configs:
        - role: endpoints
        relabel_configs:
        - action: keep
          regex: default;kubernetes;https
          source_labels:
          - __meta_kubernetes_namespace
          - __meta_kubernetes_service_name
          - __meta_kubernetes_endpoint_port_name
        - source_labels: [ ]
          target_label: cluster
          replacement: orbstack
        scheme: https
        tls_config:
          ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
          insecure_skip_verify: true
        bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
      alerting:
        alertmanagers:
        - scheme: http
          static_configs:
          - targets:
            - alertmanager.tanzu-system-monitoring.svc:80
        - kubernetes_sd_configs:
          - role: pod
          relabel_configs:
          - source_labels: [ __meta_kubernetes_namespace ]
            regex: default
            action: keep
          - source_labels: [ __meta_kubernetes_pod_label_app ]
            regex: prometheus
            action: keep
          - source_labels: [ __meta_kubernetes_pod_label_component ]
            regex: alertmanager
            action: keep
          - source_labels: [ __meta_kubernetes_pod_annotation_prometheus_io_probe ]
            regex: .*
            action: keep
          - source_labels: [ __meta_kubernetes_pod_container_port_number ]
            regex:
            action: drop
EOF
```

次のコマンドでインストールします。

```
tanzu package install -n tkg-system -p prometheus.tanzu.vmware.com -v 2.43.0+vmware.2-tkg.1 --values-file prometheus-values.yaml prometheus 
```

```
$ kubectl get pod,httpproxy -n tanzu-system-monitoring -o wide
NAME                                                 READY   STATUS    RESTARTS   AGE   IP               NODE       NOMINATED NODE   READINESS GATES
pod/prometheus-node-exporter-2qjmj                   1/1     Running   0          55s   192.168.194.48   orbstack   <none>           <none>
pod/prometheus-kube-state-metrics-7d4b54447c-5m7vs   1/1     Running   0          53s   192.168.194.50   orbstack   <none>           <none>
pod/prometheus-pushgateway-5f6d8695d4-w4f5w          1/1     Running   0          53s   192.168.194.52   orbstack   <none>           <none>
pod/alertmanager-85796b8bc9-6dlbk                    1/1     Running   0          54s   192.168.194.53   orbstack   <none>           <none>
pod/prometheus-server-5f784b75fd-kpf4d               2/2     Running   0          53s   192.168.194.54   orbstack   <none>           <none>

NAME                                               FQDN                                  TLS SECRET       STATUS   STATUS DESCRIPTION
httpproxy.projectcontour.io/prometheus-httpproxy   prometheus.192-168-194-146.sslip.io   prometheus-tls   valid    Valid HTTPProxy
```


`ingress.virtual_host_fqdn` に指定したURLにアクセスするとPrometheusのUIが表示されます。

<img width="1912" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/1b64fbe7-3e57-46d8-84aa-aaf4a6aa61a0">

`--web.enable-remote-write-receiver`フラグが有効になっていることを確認します。

<img width="1912" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/9315bfa6-35ae-43b1-b43c-1310575f4c1a">

各メトリクスに`cluster`ラベルがついていることを確認します。

<img width="1912" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/87d3cc81-2aaf-4cfd-8706-adda40561502">

<img width="1912" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/92b499e0-fc11-4ab8-864e-7ee06dbc6837">


### agent modeのPrometheusのセットアップ

次にその個々のKubernetes側でagent modeのPrometheusをセットアップします。 前提となるパッケージはありません。


次のYAMLを作成します。Prometheusの起動オプションに`--enable-feature=agent`を追加するところがポイントです。
また`prometheus.yaml`の`remote_write`で集約PrometheusのURLを設定します。`global.external_labels`でremote write時に追加するlabelを指定できます。
ここではクラスタ名として`cluster`ラベルに`kind`を設定しています。自環境に合わせて修正してください。agent modeの場合は`prometheus.yaml`にalertの設定ができないので、設定を削除します。

PVCは不要ですが、Tanzu Packageだとvalues fileで無効にできないので小さいサイズを設定します。
同じくAlertManagerやPush Gatewayも不要ですが、values fileで無効にできないのでreplica数を0にしておきます。

```yaml

cat <<'EOF' > prometheus-agent-values.yaml
---
prometheus:
  deployment:
    containers:
      args:
      - --config.file=/etc/config/prometheus.yml
      - --enable-feature=exemplar-storage
      - --enable-feature=agent
      - --storage.agent.retention.max-time=5m
  pvc:
    storage: 1Gi
  config:
    prometheus_yml: |
      global:
        evaluation_interval: 1m
        scrape_interval: 1m
        scrape_timeout: 10s
        external_labels:
          cluster: kind
      remote_write:
      - url: https://prometheus.192-168-194-146.sslip.io/api/v1/write
        send_exemplars: true
        tls_config:
          insecure_skip_verify: true
      scrape_configs:
      - job_name: 'prometheus'
        scrape_interval: 5s
        static_configs:
        - targets: [ 'localhost:9090' ]
      - job_name: 'kube-state-metrics'
        static_configs:
        - targets: [ 'prometheus-kube-state-metrics.tanzu-system-monitoring.svc.cluster.local:8080' ]
      - job_name: 'kubernetes-pods'
        kubernetes_sd_configs:
        - role: pod
        relabel_configs:
        - source_labels: [ __meta_kubernetes_pod_annotation_prometheus_io_scrape ]
          action: keep
          regex: true
        - source_labels: [ __meta_kubernetes_pod_annotation_prometheus_io_path ]
          action: replace
          target_label: __metrics_path__
          regex: (.+)
        - source_labels: [ __address__, __meta_kubernetes_pod_annotation_prometheus_io_port ]
          action: replace
          regex: ([^:]+)(?::\d+)?;(\d+)
          replacement: $1:$2
          target_label: __address__
        - action: labelmap
          regex: __meta_kubernetes_pod_label_(.+)
        - source_labels: [ __meta_kubernetes_namespace ]
          action: replace
          target_label: kubernetes_namespace
        - source_labels: [ __meta_kubernetes_pod_name ]
          action: replace
          target_label: kubernetes_pod_name
      - job_name: kubernetes-nodes-cadvisor
        kubernetes_sd_configs:
        - role: node
        relabel_configs:
        - action: labelmap
          regex: __meta_kubernetes_node_label_(.+)
        - replacement: kubernetes.default.svc:443
          target_label: __address__
        - regex: (.+)
          replacement: /api/v1/nodes/$1/proxy/metrics/cadvisor
          source_labels:
          - __meta_kubernetes_node_name
          target_label: __metrics_path__
        scheme: https
        tls_config:
          ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
          insecure_skip_verify: true
        bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
      - job_name: kubernetes-apiservers
        kubernetes_sd_configs:
        - role: endpoints
        relabel_configs:
        - action: keep
          regex: default;kubernetes;https
          source_labels:
          - __meta_kubernetes_namespace
          - __meta_kubernetes_service_name
          - __meta_kubernetes_endpoint_port_name
        scheme: https
        tls_config:
          ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
          insecure_skip_verify: true
        bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
alertmanager:
  deployment:
    replicas: 0
pushgateway:
  deployment:
    replicas: 0
EOF
```

次のコマンドでインストールします。


```
tanzu package install -n tkg-system -p prometheus.tanzu.vmware.com -v 2.43.0+vmware.2-tkg.1 --values-file prometheus-agent-values.yaml prometheus 
```

```
$ kubectl get pod -n tanzu-system-monitoring                                                         
NAME                                            READY   STATUS    RESTARTS   AGE
prometheus-kube-state-metrics-c7f4d6f6f-j4vfj   1/1     Running   0          4m34s
prometheus-node-exporter-xzw7d                  1/1     Running   0          4m34s
prometheus-server-6b98c76645-zz69b              2/2     Running   0          3m18s
```

次のコマンドでprometheusのUIをポートフォワードします。

```
kubectl port-forward -n tanzu-system-monitoring svc/prometheus-server 9090:8
```

UIにアクセスすると"Prometheus Agent"と表示されているので、agent modeとして起動していることがわかります。

<img width="1912" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/bba7b56d-3fb5-436a-8c65-77fb3a600c15">

集約PrometheusのUIで `sum(kube_pod_info) by (cluster, namespace)` を取得します。次のようにnamespace単位でのpod数が**cluster毎に**出力されればセットアップ成功です。

<img width="1912" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/76e08a30-780f-4e83-a3b8-b7ae5039e358">

---

Grafanaのダッシュボードも`cluster`ラベルで検索できるようにカスタマイズする必要がありますが、本記事では割愛します。

Tanzu Application Platformのマルチクラスタ構成をPrometheusで監視したい場合は、この構成にすると良いでしょう。
