概要
PrometheusはPull型の監視ツールであるため、監視対象がどれかを教えてあげなければいけません。
これまでの記事は全てstatic_configs
を用いた静的な値で、スケールした時やサービスが増減した時に柔軟性がありません。
PrometheusはServiceDiscoveryを指定することで動的にターゲットを検知できるのでそれを用います。
環境
- Prometheus 2.11.1
- Kubernetes 1.10.11
利用できるService Discoveryは?
Configuration | Prometheus に対応しているSD一覧があります。
主に使いそうなのは以下でしょうか。
- File
- Consul
- DNS
- Kubernetes
- EC2
- Azure
- GCE
Kubernetesの例
今回はKubernetesを用いた方法を説明します。
ロール(ServiceDiscoveryの種類)
PrometheusはKubernetesAPIを用いてターゲットを探します。
Prometheusで使えるKubernetesのSDは以下の5種類があります。
ロール | 何ができるか |
---|---|
node | クラスタを構成するノードを検出 kubeletをスクレイプする |
endpoints | Serviceにぶら下がったPodを検出 |
service | Serviceに見えるがロードバランシングされるのでPod検出には向かない サービスが応答するかのブラックボックスモニタリングに向く |
pod | Serviceに繋がっていないPodも含め全てのPodを検出 |
ingress | ingressはクラスタ外にKubernetes Serviceを公開するのでserviceロールと同じように使う |
よく使うであろうロールは
- node
- endpoints or pod
です。後者はメトリクス取得したい全てのPodはServiceに紐付けるというインフラ上のローカルルールがあればendpointsロールを使用しますし、そうでなければpodロールを使用することになります。
nodeロール
nodeロールを用いてクラスタのノードを検出してみます。
kubletをスクレイプするのでHTTPSである必要があり、TLSなどの設定も必要です。
ただ現在のDocker for Mac Kubernetesの場合TLS周りが上手く行かないのでinsecure_skip_verify: true
が必要です。
scrape_configs: - job_name: 'kubernetes-nodes' kubernetes_sd_configs: - role: node 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
ServiceDiscovery結果
ちゃんと監視対象として認識されてTarget Labelが登録されてます。
Targets結果
/metrics
からメトリクスを取得できていることが分かります。
cAdvisor
kubeletは/metrics/cadvisor
にて各Podのコンテナ用メトリクスを公開しています。
なのでmetrics_path: /metrics/cadvisor
を設定することでcAdvisorのメトリクスを取得できるようになります。
- job_name: 'cadvisor' kubernetes_sd_configs: - role: node 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 metrics_path: /metrics/cadvisor
Targets結果
/metrics/cadvisor
からメトリクスを取得できていることが分かります。
Grafanaで見てみる
各PodのCPU使用率が出てますね。
endpointsロール
kube-apiserverのServiceを除く全てのServiceを対象にします。
scrape_configs: - job_name: 'kubernetes-service-endpoints' kubernetes_sd_configs: - role: endpoints relabel_configs: - source_labels: - __meta_kubernetes_namespace - __meta_kubernetes_service_name regex: default;kubernetes action: drop - source_labels: - __meta_kubernetes_namespace - __meta_kubernetes_pod_container_port_number regex: default;9100 action: keep - source_labels: - __meta_kubernetes_service_name target_label: job - source_labels: - __meta_kubernetes_pod_name target_label: pod
数行毎に説明していきます。
kube-apiserverのServiceを取り除く
- source_labels: - __meta_kubernetes_namespace - __meta_kubernetes_service_name regex: default;kubernetes action: drop
ここではkube-apiserverのServiceを取り除くため、
__meta_kubernetes_namespace
がdefault
かつ
__meta_kubernetes_service_name
がkubernetes
のものをaction: drop
しています。
特定のnamespace, portのものを残す
今回各サーバは9100に/metrics
をexposeしているので、そのサーバのみ監視対象にします。
- source_labels: - __meta_kubernetes_namespace - __meta_kubernetes_pod_container_port_number regex: default;9100 action: keep
jobラベルを書き換える
jobラベルをService名に書き換えています。
- source_labels: - __meta_kubernetes_service_name target_label: job
podラベルを追加する
podラベルを追加し、pod名をセットしています。
- source_labels: - __meta_kubernetes_pod_name target_label: pod
ServiceDiscovery結果
ちゃんと監視対象として認識されてTarget Labelが登録されてます。
action: drop
にしたものはフィルタされてます。
Targets結果
各Podが認識されてます。
動作検証
Podの数を変えて動的にTargetsが変化するか見てみます。
スケールアウトさせてみる
replicas: 1
->replicas: 3
にしてみます。
増えました。
スケールインさせてみる
replicas: 3
->replicas: 1
に戻します。
減りました。
annotationベースでservice discovery
先ほどは元から存在するラベルでサービスを検知していました。
しかしmanifest側(Deployment, Service, Pod)でこれは検知してほしい、これは検知してほしくない、といった区別もしたいです。
そういった場合はannotationを使って判別します。
scrape_configs側
- job_name: 'kubernetes-service-endpoints' kubernetes_sd_configs: - role: endpoints relabel_configs: - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__meta_kubernetes_endpoint_port_name] action: keep regex: metrics - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] action: replace target_label: __metrics_path__ regex: (.+) - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] action: replace regex: ([^:]+)(:\d+)?;(\d+) replacement: ${1}:${3} target_label: __address__
条件は上から
- Serviceに
annotation.prometheus.io/scrape: true
を持つ - Serviceのport名が
metrics
です。
加えてpathやportをService側で自由に設定しても良いようにreplace処理を入れています。
service側
gateway, backendと2つのdeploymentの内、backendの方のみannotationを付けるようにします。
apiVersion: v1 kind: Service metadata: name: backend-svc annotations: prometheus.io/scrape: 'true' prometheus.io/port: '9101' spec: type: ClusterIP ports: - name: app protocol: TCP port: 10000 targetPort: 8080 - name: metrics protocol: TCP port: 10001 targetPort: 9101 selector: app: backend-service
prometheus.io/port
をtargetPort
にあわせることで、デフォルトの9100
ポート以外も指定できるようになります。
動作確認
先ほどはgatewayのpodも検知されていたのに対し、今回はgatewayが含まれなくなりました。
- prometheus.io/scrape
- prometheus.io/path
- prometheus.io/port
のannotationは色んなアプリケーションで共通的に使われているので、今回corednsも含まれていました。
まとめ
Prometheusの監視対象をServiceDiscoveryにすることで動的に監視対象を検知することができました。
サンプルコード
今回のサンプルコードはこちらです。
通常↓
annotationベース↓