じゃあ、おうちで学べる

本能を呼び覚ますこのコードに、君は抗えるか

PrometheusのSLO generator であるSloth について雑多な作業ログ入門失敗編

はじめに

このブログではPrometheusSLO generator であるSloth に関して取り上げたいと思っている。正直、業務後の深夜に書いているのでGrafana でDashboards を生成したら感動的なラストシーンということにしてほしい。今回は取り上げないが最近、バージョン1.0.0 になったOpenSLOの 周辺知識も気になっている。OpenSLOについて | フューチャー技術ブログ などはOpenSLOに関して2022 年5月現在で日本語で書かれている文章だと最高に良いと思います。

SLIを計測しSLOを設定する

いきなり、Slothの話をするのも流石に不親切なのでSRE的な話を少しだけします。ITサービスの運用に置いて、信頼性100%と、信頼性99.99%では大きな違いがあります。信頼性100%を実現するためには、99.99%とは異なり膨大な工数を投入する必要があるが、ほとんどのユーザーにとっては「99.999%」が「100%」になったからといって、大きなメリットがないことのほうが多いのである。つまり、100%を目指すことは効率的ではない場面が多いため、各サービスごとに適切な可用性を設定する必要だ。

はじめに、SLIですが、これは「Service Level indicator」の略で、提供されているサービスのレベルの性質を定義した計測量である。一般的には以下をSLIとして用いる。

  • リクエストのレイテンシ(リクエストに対するレスポンスを返すまでにかかった時間)
  • エラー率(受信したリクエストを正常に処理できなかった比率)
  • システムスループット(単位時間あたりに処理できるリクエスト数)
  • 可用性(サービスが利用できる時間の比率)

次に、SLOですが、これは「Service Level Objective」の略で、SLIで計測されるサービスレベルの目標値、または目標値の範囲を指します。例えば、SLOを「年99.99%」と設定すると、「1年のうち52分は稼働しなくてもよい」ということになる。例えば、「1年の間にサービスが30分停止する障害」が生じたとしても、SLOの範囲であればそれは想定の範囲であり、問題ではなくなる。

同様の用語で、SLA というのがある。これは「Service Level Agreement」の略で、こちらはITサービスの契約において「この稼働率を下回る場合、金銭的な保証を行う」ことを示す値です。SLIは測定値、SLOは補償を伴わない目標値である点で意味合いが異なる。

Sloth の特徴

で、Sloth はPrometheusベースのSLOを作成するために、複雑な仕様やプロセスを把握して使用する必要がないように。迅速、簡単、かつ信頼性の高いPrometheus SLO generator(生成)してくれる。生成された記録とアラートのルールに基づき、信頼性の高い均一なSLOの実装を実現します。Kubernetes でCRDなどを用いてサポートしており、OpenSLOも限定的にサポートしています。

Sloth が生成するPrometheusのルールは3つのカテゴリーに分類されます。1つ目がSLIです。SlothにおけるSLOはルールはベースとなるもので、ユーザーから提供されたクエリを使用して、エラーサービスレベル(可用性)が何であるかを示すために使用される値を取得するものです。異なる時間帯に対して複数のルールを作成し、これらの異なる結果がアラートに使用されます。2つ目がMetadataです。これらは、残りのエラーバジェットやSLO目標パーセントのような有益なメトリックとして使用されます。これらは、Grafanaダッシュボードなど、SLOの可視化に非常に便利です。3つ目がAlerts でSLIルールに基づくマルチウィンドウ・マルチバーンアラートです。Sloth はサービスレベル仕様書を受け取り、仕様書の各SLOについて、上記のカテゴリーで3つのルールグループを作成します。

Metrics

Slothが生成したルールは、SLO間で同じメトリック名を共有します。しかし、ラベルは異なるサービス、SLOを識別するためのキーとなる。このようにして、異なるチームやサービス間で、すべてのSLOを記述する統一された方法を得ることが出来ます。

Slothが作成し、利用可能なすべてのメトリック名を取得するには、次のクエリを使用します。

count({sloth_id!=""}) by (__name__)

Alert

Slothの SLOアラートは、マルチウィンドウ・マルチバーン方式を採用し、Critical/pageWarning/ticketの2種類のアラートを生成します。 また、時間帯によって4種類のAlertを使用します(が割愛)。また、Sloth は自らAlertを発するのではなく、Slothが生成したAlertルールを使ってPrometheusがAlertを発する。 Prometheusに接続されたalertmanagerを介してSlack、Pagerdutyなど に通知をトリガーします。 sloth.dev

やっていく

Getting started - Sloth を参考にKubernetes上に構築をやっていく

Promethus 周りのインストール

# Get Helm Repository Info
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# Install Helm Chart :https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack#configuration
helm install [RELEASE_NAME] prometheus-community/kube-prometheus-stack

Sloth のインストール

Sloth のhelm はこちらにあるので参照してください。 github.com

helm repo add sloth https://slok.github.io/sloth
helm repo update
helm install [RELEASE_NAME] sloth/sloth 

もしくはCRDをデプロイしていきましょう

# Sloth CRD is required
$ kubectl apply -f ./pkg/kubernetes/gen/crd/sloth.slok.dev_prometheusservicelevels.yaml
# Prometheus Operator Rules CRD is required
$ kubectl apply -f ./test/integration/crd/prometheus-operator-crd.yaml

help

コマンドをインストールしたらhelp を見る良い習慣です。

sloth help
usage: sloth [<flags>] <command> [<args> ...]

Easy SLO generator.

Flags:
  --help            Show context-sensitive help (also try --help-long and --help-man).
  --debug           Enable debug mode.
  --no-log          Disable logger.
  --no-color        Disable logger color.
  --logger=default  Selects the logger type.

Commands:
  help [<command>...]
    Show help.

  generate [<flags>]
    Generates Prometheus SLOs.

  kubernetes-controller [<flags>]
    Runs Sloth in Kubernetes controller/operator mode.

  validate --input=INPUT [<flags>]
    Validates the SLO manifests and generation of Prometheus SLOs.

  version
    Shows version.

generated

get-started.ymlと同じ例ですが、Kubernetes で実行するのでCRDを使用した例です。 Kubernetesのprometheus-operator PrometheusRules CRDにPrometheusのルールを生成します。

sloth.dev

k8s-getting-started.ymlsloth generate させます。ちなみにnamespace を namespace: default にして実行いたします。

$ sloth generate -i k8s-getting-started.yml 
INFO[0000] SLI plugins loaded                            plugins=0 svc=storage.FileSLIPlugin version=1912e6a window=30d                                                            
INFO[0000] SLO period windows loaded                     svc=alert.WindowsRepo version=1912e6a window=30d windows=2                                                                
INFO[0000] Generating from Kubernetes Prometheus spec    version=1912e6a window=30d                                                                                                
INFO[0000] Multiwindow-multiburn alerts generated        out=- slo=myservice-requests-availability svc=generate.prometheus.Service version=1912e6a window=30d                      
INFO[0000] SLI recording rules generated                 out=- rules=8 slo=myservice-requests-availability svc=generate.prometheus.Service version=1912e6a window=30d              
INFO[0000] Metadata recording rules generated            out=- rules=7 slo=myservice-requests-availability svc=generate.prometheus.Service version=1912e6a window=30d              
INFO[0000] SLO alert rules generated                     out=- rules=2 slo=myservice-requests-availability svc=generate.prometheus.Service version=1912e6a window=30d
~~~

k8s-getting-started.yml を元にさまざまなファイルが生成されています!眠いので解説はしません

# This example shows the same example as getting-started.yml but using Sloth Kubernetes CRD.
# It will generate the Prometheus rules in a Kubernetes prometheus-operator PrometheusRules CRD.
#
# `sloth generate -i ./examples/k8s-getting-started.yml`
#
apiVersion: sloth.slok.dev/v1
kind: PrometheusServiceLevel
metadata:
  name: sloth-slo-my-service
  namespace: monitoring
spec:
  service: "myservice"
  labels:
    owner: "myteam"
    repo: "myorg/myservice"
    tier: "2"
  slos:
    - name: "requests-availability"
      objective: 99.9
      description: "Common SLO based on availability for HTTP request responses."
      sli:
        events:
          errorQuery: sum(rate(http_request_duration_seconds_count{job="myservice",code=~"(5..|429)"}[{{.window}}]))
          totalQuery: sum(rate(http_request_duration_seconds_count{job="myservice"}[{{.window}}]))
      alerting:
        name: MyServiceHighErrorRate
        labels:
          category: "availability"
        annotations:
          summary: "High error rate on 'myservice' requests responses"
        pageAlert:
          labels:
            severity: pageteam
            routing_key: myteam
        ticketAlert:
          labels:
            severity: "slack"
            slack_channel: "#alerts-myteam"

validate

構文チェックも可能です

$ sloth validate --input=k8s-getting-started.yml
INFO[0000] SLI plugins loaded                            plugins=0 svc=storage.FileSLIPlugin version=1912e6a window=30d
INFO[0000] SLO period windows loaded                     svc=alert.WindowsRepo version=1912e6a window=30d windows=2
INFO[0000] Validation succeeded                          slo-specs=1 version=1912e6a window=30d

deploy

generate したものをapply していきます

$ sloth generate -i k8s-getting-started.yml | kubectl apply -f -

Grafana へのログイン

kube-prometheus のGrafanaは初期ID/PASS のadmin:admin ではないのでパスワードを確認する(ArgoCD でも似たように初期パスワードを取得できる)

# user:password -> admin:prom-operator
$ kubectl get secret sloth-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
prom-operator

Grafana へのDashBoard の追加

SLO / Detail dashboard for Grafana | Grafana Labs

入門失敗

Dashboards を生成したら感動的なラストシーン!?このダッシュボードには、各SLOの詳細が表示されますが これには、http_request_duration_seconds_count にデータが入ってないわ。。。

          errorQuery: sum(rate(http_request_duration_seconds_count{job="myservice",code=~"(5..|429)"}[{{.window}}]))
          totalQuery: sum(rate(http_request_duration_seconds_count{job="myservice"}[{{.window}}]))

Dashboards - Sloth にしたいんですけど,,, もう眠いので一旦、終わって公開します。 Sloth はとりあえず動かすためのチュートリアルが絶妙に弱くてPrometheusをある程度理解してないとうまく動かせないなーって思いました(小物として)。

参考