NewRelic の Kubernetes Integration の各種コンポーネントをまとめた nri-bundle という Helm Chart が提供されており、Guided install を進めると渡すパラメータが生成されるのでこれを CDK に書き写した。
Chart を見ると認証情報はそのまま文字列で渡すほか Secret を指定することもできたので、External Secrets で SecretsManager から取り込む。
const newrelicNamespace = cluster.addManifest('newrelic-namespace', {
apiVersion: 'v1',
kind: 'Namespace',
metadata: {
name: 'newrelic'
}
})
const secretName = 'newrelic-bundle-secret'
const newrelicBundleSecret = cluster.addManifest('NewrelicBundleSecret', {
apiVersion: 'external-secrets.io/v1beta1',
kind: 'ExternalSecret',
metadata: {
name: secretName,
namespace: 'newrelic'
},
spec: {
refreshInterval: '1h',
secretStoreRef: {
name: 'secretsmanager',
kind: 'ClusterSecretStore'
},
data: [{
secretKey: 'newrelic-license-key',
remoteRef: {
key: secretName,
property: 'newrelic-license-key'
}
}, {
secretKey: 'pixie-api-key',
remoteRef: {
key: secretName,
property: 'pixie-api-key'
}
}, {
// key of the deploy key is "deploy-key".
// https://github.com/pixie-io/pixie/blob/release/vizier/v0.14.8/k8s/operator/helm/values.yaml#L37
secretKey: 'deploy-key',
remoteRef: {
key: secretName,
property: 'pixie-deploy-key'
}
}]
}
})
newrelicBundleSecret.node.addDependency(newrelicNamespace)
newrelicBundleSecret.node.addDependency(secretStore)
現状、Pixie のバージョンが古く ARM インスタンスで動かすとエラーになる。PRは出ている。
const newrelicBundle = cluster.addHelmChart('newrelic-bundle', {
chart: 'nri-bundle',
release: 'newrelic-bundle',
repository: 'https://helm-charts.newrelic.com',
namespace: 'newrelic',
createNamespace: false,
values: {
global: {
customSecretName: secretName,
customSecretLicenseKey: 'newrelic-license-key',
cluster: cluster.clusterName,
lowDataMode: true,
},
"newrelic-infrastructure": {
privileged: true,
},
"kube-state-metrics": {
enabled: true,
image: {
tag: "v2.10.0"
}
},
"kubeEvents": {
enabled: true,
},
"newrelic-prometheus-agent": {
enabled: true,
lowDataMode: true,
config: {
kubernetes: {
integrations_filter: {
enabled: true,
}
}
},
},
"newrelic-logging": {
enabled: true,
lowDataMode: true,
fluentBit: {
// excluding pods by adding the annotation fluentbit.io/exclude: "true"
k8sLoggingExclude: true
}
},
"newrelic-pixie": {
enabled: true,
customSecretApiKeyName: secretName,
customSecretApiKeyKey: "pixie-api-key"
},
"pixie-chart": {
enabled: true,
customDeployKeySecret: secretName,
clusterName: cluster.clusterName,
}
},
wait: false
})
newrelicBundle.node.addDependency(newrelicBundleSecret)
インストールするとコンテナやノードレベルのメトリクスやログに加えeventsなども確認できる。
また、Linuxカーネル内のサンドボックスでネットワークなどのイベントによって動く eBPF プログラムでデータを収集する Pixie によってサービスマップや通信量などが可視化され、
アプリケーションのフレームグラフも見ることができる。
Pixie の PxL script で Kubernetes クラスタでの通信を取得する - sambaiz-net
newrelic-prometheus-agent は Agent mode で Prometheus を動かして Exporter から取得したメトリクスを New Relic に remote_write するコンポーネント。クエリやアラート、Recording rules は使えない。
Prometheus の Recording rules で集計したデータを New Relic に Remote write してデータ送信量を節約する - sambaiz-net
$ kubectl port-forward -n newrelic $(kubectl get pod -n newrelic -l app.kubernetes.io/name=newrelic-prometheus-agent -o jsonpath="{.items[0].metadata.name}") 9090:9090
Forwarding from 127.0.0.1:9090 -> 9090
Forwarding from [::1]:9090 -> 9090
$ curl -G 'http://localhost:9090/api/v1/query' --data-urlencode 'query=up' | jq
{
"status": "error",
"errorType": "execution",
"error": "unavailable with Prometheus Agent"
}
Exporter の Service discovery は Kubernetes の API を呼んで scrape_configs の kubernetes_sd_configs に対応するリソースを取得することで行われる。source_labels を separator で繋げた文字列と regex と比較し action が keep ならそれに合致しないものが drop され、replace なら target_label に replacement の値を設定する。つまり Pod に newrelic.io/scrape: true annotaion を付けると /metrics が返す Prometheus メトリクスが送られるようになる。
# /etc/prometheus/config/config.yaml
...
scrape_configs:
...
- job_name: newrelic-pod
honor_timestamps: true
scrape_interval: 30s
scrape_timeout: 10s
metrics_path: /metrics
scheme: http
follow_redirects: true
enable_http2: true
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_newrelic_io_scrape]
separator: ;
regex: "true"
replacement: $1
action: keep
- source_labels: [__meta_kubernetes_pod_phase]
separator: ;
regex: Pending|Succeeded|Failed|Completed
replacement: $1
action: drop
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme]
separator: ;
regex: (https?)
target_label: __scheme__
replacement: $1
action: replace
...
kubernetes_sd_configs:
- role: pod
kubeconfig_file: ""
follow_redirects: true
enable_http2: true
...
remote_write:
- url: https://metric-api.newrelic.com/prometheus/v1/write?collector_name=prometheus-agent&collector_version=1.11.0&prometheus_server=newrelic-bundle-newrelic-prometheus-agent-0
remote_timeout: 30s
write_relabel_configs:
- source_labels: [__name__]
separator: ;
regex: kube_.+|container_.+|machine_.+|cadvisor_.+
replacement: $1
action: drop
- source_labels: [__name__]
separator: ;
regex: timeseries_write_(.*)
target_label: newrelic_metric_type
replacement: counter
action: replace
- source_labels: [__name__]
separator: ;
regex: sql_byte(.*)
target_label: newrelic_metric_type
replacement: counter
action: replace
name: newrelic_rw
authorization:
type: Bearer
credentials: <secret>
...
送られたメトリクスは FROM Metric の同名のフィールドで参照できる。 ただし、Prometheus の Counter は累積和を返すのに対して New Relic の Count はデルタ値なので変換される。
/* container_memory_usage_bytes{id="/"} */
FROM Metric SELECT latest(container_memory_usage_bytes) WHERE id = '/' TIMESERIES