PrometheusメトリクスによるPodの水平スケール
はじめに
Prometheusを活用して何らかのメトリクスを取得し、必要に応じてPodを自動的にスケールさせたいケースがあるかと思います。今回は、Prometheusとsidekiq-exporterを用いて、Redisの待機中のジョブの数を取得し、ジョブが多ければPodを水平スケール(HPA)させるようにします。
Prometheus on Kubernetes & HPAのアーキテクチャ
Prometheusは複数のコンポーネントによって成り立っています。今回はわかりやすくするために図を省略しており、厳密には以下の画像より多くのリソースが存在します。
prometheus-operaterの以下の図が理解しやすいと思います。
1. Redisとsidekiq-exporterを接続する
exporterの導入は至って簡単です。以下のようにDeploymentを作成します。REDIS_URLはElasticCache for Redisのエンドポイントとします。
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: sidekiq
name: sidekiq-exporter
spec:
selector:
matchLabels:
app: sidekiq-exporter
replicas: 1
template:
metadata:
labels:
app: sidekiq-exporter
name: sidekiq-exporter
spec:
containers:
- name: sidekiq-exporter
image: strech/sidekiq-prometheus-exporter:latest
env:
- name: REDIS_URL
valueFrom:
secretKeyRef:
name: sidekiq-exporter-secret
key: redis_url
ports:
- name: exporter
containerPort: 9292
また、Prometheusがexporterからメトリクスを取得できるようにServiceとServiceMonitorを作成します。ServiceMonitorは、prometheus-operatorによって提供されるカスタムリソース定義(CRD)であり、サービスオブジェクトでEndpointsを検出し、PrometheusがこれらのPodを監視するように設定します。
apiVersion: v1
kind: Service
metadata:
namespace: sidekiq
name: sidekiq-exporter-service
labels:
app: sidekiq-exporter
spec:
selector:
app: sidekiq-exporter
ports:
- name: exporter
port: 9292
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
namespace: sidekiq
name: sidekiq-exporter-service-monitor
spec:
selector:
matchLabels:
app: sidekiq-exporter
endpoints:
- port: exporter
sidekiq-exporterがRedisと接続できているか確認します。ポートフォワードを使ってsidekiq-exporterのPodをローカルに転送します。
kubectl port-forward -n sidekiq <redis-exporterのPod> 8080:9292
curlコマンドでメトリクスが表示されると接続は上手くいっています。
curl -s localhost:8080/metrics
2. prometheus-operaterの導入
prometheus-operatorはPrometheusおよび、その関連ツール(AlertmanagerやGrafana etc)をKubernetesリソースとして管理することができます。今回は必要なものだけインストールしていきます。
・
・
spec:
project: default
source:
repoURL: https://github.com/prometheus-community/helm-charts.git
path: charts/kube-prometheus-stack/crds/
targetRevision: kube-prometheus-stack-37.0.0
destination:
server: 'https://kubernetes.default.svc'
namespace: default
syncPolicy:
automated:
prune: true
syncOptions:
- Replace=true
---
・
・
spec:
project: default
source:
repoURL: 'https://prometheus-community.github.io/helm-charts'
targetRevision: 37.0.0
helm:
skipCrds: true
values: |
alertmanager:
enabled: false
grafana:
enabled: false
kubeApiServer:
enabled: false
kubelet:
enabled: false
kubeControllerManager:
enabled: false
coreDns:
enabled: false
kubeDns:
enabled: false
kubeEtcd:
enabled: false
kubeScheduler:
enabled: false
kubeProxy:
enabled: false
kubeStateMetrics:
enabled: false
nodeExporter:
enabled: false
prometheusOperator:
admissionWebhooks:
enabled: false
patch:
enabled: false
prometheus:
prometheusSpec:
serviceMonitorSelectorNilUsesHelmValues: false
serviceMonitorNamespaceSelector: {}
serviceMonitorSelector: {}
chart: kube-prometheus-stack
destination:
server: 'https://kubernetes.default.svc'
namespace: default
syncPolicy:
automated:
prune: true
syncOptions:
- Replace=true
以下でPrometheusのコンソール画面が表示できると思います。sidekiq-exporterがUpになっていれば大丈夫です。
kubectl port-forward prometheus-prometheus-operator-kube-p-prometheus-0 8000:9090
3. prometheus-adapterがPrometheusからメトリクスを取得し、APIとして使えるようにする
・
・
spec:
project: default
source:
repoURL: 'https://prometheus-community.github.io/helm-charts'
targetRevision: 3.0.0
helm:
values: |
rules:
default: false
custom:
- seriesQuery: 'sidekiq_enqueued_jobs{namespace!="",service!=""}'
resources:
overrides:
namespace:
resource: namespace
service:
resource: service
name:
as: sidekiq_enqueued_jobs
metricsQuery: '<<.Series>>{<<.LabelMatchers>>}'
prometheus:
url: http://prometheus-operator-kube-p-prometheus.default
logLevel: 2
chart: prometheus-adapter
destination:
server: 'https://kubernetes.default.svc'
namespace: default
以下のコマンドを打って表示されれば大丈夫です。
kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1/namespaces/sidekiq/services/sidekiq-exporter-service/sidekiq_enqueued_jobs | jq .
4. custom.metrics.k8s.io APIを使ってHPAする
カスタムメトリクスAPIに登録したsidekiq_enqueued_jobsの値に応じてPodの数をコントロールすることができます。metrics.object.target.valueで閾値を設定します。以下の設定で待機中のジョブが1つ以上になるとPodが水平スケールするようになります。
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: hpa
namespace: sidekiq
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: <水平スケーツの対象>
minReplicas: 1
maxReplicas: 2
metrics:
- type: Object
object:
describedObject:
apiVersion: v1
kind: Service
name: sidekiq-exporter
metric:
name: sidekiq_enqueued_jobs
target:
type: Value
value: 1
参考文献
sidekiq-exporter
prometheus-operater
prometheus-adapter
Horizontal Pod Autoscaling (HPA)
その他
Discussion