Prometheus を CDK でインストールして Recording rules で集計したデータを New Relic に Remote write することでデータ量を節約する
awskubernetesnewrelicprometheusPrometheus の Recording rules は PromQL で既存のメトリクスから新たなメトリクスを作ることができる機能。これによって集計したデータを送ることで生のデータを送るのと比べて New Relic へのデータ送信量を節約することができるが、newrelic-bundle に含まれる newrelic-prometheus-configurator の Prometheus は Agent mode で動くので Recording rules に対応していない。
CDKでEKSクラスタにnewrelic-bundleをインストールしてモニタリングする - sambaiz-net
そこで Helm で自前の Prometheus をインストールして Remote write する。
cluster.addHelmChart('PrometheusOperatorChart', {
release: 'kube-prometheus-stack',
chart: 'kube-prometheus-stack',
repository: 'https://prometheus-community.github.io/helm-charts',
version: '59.1.0',
namespace: 'prometheus',
createNamespace: true,
values: {
defaultRules: {
create: false,
},
prometheus: {
enabled: true,
prometheusSpec: {
storageSpec: {
volumeClaimTemplate: {
spec: {
resources: {
requests: {
storage: '30Gi',
},
},
},
},
},
retention: '7d',
retentionSize: '25GB',
remoteWrite: [{
url: 'https://metric-api.newrelic.com/prometheus/v1/write?prometheus_server=prometheus',
authorization: {
type: 'Bearer',
credentials: {
key: secretKey,
name: secretName,
}
},
writeRelabelConfigs: [
{
sourceLabels: ['aaaa'],
separator: ';',
regex: 'bbbb',
action: 'keep',
},
],
}],
},
},
nodeExporter: {
enabled: false,
},
alertmanager: {
enabled: false,
},
grafana: {
enabled: false,
},
},
})
これをインストールすると Prometheus などの CRD を介して Prometheus server が立ち上がる。Operator を用いない Chart もあるが、 extraScrapeConfigs が文字列なのでインデントが正しくないとエラーになって設定しづらかったりするのと、Operator には各種 CRD によってアプリケーション側での必要に応じて Prometheus server を立ち上げたりスクレイピングの設定を行いやすいという利点がある。
const extraScrapeConfigs =
`- job_name: newrelic-pods
honor_timestamps: true
scrape_interval: 30s
scrape_timeout: 10s
...`
デフォルトで Alertmanager なども立ち上がるが、今回は使わないので無効化している。
Service|PodMonitor でスクレイピングする targets の設定ができ、 PrometheusRule で Recording rules を設定できる。メトリクス名は level:metric:operations の形式にする。
podMonitorSelectorNilUsesHelmValues がデフォルトの true のとき、 service|podMonitorSelector が matchLabels: release: になるため、このラベルを付けないと configuration に読み込まれない。configuration に読み込まれているが targets に出ない場合 selector などの値が正しいかを確認する。podMetricsEndpoints の port は名前しか渡すことができず、番号は __meta_kubernetes_pod_container_port_number に対応する targetPort で渡す必要がある。
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: testapp-monitor
namespace: prometheus
labels:
release: kube-prometheus-stack
spec:
selector:
matchLabels:
app: testapp
namespaceSelector:
matchNames:
- testapp
podMetricsEndpoints:
- port: monitor
path: /metrics
interval: 5m
scrapeTimeout: 10s
---
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: example
namespace: prometheus
labels:
release: kube-prometheus-stack
spec:
groups:
- name: example
interval: 5m
rules:
- record: code:prometheus_http_requests_total:sum
expr: sum by (code) (prometheus_http_requests_total)
labels:
aaaa: bbbb
Prometheus server にポートフォワードして PromQL で Recording rules のメトリクスを取得してみる。
$ kubectl -n prometheus port-forward svc/prometheus-server 9090:80
Forwarding from 127.0.0.1:9090 -> 9090
Forwarding from [::1]:9090 -> 9090
$ curl -G 'http://localhost:9090/api/v1/query' --data-urlencode 'query=code:prometheus_http_requests_total:sum' | jq
{
"status": "success",
"data": {
"resultType": "vector",
"result": [
{
"metric": {
"__name__": "code:prometheus_http_requests_total:sum",
"aaaa": "bbbb",
"code": "200"
},
"value": [
1716339421.309,
"182"
]
},
{
"metric": {
"__name__": "code:prometheus_http_requests_total:sum",
"aaaa": "bbbb",
"code": "302"
},
"value": [
1716339421.309,
"2"
]
}
]
}
}
New Relic にも送られていることが確認できる。
FROM Metric
SELECT latest(`code:prometheus_http_requests_total:sum`)
WHERE prometheus_server = 'prometheus' FACET code