GrizzlyとGrafonnetで始めるGrafana Dashboards as Code

先日、というかもう3ヶ月も経ってしまいましたが Grafana Meetup Japan #1 - connpass にてLTをさせて頂きました。

趣味のダッシュボード開発というテーマで、あわせてGrafanaのダッシュボードをコードで管理するソリューションの1つとして Grizzly GitHub - grafana/grizzly: A utility for managing Jsonnet dashboards against the Grafana API を紹介するお話をさせて頂いたのですが、結構な人数が参加されていたものの知ってる人が一人もいないぞ・・という結果になり、それもなんだかもったいない話だと思いました。

ということで今回はとりあえずGrizzly、Grafonnetがどういったもので、どうGetStartedしていくとよいか、といった話を改めてブログで書いていきます。

なお本記事で利用するツールのバージョンはこんな感じです、jsonnet-bundlerはdevってなんやねんという感じですが、Homebrewで入る最新のものを使ってます(※0.5.1でした)。

$grr --version
grr version v0.4.3

$jb --version
dev

$jsonnet --version
Jsonnet commandline interpreter (Go implementation) v0.20.0

リモートのGrafanaバージョン
Grafana v10.4.2 (22809dea50)

いちおうサンプルコード一式はここにおいてます

GitHub - egmc/egmc-dashboard-blog: sample code for my blog post

Grafanaのダッシュボード表現とGrafonnet

GrafanaのダッシュボードはJSONで構造化されて表されます。 JSONなので、このままでもバージョン管理できるのですが、これをエディタで編集して変更管理する、というのはなかなかに大変です。 結局ダッシュボードの変更は画面上から行い、結果としてexporterされたJSONをバージョン管理するというのは変更とexport、コミットを繰り返すことになるので作業としてもやや冗長になります。

最終的にJSON表現となればよいのでJSONを生成するテンプレート言語を使ってより簡潔な記述を可能とするのがJsonnet(JSONテンプレート言語)とGrafonnet(JsonnetでGrafanaのダッシュボード表現を扱うためのライブラリ)です。

Jsonnet、Grafonnetのセットアップ

Jsonnet、Grafonnetのセットアップについては以下を参照

起点として以下のページからたどれますが

Home - Grafonnet

Jsonnetはc++とgoの実装がありますが公式の推奨どおりgo-jsonnetを使いましょう

github.com

Grafonnetを使うためにJsonnetバンドラー(Jsonnetのパッケージマネージャ)を入れます

github.com

最後に実際にダッシュボード管理を行うプロジェクトレポジトリでgrafonnetをインストールします

grafana.github.io

参考までにmacでHomebrewを使う場合は以下のような流れになります(細かい部分はそれぞれのドキュメント参照)

$ brew install go-jsonnet
$ brew install jsonnet-bundler

#以下プロジェクトフォルダにて
$ jb init
$ jb install github.com/grafana/grafonnet/gen/grafonnet-latest@main

Grizzlyを使う

GrizzlyはGrafanaダッシュボードなどを管理するためのcliツールです。

野良ではなく、GrafanaのOrg配下で開発されています・・が情報は正直少ないです。

ダッシュボード管理機能からスタートしたものの、現在はGrafanaの周辺ツール(Synthetic MonitoringやPrometheusのアラートルールなど)にも対応を広げているため、observability resourcesをコードで管理するためのcliツールという位置づけになっています。

Grafana Grizzly is a command line tool that allows you to manage your observability resources with code.

本記事ではGrafanaダッシュボードのみを取り扱います。

Grizzlyのセットアップ

プラットフォームごとのバイナリリリースがありますのでこれをそのまま落としてきて使います

Releases · grafana/grizzly · GitHub

grrコマンドが実行可能になったら、まずはリモートのGrafanaを扱うためのクレデンシャルをセットします(環境変数でも設定できますが、本記事では最初から利便性のためにconfig setを利用します)

Setup and Configuration | Grafana Grizzly Docs

を参考にまずはリモート環境に合わせたコンテキスト(環境名)を設定します

grr config create-context xxx

そしてクレデンシャル(GrafanaのURLとトークン)をセットします

grr config set grafana.url {リモートのGrafana URL}
grr config set grafana.token {Grafanaのサービスアカウントに紐づいたトークン}

以降特に指定せずに現在のコンテキストに紐づいた設定が利用されます。

複数のGrafana環境を切り替える際は別名でコンテキストを作成して切り替えると良いでしょう。

Grizzlyを使ってJSON/形式でダッシュボードを作成する

サンプルダッシュボードを作っていきます。

本記事ではお題として拙作の GitHub - egmc/systemd_resolved_exporter を使ってsystemd_resolvedのキャッシュヒット率を出すグラフを作ってみます。

PromQL的にはこんな感じです

rate(systemd_resolved_cache_hits_total[$__rate_interval]) / (rate(systemd_resolved_cache_hits_total[$__rate_interval]) + rate(systemd_resolved_cache_misses_total[$__rate_interval]))

(単にこちらはサンプルなので、実際に動かす場合はすでに取得しているexporterの適当なメトリクスで同様のステップで試してみると良いでしょう)

単にGrafanaのUIを使ってダッシュボードを作成し、JSON表現(Grizzlyのデフォルトはyamlですが)を管理するだけであれば grr serve が簡単です。

この機能は比較的最近追加されたものですが、なかなか動作的におもしろい機能になっています。

例としてこんなyamlファイルを用意し(metadataのnameとspecのuidは合わせる必要があります)

apiVersion: grizzly.grafana.com/v1alpha1
kind: Dashboard
metadata:
    folder: general
    name: systemd_resolved_sample
spec:
    title: systemd_resolved_sample
    uid: systemd_resolved_sample

systemd_resolved_sample.yamlとしてプロジェクト直下に保存します。

この時点では単にタイトルとuidだけが指定されているだけの空のダッシュボードです。

$ grr serve ./*.yaml -t dashboard

するとlocalhost:8080でおもむろにサーバが立ち上がり、アクセスするとこんな表示になり

systemd_resolved_sampleにアクセスすると空のダッシュボードが立ち上がっているので、Add visualizationで先ほどのクエリをもとにUI上で作業してグラフを足していきます

単にクエリを追加しただけだと0.xxといった値が折れ線グラフで表示されるだけなので、いくつかグラフをいじって見た目を整えます

  • unitをpercent(0.0-1.0)に
  • maxを1に(常に100%まで表示されるように)
  • グラフタイトルを設定してLegendをsampleに
  • 諸事情によりこのサンプルは60s間隔でscrapeしてるのでinteval=60に設定してます

グラフが出来上がったらそのままSave dashboardから保存します。 するとおもむろに手元のyamlが書き換わり、以下のようなものになります。

(データソースのIDなどは環境固有なので、各々環境で適宜読み替えてください)

apiVersion: grizzly.grafana.com/v1alpha1
kind: Dashboard
metadata:
    folder: general
    name: systemd_resolved_sample
spec:
    annotations:
        list:
            - builtIn: 1
              datasource:
                type: grafana
                uid: -- Grafana --
              enable: true
              hide: true
              iconColor: rgba(0, 211, 255, 1)
              name: Annotations & Alerts
              type: dashboard
    editable: true
    fiscalYearStartMonth: 0
    graphTooltip: 0
    links: []
    panels:
        - datasource:
            type: prometheus
            uid: adk2jn9tqqiv4e
          fieldConfig:
            defaults:
                color:
                    mode: palette-classic
                custom:
                    axisBorderShow: false
                    axisCenteredZero: false
                    axisColorMode: text
                    axisLabel: ""
                    axisPlacement: auto
                    barAlignment: 0
                    drawStyle: line
                    fillOpacity: 0
                    gradientMode: none
                    hideFrom:
                        legend: false
                        tooltip: false
                        viz: false
                    insertNulls: false
                    lineInterpolation: linear
                    lineWidth: 1
                    pointSize: 5
                    scaleDistribution:
                        type: linear
                    showPoints: auto
                    spanNulls: false
                    stacking:
                        group: A
                        mode: none
                    thresholdsStyle:
                        mode: "off"
                mappings: []
                max: 1
                thresholds:
                    mode: absolute
                    steps:
                        - color: green
                          value: null
                        - color: red
                          value: 80
                unit: percentunit
            overrides: []
          gridPos:
            h: 17
            w: 24
            x: 0
            "y": 0
          id: 1
          options:
            legend:
                calcs: []
                displayMode: list
                placement: bottom
                showLegend: true
            tooltip:
                mode: single
                sort: none
          targets:
            - datasource:
                type: prometheus
                uid: adk2jn9tqqiv4e
              editorMode: code
              expr: rate(systemd_resolved_cache_hits_total[$__rate_interval]) / (rate(systemd_resolved_cache_hits_total[$__rate_interval]) + rate(systemd_resolved_cache_misses_total[$__rate_interval]))
              instant: false
              interval: "60"
              legendFormat: sample
              range: true
              refId: A
          title: systemd resolved chache hit rate
          type: timeseries
    schemaVersion: 39
    tags: []
    templating:
        list: []
    time:
        from: now-6h
        to: now
    timepicker: {}
    timezone: ""
    title: systemd_resolved_sample
    uid: systemd_resolved_sample
    version: 1
    weekStart: ""

これでJSON Model(を内包したYAMLファイル)が残りましたので、このままバージョン管理を行うことができますし、再び grr serve で編集を再開することができます。

grr serve の動作としては、ローカルでGrafanaを立ち上げつつ、データソースとしては指定したクレデンシャルを利用してリモートのGrafanaのデータソースへリクエストをプロキシして利用するような形になっています。

リモートのデータソースを利用しつつ手元でトライアンドエラーを行ってダッシュボードをファイルで管理できる、といったあたりが利点になるかと思います。

一方、GrafanaのJSON Modelを生で扱うため抽象度は低く、明示的に指定したいプロパティ以外もすべて特定のスキーマバージョンに基づいて保存されてしまうため、記述内容そのものは冗長になりますし、バージョンをまたいだ環境間の行き来などは難しそうです(実際Grizzlyのpull/pushでGrafanaバージョンまたいでダッシュボード定義を移動しましたが割と動かないものがあったりしました)。

Grizzlyを使ってGrafonnetでダッシュボード管理を作成する

同様のダッシュボードを今度はGrafonnetで作成してみます。

今度は最初からコード管理を行いますので、新規に systemd_resolved_sample.jsonnet を作成します。

local g = import 'github.com/grafana/grafonnet/gen/grafonnet-latest/main.libsonnet';
 
# dashboardを生成してpanelを追加する、必要な属性はGrafonnetが提供する関数を利用して生成し+結合で追加していく
local dashboard = g.dashboard.new("systemd_resolved_sample_jsonnet") + g.dashboard.withUid('systemd_resolved_sample_jsonnet')
  + g.dashboard.withPanels([
    g.panel.timeSeries.new('systemd-resolved cache hit rate')
    + g.panel.timeSeries.queryOptions.withTargets([
        g.query.prometheus.new(
            'prometheus',
            'rate(systemd_resolved_cache_hits_total[$__rate_interval]) / (rate(systemd_resolved_cache_hits_total[$__rate_interval]) + rate(systemd_resolved_cache_misses_total[$__rate_interval]))',
        ) + g.query.prometheus.withInterval("60")
          + g.query.prometheus.withDatasource('prometheus')
          + g.query.prometheus.withLegendFormat("sample")
    ]) + g.panel.timeSeries.queryOptions.withDatasource('prometheus', 'adk2jn9tqqiv4e')
    + g.panel.timeSeries.standardOptions.withUnit('percentunit')
    + g.panel.timeSeries.standardOptions.withMax("1")
    + g.panel.timeSeries.panelOptions.withGridPos(17,
     24, 0, 0)
]);
# Grizzlyの作法に合わせてmetadataを付与し、specにdashboardのJSONを入れ込む
{ 
  apiVersion: 'grizzly.grafana.com/v1alpha1',
  kind: 'Dashboard',
  metadata: {
    name: "systemd_resolved_sample_jsonnet",
    folder: "general" 
  },
  spec: dashboard
} 
$ grr apply ./systemd_resolved_sample.jsonnet -t  dashboard

で反映します。

また、 grr watch を使うことでファイルの変更を検知して(エラーがない限り)リモートのGrafanaへ即座に反映することもできます。 リモートに対してトライアンドエラーができる場合はこのやり方がおすすめです。

$ grr watch . dashboard -t  dashboard

grr serve ポチポチつくたものと同様のダッシュボードができました。

Jsonnetは作法を抑える必要はありますが、記述そのものは生のJSON Model表現より「実際の関心事」フォーカスにした内容になっています。

(本記事では簡単のためにダッシュボードのuidを環境に合わせて指定していますが、このあたりは実際は動的に設定することで環境固有の情報をなくせるでしょう)

スキーマバージョンについてはGrafonnetライブラリに依存しますが、コードそのものにそういった情報は含まれないため、ライブラリが追随してくれる限り将来のバージョンアップも比較的容易になるはずです。

まとめ

  • Grizzlyを使うことでお手軽にGrafanaのDashboards as Codeをはじめることができます
  • grr serve は手元でGrafanaそのものを使ってDashboardを作成するのに便利です
  • Grafonnetは作法を覚える必要はありますが、本格的にダッシュボードのコード管理を長期的に行う場合は有用な選択肢になります

・・・と一旦まとめた後の雑多な補足

  • Grizzlyは実際便利だと思うんですが、まだまだバギーでコマンド体系は統一されておらず、ツールとしてははまりどころも多いです
    • エラーも不親切でまだまだ発展途上な感は否めません
    • ということで本記事の一つの目的としてはユーザー増やしてツールの環境がもっとよくなるいいなあ、などという意図もあったりします、バグレポでもPRでも
  • Jsonnetでの記述でDashboardをspecに入れてGrizzlyのapiVersion、kind、metadataをいれるやり方ですが実際これ公式自体は公式ドキュメントにないので、これが意図したやり方なのか実は確認してません、しかしかつてのHidden Elementを利用した記述方法ももはやサポートされてなさそうなので、こうするしかないんじゃないかな・・と思ってます
  • Grafonnetライブラリはかつて https://github.com/grafana/grafonnet-lib が使われていたのですがGrafana本体のアップデート、API変更に追随が難しくなり自動生成するアプローチになったのが現在の https://github.com/grafana/grafonnet レポジトリです。最新のAPIに追随してくれるのは良いのですが、特定のGrafanaバージョン、スキーマバージョンの指定みたいなのはできなさそうなので古いGrafanaバージョンを使っている場合はやや注意がいりそうです。タグで分けてくれたらいいんじゃないかと思うんですが・・。
  • クレデンシャルを含むconfigのパスは grr config path で取得できます。手元のMacだと /Users/{ユーザー}/Library/Application Support/grizzly/settings.yaml に設定されてました。

参考

公式系

その他

  • Jsonnetの薦め #JSON - Qiita 元記事の作成時期は結構古いですがJsonnetについての概要を日本語で掴むのにおすすめです

PrometheusのRemoteWriteがんばり過ぎ問題と最近の関連パラメータ更新について

SampleAgeLimitというのがmainにマージされたのを観測したのでちょっと歴史を含めてメモしておくという雑記事です。

三行

  • 1) 2.11.0 / 2019-07-09 MaxRetriesが削除された
  • 2) 2.32.0 / 2021-12-09 MaxBackoffが100msから5secに変更
  • 3) xxx / 2024-01-05 SampleAgeLimitが追加されmainにマージされた(デフォルトは無効)

2年おきくらいになにがしか更新がある

RemoteWriteがんばり過ぎ問題

プロダクション環境の信頼性を損ねず観測する技術 - Speaker Deck

こういうの

  • PrometheusのRemoteWriteはExponential Backoffなリトライをする
  • しかしMaxBackoffに到達するとそこでひたすらRetryを繰り返す
  • WALは2h程度で削除されるのでいちおう無限に繰り返されるわけではない(という理解
  • 加えて、(RemoteWrite先が完全に死んでいれば行わないが)sampleの受け取りに対して書き込みが遅いとShardの数を増やして一度にRemoteWriteできる量を増やそうとする
  • しかしRemoteWrite先は古いsampleをいつまでも受け取らず大抵の場合はdropしてしまうので(例えば2h程度書き込み先が半死状態で、復旧したような場合)、ネットワーク帯域を最大限に使って大量のRemoteWriteを試みても、無駄になってしまう上に帯域を逼迫して障害を起こすことさえある

ということで

一周回ってSampleAgeLimit(再送するサンプルをいつまで保持するかを決定するパラメータ)が追加されたようです

個人的な雑感

  • 1)のMaxRetriesはたしか3回とかだったので、WALの話はあるにせよ、せっかくExponential Backoff実装しているのに100msが上限というのはやはり無茶な設定というか意味がなかったよなあと思う、SYNの再送でも秒単位だというのに、送信失敗した相手に対して秒間10回リトライするというのはやはりやりすぎだと思う
  • MaxBackoffが伸びたので今の環境はいくぶん再送まわりはましになっているがそれでも5秒でリトライは割と高頻度だと思う、どうせDropされてしまうのであれば(これはRemoteWrite先によるが)、SampleAgeLimitはかなり短く設定しておいてよいと思う、1分とかでもいいんじゃなかろうか
  • kube-prometheus-stackなんかで導入している環境は諸々デフォルトで設定されてくると思われるので、デフォルトが安全になってくれるといいなあという気分
  • メトリクスをあとで埋める方法も確かThanosあたりでなにか考えられてた気がするが、このあたりのコンセンサスが固まると双方幸せになりそう、新しいsampleのingestとbackfillみたいなものは分けて考えた方がいいんだろうなあ

ref

github.com

github.com

github.com

github.com

github.com

IaC、あるいはインフラ抽象化レイヤー導入時に考えたらいいんじゃないかと思うことを雑多に書く

この記事はSRE Advent Calendar 2023の4日目の記事です。

qiita.com

3日目は@myu_mxさんのゆるやか成長スタートアップの小さなEnabling SRE的活動でした。

久々のアドカレ参加ですが、少し思いの丈に任せてみようということで経験と主観が強めの記事です。
この辺で語られていたよとかこれは賛同できないというポイントなどもっといい情報があればぜひお知らせください、という感じで雑多に書いて参ります。
TerraformやCloudformationあたりをよく触るのでそのあたりがどうしても頭にありますがなるべく固有の話はしない方向で。

色々書きつつ、基本的には長期的な運用を見越したソフトウェアの運用設計と同じ考えで良いとは思ってます。
最低限のインターフェースを公開し疎結合に設計する、モジュールは交換可能する、ライフサクルを考える、などなど。

ただIaCコードは割と長生きする傾向にあるので、コードを書き始める前に少し注意深く設計しておくと長期的に楽になるんじゃないかと思います。

解決すべき課題を明確にする

  • ここからかー、となる話でもありますが、コード化は手段であり、目的ではないので、課題が何でアプローチが適切なのか、他にやり方はないのか考えるべきです
  • 後述しますが、運用上IaCが向かないリソースというものも当然存在するので、シェルスクリプトやWebコンソールでの手作業も手段の一つとして検討に入れておきましょう

ワンショットで使うか長期的に更新適用し続けるか

  • 環境の初期構築のみに使うか、一度構築してコードの管理下においたものを更新し続けるか、これは導入前に必ず決めたほうが良いでしょう
  • 判断の一つとして、運用中に変更が発生することがほぼなく、消えたらどう考えてもまずいようなリソースは予めワンショットで作成しておき、以降はコード管理下から外しておく方が運用しやすく安全であるケースがあります(典型的にVPCやサービスで利用するドメインのゾーン情報など)

リソースのライフサイクルを考える

  • ライフサイクルがあまりに異なる状態をひとまとめにすると、同時に管理されているほぼ更新のないリソースが足かせになったり依存関係により管理上の手間が増えます
  • あるインフラ環境、認証基盤、なんでも良いのですがそれらの全体のライフサイクルがあるとして、頻繁に更新のかかる部分とそうじゃない部分は分離して、必要な状態のみを参照するような設計を予め考えておくとトータルでメンテが楽になります
  • 個人的には一発で構築するということにこだわらず、システムの境界を跨ぐ部分は状態を分けておいた方が、それぞれのシステムのライフサイクルに合わせて余計な依存関係を持ち込まずに更新可能となるため、特に長期運用するシステムではおすすめです
  • Terraform的にいうとproviderがいくつも混在するようなコード管理は避けた方が良いと考えています

適用範囲を考える

  • コードを書き始める前にどこまでをコード管理をすべきか、を検討する
  • 雑な一般論としてIaCなソリューション各位は宣言的である(ものが多い)故に「どういった状態にするか」は得意で「どうやってその状態にするか」はあまり得意ではないので、後者が重要視されるものは別のツールや手段による運用が向いている
    • 例えばDBの切り替えみたいなオペレーション系
    • 証明書の更新、DNSレコードの変更など、新旧用意して切り替える系
    • snapshotからの復旧など状態をもって運用オペレーションを伴うリソース
  • 変更プロセスに重きをおいて安全性を担保するようなオペレーションが該当するかなと思います
  • 余談としてはクラウドベンダーのWebコンソールなどでは追加のバリデーションが期待できたり、API上提供されてないオペレーションをそれっぽく組み合わせて提供していることもあるのでそういったものにも価値があるということも考えておくとよいでしょう

抽象化レイヤーは必ず動くとは限らない

  • 割と失敗するので失敗しても安全なように設計する
  • 一般に抽象化レイヤーを挟んだトラブルシューティングAPIを直接操作するより面倒になるため、これもトレードオフの一つとして考えておきましょう

必要な機能について確認する

  • 当たり前ですが抽象化レイヤーを挟むと基本的にはその上位のレイヤーの機能に対して遅れて対応されるということを理解しておく
  • AWSのベンリ新機能でました、でもCloudFormationではまだ使えません、みたいなアレです
  • コード書き始める前に、必要な機能がサポートされているか見ておきましょう

先々のバージョンアップペースについて考える

  • ワンショットの利用でない場合、IaCコードは基本的に管理するリソースのライフサイクルとともに生き続けるので(途中でやめることもできるが)、長期的なライフサイクルをある程度考えておいた方が良い
  • コード化にあたって例えばTerraform導入しました、コード化できました、といったときに実際に導入しているのはTerrafom1.6.5であったりAWS CDK2.110.0であったりするし、AWS Provider5.29.0だったりするということを意識する
  • これらの、少なくとも主要なコンポーネントがどの程度のペースでリリースに追随していく必要があるのか、ということを導入時点で考えておくとよいでしょう

SRE NEXT 2023で「Runbookに何を書き、どのようにアラートを振り分けるか?」というお話をしました

登壇&参加記事です

今までのあらすじ(ずっとアラートの話してる気がする)

2020

dasalog.hatenablog.jp

2022

dasalog.hatenablog.jp

開発者とともに作る Site Reliability Engineering / SREing with Developers - Speaker Deck

で @yuuk1t さんも皆勤だったみたいな話をしていたので

(ワイも、と言いたかっただけです)

今回の発表まわりの蛇足

speakerdeck.com

「おかしい、何度やり直しても20分間早口おじさんになってしまう・・」

というのはさておき、Runbookの話でした。

x(慣れない)でも書いたのですがこれは2020の発表の伏線回収でもあったのでした

引用先のスライドにも書いてあるんですけど言ってしまえばこれは当時すでに存在した手法を自分たちの組織課題に合わせてアレンジしつつ取り込んだ、という話でもありめちゃめちゃ新規性のある話というわけではないのですが、そうはいっても実際問題組織が抱える課題はそれぞれで、自分たちの課題はこういったものでそれに対する解決をSRE的なプラクティスを踏襲しつつ実践してみた、ということで一つの解として参考になれば良いし、そこが聞く人にとっての価値であろうと考えこの内容にしました。

2020からのアラートの話も今回のRunbookの話もそうなのですが、このあたりの取り組みのモチベーションは自身の(あまりよくないなーと思った)体験がベースなっており、もう少し言うと自身が苦労したことを次の世代で同じように苦労する必要はないのではないか、という思いがありここらへんの負債(≒暗黙知)を減らせるような取り組みができればよい、そのためにSRE的なプラクティスがたまたま有効だったのでアレンジをしつつ採用したらよさそうだな、というのが個人的な考えでもありました。

もちろん発表でも少し触れた通り、ドキュメントを新規に作るということは(コードと同じように)、書いた瞬間から負債化のリスクを抱えており、「よかれと思って」仕組みを作ったものが今後かえって重荷になる可能性を孕んでいます(というか最終的には確実にするでしょう)。

今後の取り組みとして、そのあたりのライフサイクルをゆるやかに回す、総量をあるラインで留めてメンテナンスコストを一定に保つ、といったところがチャレンジになると考えています。

(そしてセッション後すぐにお声がけ頂いたりしてこれは大変嬉しかったですね、課題感はそれぞれですが、というのとこれはセッションの内容とも絡んでくるのですが各々の文脈におけるヒントになれば幸いです、課題に合わせてアレンジしつつやっていきましょう)

セッション

参加させて頂いたセッションについて、一応色々メモってはいたところから印象に残っているところを

ギークがイオンに飛び込んだ結果がやばい〜Reliabilityと経営〜

樽石さんによるキーノート。

micro company architectureという壮大な話の一方でdockerイメージ全部入りアーキテクチャという話を対比しつつ、「コンピュータ・サイエンスの基礎を理解すると各種アーキテクチャに応用ができるよ」という話が実践されていて実際これこそがTHE SREみたいなことなのではないかというところに(個人的に)落ち着いて強さを感じたセッションでした。

LINEスタンプのSREing事例集:大量のスパイクアクセスを捌くためのSREing

maruさんによる、今から3ヶ月後に想定されているスパイクに備えて皆さんでやっていきましょう、という追体験型セッション。

印象ポイントとしては、本番環境で模擬負荷試験みたいなところで、インスタンス数を徐々に下げていって、実際じゃあ一台でこれくらいのRPSさばけるね、という(リリース前であれば)負荷試験でやる内容を本番でやるという話があり、これは大変理にかなってるなーと思いました。 すかすかだと負荷見積もれんし、じゃあ去年のものをそのままベースにするかというとなんらかの係数で推測はできるもののコードも諸々変更が入っているわけで、じゃあ今だったらどれくらいさばけるの?を直接的に得ることができるのは確かになーと思ったところでした。

エンジニアのためのSRE論文への招待

論文is敷居が高いと完全に思っている自分のような人間に向けたセッション。

自分はもうちょい世に出てきた技術からじゃあみていこうというレベルなのだけど10年先を見ていこうと思ったら、当たり外れはあるにせよこういったアカデミック分野をみていくべきなんだろうなあ、と思う次第でした。

各所ポインタをまとめてくれていますしsrelounge slack内にも #sre-paperチャンネルが作られたので入り口として覗いてみるのも良いですね。

【コミュニティコラボ企画】パネルディスカッション 〜信頼性に関わる、ご近所さんが集まりました〜

こちらは配信なしで、各所のコミュニティの生の話が聞けて良きセッションでした。

お隣さん、で個人的にやはり思ったのはそれぞれ特色はありつつ、SREの文脈でももう少しこういう話あってもいいのでは、みたいな内容が他のカンファレンスでもあったりするのでそういったことを輸入する機会があっても良い、超個人的にはeBPFでオブザーバビリティ的な話がもう少しあってもいいと思うしなあ、みたいな話であったり、実際SRECONではこれくらいのトピック結構出てくるので、特色を損なわない程度に少しずつ相互交流があるとお互いいいよなあ、などと思った次第でした。

ブルームバーグのセントラル・テレメトリー・システムが業務にもたらす価値

まずブルームバーグだ、という点でSRECON的な香りを感じておお、となったセッション。

セントラルモニタリングシステムを自前運用する話で、ちょうどその裏側のお話も懇親会で少し掘らせて頂いたのですが今後もネタがありそうだなあということで未来を感じる楽しみなお話でした。

開発者とともに作る Site Reliability Engineering

@chaspyさんの修論セッション。
チームにフォーカスした@chaspy
さんらしい良いセッションでしたね。

最終的に文化の話になっていて、文化はたしかにプラクティスの上位というか根幹にくるもので、ベースの文化というのはおいそれと変わらないですし文化にマッチしないプラクティスはそもそも根付かないであろうというところで、翻ってなんらかのプラクティスを持ち込むためにはたとえ実際に良いものであったとしても文化にマッチするかどうか、を詰めるべきなんだろうな、などと考えた回でした。

信頼性目標とシステムアーキテクチャ

クロージングに来つつ、基本に立ち返るような骨太な話だなーという印象のセッションでした。
サービスの目標、SLOを定めじゃあどう実現していくかということについて深く考えていくとそこからアーキテクチャにするべきなのか、運用はどうあるべきなのかという話になり、当然そこにはコストも時間もかかり・・、というところで会話を通しての意思決定が重要になる、という話がありつつじゃあ実際どこまでやるべきか、を各々が決めていく、答えはないけどヒントならあるよ、という実際これがSRENEXT的な話でもあるよなあと思ったクロージングでした。

セッション以外

雑多に箇条書きで

  • 会場めちゃ良かった
  • コーヒー助かる、カンファレンス会場で豆を買ったのはさすがに初でした
  • 懇親会は話したいなーと思っていた方々とはだいたいお話できたと思いつつ限られた時間の中でもっと話したい人もいたなあという悩ましさ、ケータリングも配慮が行き届いていて大変良かったのですが人と話す方を優先したい気持ちが強くほとんどビールとトークという感じで終わってしまった

今後について

@chaspy_さんは引退!というお話をされていましたが自分もそこまでではないにせよ、登壇したさは今回ピークを迎えいったんネタも出しつくして一区切りかなーと思っております、まあ先のことはわからんですしなにか話したいネタが発生したらがんばるかもしれません。

コミュニティ的にも新しい分野、企業からの発表が増えてきてそれを聞いていきたいという思いも強く、イベントが続く限りなんらかの形で関わっていきたいなあとぼんやり考えております。

あと全般的に、成功事例!みたいなのばかりでなくもう少しナマな話があってもいいよねえというのもあって(いうて自分も2022の発表はそういうのをまあまあ出していったつもりはありつつ)、ゆるSRE方面ではそういうのをやろうかみたいな機運も一部ではあるらしいので若干興味が湧いているところでもございます。

最後に、運営皆様素晴らしいイベントをありがとうございました。

ハイブリッド開催めちゃ大変だったと思いますが、1参加者、スピーカーとしてスタッフ皆様に御礼申し上げます。

ITエンジニア男育休時のちょいTipsとか買ってよかったやつとか

こちらを最近読んで

takumif.hatenablog.com

一年前の記事ですがめちゃよくまっていてすばらしいですね。

当時子が産まれるちょい前くらいのタイミングで男性育児系の記事いくつか読んだのだけどこれ読んでなかったなと思ったら時期が微妙にずれていたのでした。 育児中、だいたい手が空かないのでぴよログのalexa連携はめちゃ良いですね、皆使うと良いと思う。実装してくれたぴよログの人ありがとう。

ということで、最近育児記事みたいなのも増えてきましたが自分も覚えてるうちに少しは書いておこうという気持ちで、サンプル1/1程度のなにかをざっと書いてみましたなやつです。

どんな状態だったか

  • 最初の子
  • 育休期間は4ヶ月弱
  • 夏生まれ
  • 生まれてから一ヶ月ちょいまで妻の母が泊まりでサポートに来てくれていた

我が家の場合

  • 基本的な役割分担
    • 自分と妻が交代で子のお世話
    • 妻の母が家事サポート
    • 実際は家事以外も色々サポートしてもらえたのでだいぶ助かった
  • 件の記事と同じく基本二交代制で、夜勤(と呼んでいた深夜担当)を交互にやっていた
    • リビングにベビーベッドおいて、担当するほうが横にふとんを敷いて寝るスタイル
    • 最初から交代でいくつもりだったが、出産後の母親はダメージがでかいので床から起き上がるのが困難であり当初一ヶ月はまるまる自分が担当していた
    • 夜勤時は3回ミルクタイムが挟まるが、ここは割とがんばって最適化すると自分も寝やすくなるので
      • 予想時間のちょい前に起きて
      • 調乳を済ませ(この間に起きて泣きだしてもいったんスルー)
      • おむつを替え(濡れてるかどうかは気にせずに投機的実行として毎回やる、赤ちゃんめちゃおしっこするのでどうせ高確率で替える必要がある)
      • ミルクを飲ませて寝かしつける
    • というフローに最終的に落ち着いていた
    • ミルクが一番落ち着くので、これを最後に持っていくようすると寝付きがスムーズになる
  • 育休開始と終了のタイミング
    • 予定日の1週間程度前から有給使って開始
    • 復職タイミングはだいたい4ヶ月後
    • これはめちゃくちゃ子供のタイプに依存すると思われるので自分の場合はー、だけども実際問題タイミングとしてはちょうど良かった
    • この時期は睡眠が落ち着いていて(3ヶ月くらいから急に朝まで寝るようになった)、離乳食がまだ始まっておらず、一時的にちょっと楽になったタイミングだったので割となんとかなった

やってよかったこと

  • サンプルはもらえるだけもらう
    • 子が生まれたらベビー用品店でサンプル特典的なものがもらえるので近場でもらいましょう、我が家は西松屋ベビーザらスがあったので両方もらった
    • 新生児期は一ヶ月しかないので、どのメーカーが合うのかとか試しているうちにあっという間に過ぎてしまうので、子の体型にあったものを選ぶのにサンプルでちょっとずつ試してみるのがよいですね
    • 我が家は哺乳瓶の消毒はコンビの除菌じょ〜ずを使っていたので、たまに実家に買える時などはミルトンを使っていたけどこれくらいであればサンプルでも十分足りてしまう
  • 産後の育児相談
    • 産院で初回は無料で相談に乗ってもらえるやつに行った
    • 両親学級みたいなもの(だいたいオンラインだった)はあるものの父親はなかなか実際に対面でアドバイスを貰える機会がないのでこれはとても良かった
    • 個人的には沐浴やらその他のお世話より何より縦抱きが腕に負担がかかってしんどかったのでこのあたりであったり、ワンオペ風呂のやり方などかなり参考になった
  • 簡易ベビーモニター
    • 家ではベビーモニターを使えばいいが、出先では即席のベビーモニターとしてPCとスマホでMeetなどでビデオ通話を繋いでおくというのをやってみたら割とよかった
    • 実家などでお昼寝をさせている間など別室から様子がわかるのでおすすめ

買ってよかったもの

  • 温度指定可能な電気ケトル
    • とりあえず一回100℃で煮沸しておいておき使うときに80℃にして使う
    • 温度をキープする機能もあったりするが1hとかなのでほぼ使わなかった(次の調乳のタイミングまでにはどうせ冷めてしまう)、十分はやく沸くし狙った温度になるのでそれだけでOK
  • 電動鼻吸い
    • 自分&妻は口で吸うタイプの鼻吸いが使いこなせなかったので、割と早い段階で導入した
    • 3ヶ月くらいまでは鼻が詰まってしまうとミルク飲み時に苦しくなくってぐずるというコンボになってしまうことがありそういう時にかなり重宝した
    • 安くはないものの成長していっても使うのでヨシ
  • イブルマット
    • 義弟氏のおすすめで出産祝いで一畳ちょいくらいのを一枚もらい、その後同じサイズのを買い足した
    • 乾きやすい、毛玉的なものが出ない、などでかなり重宝
  • 爪切り
    • 我が家は爪切りが怖かったので基本爪やすりで済ませていた、赤ちゃん爪柔らかいので割とこれだけでダイジョブだった
    • ある一定のライン(1歳が近づいたあたり)を超えたら大人と同じ爪切りに移行
  • アリエクで買ったやすいスマート温度湿度計
    • 夏の間だったのでとりあえず新生児期くらいは環境的な要因でなにか不快になる要素はなるべく減らしとこうと思い、これで26-28℃、湿度40-60%でアラーム設定してせっせと温度調整したり除湿機の水を捨てる仕草をやっていた

これではなかったけど同じようなやつを使ってた

ケトル、温度がみえてかっこいいけどお湯を入れすぎるとやや蓋が開きづらい、もうちょいシンプルなやつのほうが使いやすいかも

鼻吸い、後発品ということでお高かったけど構造的にチューブの部分に鼻水が入ってこず先端を洗って除菌じょ〜ずで消毒すれば良いので運用は結構楽だった、見た目もシンプルでよい

使わなかった / 使えなかったもの

  • 手動鼻吸い
    • ↑の通り使いこなせなかった
  • 赤ちゃん用綿棒
    • 小さいのでいまいち使いづらく、大人用綿棒でよかった
    • ワセリンと組み合わせて耳掃除するのに重宝
  • おむつ替えシート
    • 黄色い専用シート的なものをベビーザらスで買ってみたが我が子は動きがダイナミックだったせいか破けるしあまりよくなかった
    • ペットシーツがサイズ的にも耐久性的にもちょうどよくておすすめ
  • コンビ以外の肌着
    • 短肌着とかあまり着なかった、だいたいずっとコンビで、洗濯さえ回ってれば意外と少ない枚数でいけてしまった

LinuxにおけるMonitoringツールごとの使用メモリ算出いろいろ2023

サマリ

  • Linuxにおいて使用メモリの情報はだいたい/proc/meminfoの情報から計算されるが、計算式にゆらぎがあって異なるツールやSaaSエージェントを使うと結果が異なることがあるので故あって調べた
  • ダッシュボードの表示とfree(1)の結果が異なるなど
  • 2023現在使用メモリはだいたいMemTotal-MemAvailableということでOK
  • free(1)などprocps依存なコマンドもMemTotal-MemAvailableをUsedとして扱うようになる
  • 稀に計算式が異なるケースもあるのでおかしいな、と思うことがあれば一応まだ気にしたほうがよいことがあるかもしれない
  • ツールをまたぐ時は特に

各種SaaSやツールの状況

procps

  • v4.0.1からMemTotal - MemAvailable、それ以前はMemTotal - MemFree - Buffers - Cached - SReclaimable
  • 変更の経緯としてはコミットログからリンクされているが最終的にカーネルが推定する使用可能なメモリ以外をUsedとして扱うことになった
  • v4.0.1のリリースは2022/10/20でubuntuの現行LTSであるjammyで入ってくるバージョンはまだ3.3.17であり、将来的にバージョンアップが進んで4.0.1が取り込まれるとfree、top、vmstatなどprocpsを利用するツールも計算式が変わると思われる

gitlab.com

gitlab.com

Datadog

  • MemTotal - MemAvailableを出している
  • datadog-agentの実装をみるとAvailableの計算はshirou/gopsutilに依存していて、カーネル3.14より古い場合はこのアルゴリズムをベースに計算されているっぽい

github.com

github.com

Mackerel

  • MemAvailableを使える場合はMemTotal - MemAvailable、使えない場合はMemTotal - MemFree - Buffers - Cached(SReclaimableは含まれない)

github.com

github.com

node_exporter + Grafana Dashboard

  • node_exporterは/proc/meminfoをそのまま出力するのでダッシュボードの作り方に依存する
  • Node Exporter Fullの現在のバージョン(Revison29)においてはmemory basicの方はnode_memory_SReclaimable_bytesを考慮するようになっていてRAM Usedはtotal-availableになっている
  • 細かいバージョンは不明だが過去のバージョンではmemory basicの計算はSReclaimableを考慮しないMemTotal - MemFree - Buffers - Cachedだった

grafana.com

GCPOps エージェント)

この VM が使用したメモリの割合(ディスク キャッシュを除く)。Linux VM の場合はカーネルメモリも除外されるため、ユーザー空間のみの使用量になります。

  • メモリ使用率が上記の説明でMemory Usageにはusedというメトリクスがあるが、procpsの仕様とは違ってMemTotal-MemAvailableよりは低く、MemTotal - MemFree - Buffers - Cached - SReclaimableよりは高い値が出てるっぽい
  • 気が向いて時間があれば調べる

余談1 SReclaimableを入れるか入れないのかについて

  • procpsの実装はfreeのマニュアルにもある通りcachedが/proc/meminfoでいうところのCached+SReclaimableなので、Availableを使う計算式以前にMemTotal - MemFree - Buffers - Cachedという計算式がダッシュボードでよく採用されていた経緯が気になる(freeやtopの結果の結果と異なることになるので混乱があったのではと思うが)(単に読み違えたのか他に理由があったのか)
  • SReclaimableが含まれる場合、slab cacheは長期的に増えるので、生存期間の長いサーバでUsedが増えているように見えてユーザーが実行しているアプリケーションでリークが疑われるケースなどがあった(世の中的にもあったんじゃなかろうか
  • かつてあったこれとかもUsedに含まれて表示されると混乱したんじゃないかとか

余談2 Mackerelのめちゃ細かい話

  • Mackerelのグラフで表示される数値とfree -mの結果が微妙にずれるのだけどどうもこれはよくあるMB、MiBの違いっぽい
  • グラフ表示画面のリクエストみるとメトリクスはbyte単位で返しているのだけどグラフ描画時に単位ごとに/1000して表示してる模様
  • 単位はMB、GB等で表示されてるので間違いではないのだけど個人的にはMiB/GiBにしてくれると良いなあと思っている

SRE NEXT 2022で「プロダクション環境の信頼性を損ねず観測する技術」というお話をしました

登壇&参加エントリです。

ややエモよりになる予定。

当日の体験については他の登壇者の皆様とも少しお話したんですが、完全に馬場さんのエントリに書かれている点と同じ感想であり(事前収録は当日落ち着けてよい、参加者としてのZoom Event体験はかなり良かった、ブースの仕様はやや残念ではあったが個人的にはそれでも楽しめた)、まあ同じことを書いてもということで発表まわりや個別の参加体験の方を書いていきます。

登壇について

プロダクション環境の信頼性を損ねず観測する技術というタイトルで登壇させて頂きました。 6/9時点でまだスライドのみですが、ぼちぼちアーカイブの方も上がってくるかなと思います。


www.youtube.com

前回2020の登壇から2年、SRE NEXTが開催されたら何はともあれproposalは出したいと考えていたので募集の段階でネタを考えました。

ネタは2本考え、1つは長期運用した監視システムの移行についての事例を話すというものでしたがこちらはボツにして監視まわりのトラブルからのLesson Learned的な話一本に絞り、無事採択されました。

前回登壇の反省点として20分セッションに対して必要な背景説明が多くかなり駆け足になってしまったというのもあり、事例紹介もいいけどテーマ絞って背景はコンパクトにできれば聞く側も何を持ち帰ればよいのか?という部分に集中できてよいだろうという判断だったのですが、そうはいっても3事例入れて結果的に駆け足気味になってしまったという反省があります。次はもうちょっとうまくやりたい(再)。

狙いとしては、世の中エージェント入れてGet Startedしたらすぐにオブザーバリティが達成できますよみたいな紹介が多くあり、まあそれはそれで間違ってはいないのですが実際トラブルもあるし結局地道にエンジニアリング的な解決が必要になりますし、できれば実際に障害になる前にこういうことを考えたいよね・・ということで一部の人には刺さるかなーと思ってこういった内容にしました。

他方当日までこれ需要あるのかという不安もありましたが1、これも一つのSRE DIVERSITYということで(多分)採択していただき、技術的な理由によるサービストラブル事例みたいなお話がそれほどなかったというのもありありがたいことにはまった方もいたのではないかという感触でした。よかった。

次回以降、ちょっと現時点で不確定なことはありつつ、できればまた開催して頂ければproposal出したいし、たとえ通らなくても継続的に参加していきたいですね。

セッション、参加体験まわり

自分は特段コミュニティにがっつりというタイプでもないのですがぼんやりとtwitterでやってるなーと思っている方々と久々にお話する機会などありこういうのもトピック広いイベントの良さよなあと思うなどしていました。

全体の体験については冒頭に書いたんですがコミュニケーションツールがtwitterに寄せられてたのは個人的には良かったですね。

セッションについては諸事情によりメモにアクセスできなくなってしまっているのでいくつか思い起こしながら少し書くと、やはり(内容は雰囲気なりに)yuuk1さんのAIOpsのお話は面白く、これは特にご本人に伺ったわけではないので想像ですが課題感の設定やアプローチに実際のサービス運用経験が反映されてるんだろうなーと思いながら聞いてました。自分は監視システム運用する方なので、「これやるために大量のメトリクス扱わないといけないのでそっちはそっちでコストが・・」とか考えがちですが、こういった仕組みが人間の意思決定補助してくれる世界は期待したくなるところ。

LINEのmaruloopさんのお話fujiwaraさんのお話はそれぞれポストモーテムの運用に関する話で、このあたりは自分とこでも課題があり、最近だとシステム運用アンチパターンの9章「せっかくのインシデントを無駄にする」を眺めつつ、まあいきなりかっちりやるのは難しいにせよ、共有文化ややり方については大いに参考にしたいですねという気分になりました。

SRE DIVERSITY

これは誰に向けてなのかというところですがまあ個人的にこれでいいのではというメモとして、SREに関するトピックは非常に広く2、各社それぞれ組織的な取り組みをしていて素晴らしいと思うのですが、他方やはり結局解決しなければならない課題は組織のフェーズ、規模等々によって異なりますし、それぞれ必要だと思うプラクティスを取り込んで行けば良いし合わないものは無理に頑張る必要ないと思います。このあたりは技術選定に対する考え方みたいなのとあまり変わらないかなと。

自分に関していえば2020当時は自身の課題意識としてアラートなんとかしたい、という思いが強くそこにSRE本で提示されている考え方、プラクティスがはまったので自組織に合わせて適用していったという感じで特段それに関して「SRE導入しましょう」みたいな話はしなかったですし、そういったほうがうまくいくのであればすればよいのではくらいに考えてます。

やりたいことは目の前の課題をどうにかしたいであって、SRE的な考え方がはまればそれでいいですし、これは合わないとかtoo muchですねみたいなものはスルーする、SRE implements DevOpsだけど実装はある程度合わせたほうがワークするし、なのでSRE DIVERSITYということになるんだろうなあと(いや別にそういうわけではないというツッコミが入るかもしれませんが自分なりに)勝手に解釈しつつ、粛々と課題解決やっていきましょうという気持ちを述べておきます。

最後に運営各位楽しいイベントをありがとうございました。ささやかなブログポストであれですがこちらでも感謝を述べつつ締めたいと思います。


  1. 完全に余談ですがテーマ的には2020の方がproposal出して通るだろうという自信があり、他方今回は人をやや選ぶからどうかなあと思ってました

  2. 実際USENIXのSREConもかなり広範なトピックが取り扱われますし、LISAが21で終わりになってSREConに統合されそのあたりの大規模インフラ寄りな話も今後増えてくるのかなと思ってます