YAMAGUCHI::weblog

海水パンツとゴーグルで、巨万の富を築きました。カリブの怪物、フリーアルバイター瞳です。

Raspberry Pi Zero WとStackdriver Monitoringで部屋の空気のモニタリングをする

はじめに

こんにちは、Stackdriver担当者です。同僚の @proppy と Pimoroni 見てたら、便利そうなHATとセンサーがあったので買って遊んでいます。

TL;DR

BME680で取得したデータをStackdriver Monitoringでダッシュボード作って見てみると楽しい。

BME680

BME680とは

BME680は、BOSCH製の空気質センサーで、この3mm四方の小さなセンサーだけで気温、湿度、大気圧、空気質が測定できます。

BME680

さらにこのセンサーのブレイクアウトがPimoroniから販売していて、I2Cを使って簡単に数値を読み取れるというわけです。

セットアップ

RaspberryPi Zero W は Raspbian (Stretch) が動いている前提です。

$ sudo apt-get install python3-venv i2c-tools read-edid libi2c-dev python3-smbus
$ python3 -m venv --system-site-packages .venv
$ .venv/bin/pip install bme680
$ wget https://raw.githubusercontent.com/pimoroni/bme680-python/master/examples/read-all.py
$ .venv/bin/python3 read-all.py

これでちゃんと数値が表示されたらBME680を無事に認識しているので準備完了。 これを使って部屋の気温、湿度、気圧、空気室などを記録してみます!

Stackdriver Monitoring へのデータの送信

Stackdriver Monitoringとは

Stackdriver Monitoringは、通常Monitoring Agentと呼ばれるエージェントをインスタンス上で実行し、システムやアプリケーションのメトリクスをサンプリングすることを想定しています。特によく利用されるデータベースやミドルウェアに関しては事前定義のメトリクスを簡単にStackdriver Monitoringに送信できます。

カスタム指標(カスタムメトリクス)

そして、もちろん自分のアプリケーションの状況を伝えるためのカスタム指標をエージェント経由で送信することもできますが、今回は別の方法としてStackdriver Monitoring API v3 を使って送信してみます。

cloud.google.com

今回は上のようにBME680のデータをPythonで取ってきているので、そのままPythonクライアントを使って送信しようと思います。

ライブラリセットアップ

上記に加えて google-cloud-monitoring のパッケージをインストールする必要がありますが、ここで一つ嵌りどころとして依存先の grpcio パッケージのインストールがあります。Raspberry Pi はSDカード上でOSを走らせているので、なるべくSDカードの寿命を延命させるために /tmp/var/tmp を tmpfs 上でマウントしたりします。自分も何も考えずにそうしていたのですが、これが grpcio パッケージのインストール時にネックとなります。

google-cloud-monitoring パッケージが依存している grpcio パッケージの最新バージョンは本記事執筆時当時は 1.19.0 です。執筆時の Raspbian Stretch でのデフォルトのPython 3のバージョンは 3.5 なのですが、上のPyPIのページを見るわかるように 1.19.0 には CPython 3.5 の ARMv6ターゲットの wheel がありません。 また piwheels を見ても 1.18.0 までは CPython 3.5 の ARMv6 ターゲットの wheel があるのですが、1.19.0 はありません。

そうなると手っ取り早い方法としては選択肢は2つなります。*1

  1. constraints.txt などで grpcio パッケージは 1.18.0 以前に固定(依存的には 1.8.0 以上であればよい)し、 --extra-index-url=https://www.piwheels.org/simple のオプションを pip install に加える
  2. grpcio 1.19.0 をローカルでビルドすることに決めて、 pip--build--cache-dir のオプションを /tmp 以外の場所に設定する

自分は新しいライブラリで問題ないかも確認したかったので grpcio 1.19.0 をローカルでビルドすることにして、何も設定せずにそのまま google-cloud-monitoring パッケージをインストールしました。(結構時間がかかる)

$ TMPDIR=$HOME/tmp .venv/bin/pip install --cache-dir=$TMPDIR/cache --build=$TMPDIR/build google-cloud-monitoring

1. メトリクスの作成

先に挙げたドキュメントのとおりなのですが、カスタムメトリクスを記録するためには、まずカスタムメトリクス自体をStackdriver Monitoringに登録する必要があります。 流れとしては

  1. Stackdriver Monitoringのクライアントのインスタンスを作成
  2. MetricDescriptorインスタンスを作成し、カスタムメトリクス名、メトリクスのタイプ、メトリクスの値の型、メトリクスの説明書き、メトリクスのラベルを設定
  3. クライアントに今作成した MetricDescriptorインスタンスを渡して、メトリクスを作成

のようになります。次は temperature というカスタムラベルを作成しています。実際にはセンサーが取得できる presssurehumiditygas_resistance についても同様に作成しています。

client = monitoring_v3.MetricServiceClient()
project_name = client.project_path(project_id)

descriptor = monitoring_v3.types.MetricDescriptor()
descriptor.type = "custom.googleapis.com/temperature"
descriptor.metric_kind = (
    monitoring_v3.enums.MetricDescriptor.MetricKind.GAUGE)
descriptor.value_type = (
    monitoring_v3.enums.MetricDescriptor.ValueType.DOUBLE)
rainfall_label = descriptor.labels.add()
rainfall_label.key = "rainfall"
rainfall_label.value_type = (
    monitoring_v3.enums.LabelDescriptor.ValueType.INT64)
rainfall_label.description = "rainfall observation report from weather forecast service"
descriptor.description = "room temperature"

descriptor = client.create_metric_descriptor(project_name, descriptor)

ここでメトリクスのラベルを設定していますが、これは取得するメトリクスに紐づいて取得時ごとに変化する付加情報を入れるためのものです。今回のサンプルでは温度や湿度を取るわけですが、その際に外の天気との関係性を知りたくなるでしょう。そのため、天気予報サイトから雨量の情報を取得し、 rainfall ラベルに入れることにしました。

実際のユースケースでは、例えばウェブアプリケーションの場合、「レスポンスデータのサイズ」をメトリクスにしていた場合、ステータスコードが400番台のものだけのグラフを作りたい場合に、「ステータスコード」をラベルとして設定しておきます。

またこの create_metric_descriptor はまったく同盟のメトリクスが存在する場合は特にエラーが起きず上書きされ、エラーになることはありません。(メトリクスが存在するかどうか事前に確認しなくても大丈夫です。)

これをプログラムの開始時にだけ1度実行します。

2. メトリクスデータの書き込み

こちらもドキュメントのとおりです。ある瞬間のセンサーデータを登録する場合の流れは

  1. TimeSeries インスタンスを作成
  2. カスタムメトリクス名、メトリクスのラベルの値を設定
  3. リソースのラベルを設定
  4. TimeSeries にメトリクスデータが入った Point を追加
  5. クライアント経由で TimeSeries をStackdriver Monitoringに送信
# 1. TimeSeriesの作成
series = monitoring_v3.types.TimeSeries()
# 2. カスタムメトリクス名、メトリクスのラベルの値を設定
series.metric.type = "custom.googleapis.com/temperature"
series.metric.labels['rainfall'] = fetch_rainfall()
# 3. リソースのラベルを設定
# https://cloud.google.com/monitoring/custom-metrics/creating-metrics#which-resource
series.resource.type = 'generic_node'
series.resource.labels['location'] = 'asia-northeast1-a'
series.resource.labels['namespace'] = RESOURCE_NAMESPACE
series.resource.labels['node_id'] = socket.gethostname()
# 4. `TimeSeries` にメトリクスデータが入った `Point` を追加
sensor = bme680.BME680() # 実際はプログラム起動時にインスタンス作成
sensor.get_sensor_data()
point = series.points.add()
point.value.double_value = value
now = time.time()
point.interval.end_time.seconds = int(now)
point.interval.end_time.nano = int(
    (now - point.interval.end_time.seconds) * 10**9)
# 5. クライアント経由で `TimeSeries` をStackdriver Monitoringに送信
client.create_time_series(project_name, [series])

リソースのラベルを設定する部分では generic_node を設定しています。(本来は global を設定すべきかも)リソースラベルはメトリクスラベルと違い、時間が経過してもそのデータを取得する上において変化しない属性を記録します。たとえば、マシンのホスト名などです。

どのリソースタイプでどのリソースラベルを設定するかは次のページに記載されています。

Point の追加で注意しなければいけないことは、TimeSeries を送信する際には Point が2つ以上含まれていてはいけないということ。公式ドキュメントを引用します。

When creating a time series, this field must contain exactly one point and the point's type must be the same as the value type of the associated metric. If the associated metric's descriptor must be auto-created, then the value type of the descriptor is determined by the point's type, which must be BOOL, INT64, DOUBLE, or DISTRIBUTION.

したがって、上のように Point を1つだけ追加しておしまいです。 *2

逆に TimeSeriesインスタンスはクライアント経由でまとめて送信できます。今回はセンサーで取れる値が温度、湿度、気圧、空気質の4つあるので、上と同じ流れで4つ TimeSeries をつくって、まとめて送信します。

これを10秒おきなど、定期的に実行します。

Stackdriver Monitoringの設定

以上のようなコードでデータをStackdriver Monitoringに送信し続けると、ダッシュボードでメトリクスとして選択できるようになります。

f:id:ymotongpoo:20190318084145p:plain

この自分で作成した custom/temperature のメトリクスを選択すると、送信されたデータを元に作成されたグラフが表示され、さらにFilterの項目ではリソースラベルとメトリクスラベルでの絞り込みができるようになっています。

f:id:ymotongpoo:20190318084514p:plain

それ以下、Aggregationの項目ではグラフの書き方などについての一般的な設定を行っていき、SAVEボタンでチャートを保存します。そのようにして以下、湿度、気圧、空気質に関しても同様に行っていくとダッシュボードが完成します。

f:id:ymotongpoo:20190318084736p:plain

部屋の温度が日の出とともにぐっと上昇する様子や、湿度が人間の生活時間に合わせて上昇する様子、今日は高気圧であるなとわかるなど、記録を取るだけでかなり面白かったです。次はこれを複数台に増やしてチャートに重ねてみようと思います。

参照

BME680

Stackdriver Monitoring V3

*1:他にも自分でQEMUを使ってビルドする方法などもあります

*2:Pointのintervalでend_timeしか設定していないのは、start_timeがoptionalだからです。詳細はproroファイルを参照。

好きなものづくり系YouTubeチャンネル

はじめに

こんにちは、Stackdriver担当者です。唐突にどうでもいいエントリーですが、日曜の夜なのでたまには息抜きもいいかなと思ったので、自分が好きなYouTubeチャンネルを紹介します。

Primitive Technology

www.youtube.com

このチャンネルは名前の通り、原始的な技術を実際に試してみるという動画です。一人の白人男性がボロいハーフパンツ一丁で出てきて、無言でひたすら穴をほったり、土を練ったり、葉っぱを編んだり、しながら家を建てたり、瓦を焼いたり、鉄を精製したり、というのを眺めるだけのチャンネルです。

このチャンネルを見てると、小さい頃に泥遊びや秘密基地ごっこをしていた思い出が蘇ってくるのですが、大人が本気をだすとこういうことになるのかと感心します。多くのフォロワーチャンネルも開設されていますが、やはりオリジナルというべき味わいがあるので、まずはこちらをチェックすることをおすすめします。

JSTサイエンスチャンネル (jstsciencechannel)

www.youtube.com

科学技術振興機構 が公開しているチャンネルなのですが、なぜかチャンネルタイトルをちゃんと設定してくれていないので、担当者の方がこの記事を見ることがあったらぜひチャンネルタイトルをわかりやすい日本語にしてあげてください。

さて、私は工場見学が好きで、普段見れないような施設を見学する機会があれば極力参加する類の人間なのですが、そんな自分が大好きで見ているのがこのチャンネルの「THE MAKING」シリーズです。

www.youtube.com

www.youtube.com

スペシャル版を除き、基本的に15分程度でいろいろな身近なものが作られる工程を動画で説明してくれます。個人的には食品系の回は面白いのでよく見ています。

たまにコメント欄が大盛り上がりすることがあり、コメントを読んでる間に動画が終わってしまうこともあります。またゆるい音楽と淡々とした字幕だけの解説のせいで催眠効果もかなりすごく、疲れていると冒頭の2分だけ見て寝てしまうこともあります。

Baumgartner Restoration

www.youtube.com

このチャンネルも趣としてはPrimitive Technologyと似ているのですが、美術館に飾ってあるような古い絵画をいかに再生させるかを事細かに説明しているチャンネルです。基本的には古い絵が出てきてそれを修理するだけなんですが、映像が綺麗なのと淡々としているので、流しっぱなしにしていてもうるさくないのが気に入っています。

次世代に繋ぐ伝統建築【先人の知恵を記憶する】

www.youtube.com

小林建工という愛媛の工務店が運営しているチャンネルです。小林建工の会社サイトの概要にあるように、日本建築の伝統技能の伝承に情熱を持っている方が代表を務めているようで、それもあってチャンネルには数多くの日本建築の技法を紹介する動画が掲載されています。最近更新されていないですが、1年前の更新の前は3年前だったりするので、気長に更新されるのを待っています。

Boston Dynamics

www.youtube.com

言わずと知れたBoston Dynamicsのチャンネルです。新型ロボットが公開されるたびに、今回はどんないじめ方でロボットの安定性テストをしているのだろうかと気になってしまいます。ほそぼそと更新が続いているので通知が来るのをいつも楽しみにしています。

Torbjörn Åhman

www.youtube.com

ひたすら工具を自作するところを撮った動画が載っているチャンネルです。鉄を熱くして、叩いて伸ばして穴を空けて、というのを淡々と長柄めているのはなかなかに心が落ち着きます。

おわりに

こういうものづくり系チャンネルが大好きなので、他にもおすすめがあったらコメント欄などで教えてください。

恵贈御礼「入門 監視」読了

はじめに

こんにちは、Stackdriver担当者です。年明けに「入門 監視」を恵贈頂いたのですが、書評を公開するのが遅くなってしまいました。すでに多くの方が書評を公開していらっしゃいますが、そちらは気にせず自分の書評をメモ代わりに書いておこうと思います。

入門 監視 ―モダンなモニタリングのためのデザインパターン

入門 監視 ―モダンなモニタリングのためのデザインパターン

TL;DR

  • 本書を読んでも即座に監視に関する問題が解決するわけではないが、システム監視について何から始めれば良いかわからない人はまず手にとるべき本であると思う。
  • 本書とSRE bookを読むことで同じ内容を異なる角度から捉える事ができ、非常に有益。

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

感想

全体として

  • 1章 監視のアンチパターン
  • 2章 監視のデザインパターン
  • 3章 アラート、オンコール、インシデント管理
  • 4章 統計入門
  • 5章 ビジネスを監視する
  • 6章 フロントエンド監視
  • 7章 アプリケーション監視
  • 8章 サーバ監視
  • 9章 ネットワーク監視
  • 10章 セキュリティ監視
  • 11章 監視アセスメントの実行
  • 付録A 手順書の例:Demo.App
  • 付録B 可用性表
  • 付録C 実践.監視SaaS

本書の目次を見て分かるとおり、前半で監視の設計手法や取り組み方に関してから始まり、後半でシステム内の各構成部品に対する監視の概要を見ていくという内容でした。よって、本書一冊ですべてが解決するという辞書のような使い方ではなく、本書で大まかに監視全体を把握するのに向いていると思いました。

特に今2019年現在において「監視」というのがどのような取り組み・行為なのかを解説した本として充実していました。現代での「監視」のスナップショットの確認として、さらっと一度流し読みするだけでも価値があると感じます。

システムアーキテクチャ・開発手法の変化による監視手法の変化

本書で最も特徴的であり、自分が大きく賛同した部分は、本書が「システムアーキテクチャや開発手法が変化したことにより、監視手法も変化してきている」という点を様々な角度から論じていた点です。

各章で語られていたことを簡単に抜粋してみます。

1.2 アンチパターン 2: 役割としての監視

監視とは役割ではなくスキルであり、チーム内の全員がある程度のレベルに至っておくべきです。(中略)監視の旅へ進むに当たって、皆が監視について責任を持つことを主張してください。

2.1 デザインパターン 2: ユーザ視点での監視

まず監視を追加すべきなのは、ユーザがあなたのアプリケーションとやり取りをするところです。

3.2.3 上手にオンコールローテーションを組む

ソフトウェアエンジニアもオンコールのローテーションに入れることを強くおすすめします。

5.4自分のアプリケーションにそんなメトリクスはないという時は

必要な計測データをアプリケーションが出してくれないなら、自分でアプリケーションを変更してしまいましょう。

6 フロントエンド監視

そして、時と共にパフォーマンスが悪くなってしまわないように、既存のツールにフロントエンド監視をどのように組み込んでいくのかを考え、この章の仕上げとします。

7 アプリケーション監視

アプリケーションのメトリクスはいろいろなことにとても便利に使えるので、なぜすぐ始めなかったのか不思議に思うくらいでしょう。

7.6 マイクロサービスアーキテクチャを監視する

マイクロサービスがあらゆるものを飲み込みつつあるこの世界では、優れた監視の仕組みを持つことは絶対条件になっています。

ざっくりと抜粋しているので、上記の引用だけでは読み取りづらい部分があると思いますが、私はこれらはすべてDevOps、さらにはSRE的なアプローチによって、アプリケーションとインフラを区別して捉えるのではなく、システム全体として期待されるとおりに稼働しているかを捉えることが重視されるようになったことが影響していると考えています。

またクラウド上でシステムを動作させることが増え、アプリケーションのモジュール化も進み、それに関わるインスタンスの台数も需要に応じて柔軟に増減するようになってきていることで、インスタンス自体のメトリクスよりも、アプリケーションに係るメトリクスが与える影響が大きくなっていることも関係があります。

これらによって、監視そのものが「インフラチームがアプリケーションランタイムの安定性を見る」という性質から「システム全体として期待した動作を行っているかの確認をする」という性質に大きく変化しています。当然その変化の中で、アプリケーションエンジニアが監視や運用に参加することの必要性も高まってきています。

そうした運用手法としてDevOpsを推し進めたものの一つがSite Reliablity Engineering (SRE) だと思いますし、そのような監視をどのように行うかというのを一貫して紹介したのが本書だと感じました。

また使用するランタイムの性能が向上していることもこれらを支える一助となっているでしょう。「1.1.1 監視とは複雑な問題をひとくくりにしたもの」の節のコラム「観察者効果は気にしない」には次のようにあります。

観察者効果とは(中略)技術分野では、監視ツールがシステムに負荷を加えてしまうことを指すことが多いですが、これは大した問題ではありません。今は2017年で、1999年ではありません。

Application Performance Management (APM) においては、トレース情報やプロファイル情報をサンプリングして取得する手法が主になっています。これらが許容されるようになったのはサンプリングを行ってもアプリケーションに与える影響が問題ないくらいマシンのCPUやメモリ、あるいはネットワークなどの性能が高まったからでしょう。

乱暴に言えば、クラウドではアプリケーションランタイムとしてのインスタンスは即座に上位性能のものに入れ替えられる一方でアプリケーション自体は、その開発フェーズが進めば進むほど、即座の置き換えが難しくなります。そうしたこともAPMなどといったアプリケーション側の監視の比重が高まってきている要因でしょう。

本書では「6章 フロントエンド監視」「7章 アプリケーション監視」と2章を割いて、アプリケーション側の監視の考え方を紹介していて、そういったものを導入しようとしている人向けに良い入門になっていると感じました。

SRE bookと重なる部分

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

上のような理由から、同じオライリーで発刊されている「SRE サイトリライアビリティエンジニアリング―Googleの信頼性を支えるエンジニアリングチーム」(SRE book)の内容と重なる部分や、SRE bookでより詳細に説明されている内容なども見受けられました。いくつか抜粋します。

2.1.1 監視サービスのコンポーネント

ペナルティ事項の存在しないSLAは、むしろ「目指すべき目標」と一般的には捉えられます。

この用語を区別するためにSREではSLI、SLO、SLAとサービスにおける指標、目標、契約を呼び分けています。

1.5 アンチパターン 5: 手動設定

もし手順書が単なるやることの羅列なら、さらなる自動化が必要です。

3.1.6 まずは自動復旧を試そう

アラートに対する代表的なアクションが、既知でかつ用意されたドキュメントの手順に沿って対応するだけなら、コンピュータにその手順をやらせない理由はありません。

これはまさにトイルの撲滅そのものです。

3.4 振り返り

振り返りには良くない習慣があることに私は気づきました。それは誰かを非難するという文化です。

これに関してはSRE bookにある「非難のないポストモーテム (Blameless Postmortem)」にも詳細に書かれています。

監視とは、システムを見守るという行為なので、システムの信頼性を担保する役割であるところのSREチームには大きく関係するところであり、こうした内容が重なるのは当然でしょう。

しかしとはいえSRE bookはかなりの重量級(B5版 590ページ)です。ましてこれからそうしたことに取り組もうと思っている方は、読もうと思っても、その重量に圧倒されかねません。その点入門監視はA5版 200ページとあっさり読める内容です。深堀りはしていなくても、監視の全様を大まかに把握するにはうってつけです。本書を読んでから、あらためてSRE bookを読んでみるというのも手だと感じました。

付録C 実践 監視SaaS

私が本書が翻訳版として価値があると感じたのは、もちろん「付録 C 実践 監視SaaS」です。こちらは監視SaaSであるMackerelの @Songmu さんが書き下ろしとあって、監視SaaSの利点、信頼性、選定ポイント、利用方法について、本文でぼかされていた部分を一歩踏み込んで解説し、即座に実践に活かせる内容となっています。

私も冒頭で述べているようにGoogle Cloud Platformの Stackdriver という監視SaaSの担当をしているのでうなずくことばかりです。

Stackdriverにはロギング分散トレースプロファイラモニタリングダッシュボードエラーレポートデバッガといった製品群があります。 本書で触れられていた内容に関しては一通りカバーしている製品群で、特に特徴としてはまさに本書のような現代的な監視手法を導入しやすくしている点(例: ログベースメトリクスの作成、OpenCensus を利用したアプリケーションメトリクスの取得、分散トレース、フレームグラフが見えるプロファイラなど)です。

これも主にGCP上でシステムを動かす開発者・運用者が、即座にSRE的な監視を行える機能を提供するという目的があって開発されているためです。(たとえばGoogle App Engine Standardでは分散トレースやログベースメトリクスなどはインストゥルメンテーション無しで即座に行えるようになっています)

クラウドプラットフォーム事業者が監視SaaSを提供する利点は、一番下のレイヤーまでできるだけ多くの情報を提供でき、他のサービスとの連携も図りやすい点にあります。(先程のGAEの例をはじめ、GKEでもアプリケーション側のインストゥルメンテーションのみでロギングや分散トレースやプロファイラとの連携可能です)

この付録Cを通じて、監視SaaSを導入する企業が増え、Stackdriverにもより多くのフィードバックが来ることを期待しています。GCPUG Slack の #stackdriver チャンネルにいますので、利用してみて疑問に感じたことがあればぜひ来てください!

gcpug.jp

参照

OpenCensus + Stackdriver Trace で分散トレース上にログを表示する

はじめに

こんにちは、Stackdriver担当者です。いま出張でアメリカ西海岸に来ていますが、時差ボケで破滅しています。

GCPUG Stackdriver Day January 2019でStackdriverを使った分散トレースにログを埋め込む話をしたんですが、スライドだけだともったいないと言われたのでブログの記事にもしておこうかと思います。

OpenCensusとはなにか

そもそもOpenCensusを知らないという人もまだ多いと思うので、まずそこから紹介します。OpenCensusは分散アプリケーションのメトリクスとトレースを取得するためのライブラリ群です。

opencensus.io

分散トレースのライブラリは各種APMサービスがそれぞれクライアントライブラリを出していますが、OpenCensusが特徴的なのは、TraceやStatsを取得する部分と、取得されたデータをバックエンドに送信する部分(exporter)が別れているので、バックエンドを切り替える際もexporterのインスタンスの初期化だけ書き換えれば動作するようになっていることです。また自分で独自のexporter(例: 標準出力に記録するだけのexporter)を書くこともできます。

現在 OpenCensus をサポートしているAPMツールはこちらに一覧として載っています。

opencensus.io

また今後の方向性としては OpenCensus Agent を通じてデータを送信するように変更し、これによって OpenCensus Agent 側で exporter を切り替えるだけでバックエンドが変更できるようになり、切り替えのためにソースコードを変更しなくて良くなるようにしていく予定になっています。

Stackdriver Trace

Stackdriver Trace は Google Cloud Platform が提供する APM (Application Performance Management) ツールの一つですが、特に分散アプリケーションのトレース(分散トレース)を主力機能として提供しています。Stackdriver Trace はクライアントライブラリとして OpenCensus を利用するように推奨しています。推奨しているということは当然 exporter もあります。

github.com

OpenCensusを使ってStackdriver Traceを利用する場合、Goではinstrumentationは次のようになります。

Stackdriver Trace のタイムライン内にログを埋め込む

上のサンプルのように各アプリケーション(例えばGKEクラスタで動かしている各サービス)で Trace と exporter の設定をしてからリクエストを投げてやると、次のような形で分散トレースを生成できます。

f:id:ymotongpoo:20190212082459p:plain

これでもマイクロサービス内のどこで処理時間がかかっているか簡単にわかりますが、このタイムラインの中で各Span(各サービスで行われる処理のまとまり)内で起きたイベントを確認できると便利そうです。Stackdriver Trace では Stackdriver Logging へ送信された構造化ログの中に次の2つのフィールドに適切な値が入っていた場合、そのログを Stackdriver Trace の中に表示させることができます。

  • logging.googleapis.com/trace
  • logging.googleapis.com/spanId

これら2つのフィールドに必要な Trace ID および Span ID はそれぞれHTTPヘッダやgRPCの特殊フィールドに埋め込まれていて、通常は OpenCensus のライブラリがよしなに取得できるようにしてくれています。再び Go の例で書けば次のような操作で取得できます。

func (ap *arrayParseServiceServer) Parse(ctx context.Context, pr *pb.ParseRequest) (*pb.ParsedArray, error) {
    span := trace.FromContext(ctx)
    sc := span.SpanContext()
    l := logger.WithFields(logrus.Fields{
        "logging.googleapis.com/trace": sc.TraceID.String(),
        "logging.googleapis.com/spanId":  sc.SpanID.String(),
    })
    ...
}

GKEではStackdriver Logging のエージェントが自動設定されるので、標準出力に構造化ログを出力するだけで Stackdriver Logging に送信されます。上記のフィールドに正しい値が入ったログが Stackdriver Logging に送信されると、Stackdriver Trace がそのログの中にある Trace ID と Span ID をトレースに紐づけ、タイムライン内に表示します。(タイムライン右上に [Show/Hide Logs] というボタンが表示され、ログの表示/非表示を切り替えられるようになります。)

f:id:ymotongpoo:20190212083746p:plain

またタイムライン内のログをクリックすると、画面右下に構造化ログ全体が表示されます。

f:id:ymotongpoo:20190212084113p:plain

この機能はGAEを使っていた方にはおなじみだったかもしれませんが、GKEを使っている場合においてもちょっと手を加えるだけで使えるようになるので、GKEで分散トレースを考えている場合にはぜひ利用してみてください。

参照

skaffoldのdefault repoの設定はグローバルでなくkubectlのコンテキスト依存

何が起きたか

GKEで新たなクラスタを建てて skaffold dev をしたら次のエラーで止まった。

exiting dev mode because first run failed: build failed: building [xxxxxx]: tagging: pushing: denied: requested access to the resource is denied

後半はDockerでレポジトリのアクセスが出来ない時のエラーなので、ログをちょっと遡ると原因となるものがあった。

The push refers to repository [docker.io/library/xxxxxx]

本当なら docker.io/library ではなくて gcr.io/<MY REPOSITORY> を見ていないといけない。

どうしてこうなったか

まず skaffold.yamlartifacts でターゲットのレポジトリの設定をしていないから。

しかし設定していない理由があって、skaffold.yaml でレポジトリの設定をしてしまうと、テストとかで動かすときにいちいち書き換えなければならないので面倒。 固定でいいならはじめから artifacts にレポジトリを明示的に指定しておけば良い。こんな具合に。

apiVersion: skaffold/v1alpha1
kind: Config
build:
  artifacts:
  - imageName: gcr.io/<MY REPOSITORY>/foo
    workspace: ./foo
...

skaffold には新しいオプションが加わって、最近レポジトリを動的に差し込めるようになった。

skaffold.dev

どうせ自分のテスト環境はレポジトリ1個しかないので「グローバルの設定」で済まそうと思って3つめのオプションを選択。 最初に設定したときはこれで問題なかったが、テスト用に新たにGKEクラスターを作って古い方を消したときに上記の問題が起きた。

再度手順を振り返って一つずつコマンドを叩いて確認してみると

$ skaffold config set default-repo gcr.io/yoshifumi-cloud-demo
set value default-repo to gcr.io/yoshifumi-cloud-demo for context gkc_yoshifumi-cloud-demo_<ZONE>_<CLUSTER_NAME> 

これは普通に kubectl のコンテキストに紐付いていて、実際に skaffold の設定ファイル(~/.skaffold/config)を見るとそうなっている。

kubeContexts:
- kube-context: gke_yoshifumi-cloud-demo_<ZONE>_<CLUSTER_NAME>
  default-repo: gcr.io/yoshifumi-cloud-demo

というわけで

  • skaffold.yamlartifacts でイメージ名内に明示的に指定していなかったこと(これは意図的)
  • グローバルに設定されると思ってたがそれがドキュメントバグらしいということ

の2つが原因だった。

どうするのがいいか

とりあえず2つめのオプションである SKAFFOLD_DEFAULT_REPO を都度渡すというのが良さそう。つまり

$ SKAFFOLD_DEFUALT_REPO=gcr.io/yoshifumi-cloud-demo skaffold dev

のような形にするということ。この辺りの処理はこの辺で実装されている。(2019.01.23現在 master)

github.com

しかしこのドキュメントは明らかにミスリードなので報告しとこう。。。

Change the explanation of "default repo" setting in the doc to reflect actual implementation · Issue #1516 · GoogleContainerTools/skaffold · GitHub