平常運転

アニソンが好き

過去記事とかは記事一覧で見れます

Apple M1 Mac で mackerel-agent を動かす

このエントリは Mackerel Advent Calendar 2020 の16日目です。遅刻です。

qiita.com

昨日は kazeburo さんでした。

kazeburo.hatenablog.com

今日は Apple M1 Mac で mackerel-agent を動かす話をします。
前日の "Apple M1 Mac で Go を動かす" の続きというつもりで書き始めましたが、気がつけばあまり関連性のないエントリになりました。

blog.astj.space

disclaimer

筆者 (id:astj) はこれを書いている現在 Mackerel の開発チームメンバー、いわゆる「中の人」です。

また、 Mackerel は mackerel-agent による Mac の監視を正式にはサポートしていません。開発チーム内に Mac ユーザーのエンジニアが多いことからある程度メンテナンスされているという実態はありますが、 Mackerel として正式に動作保証をしているものではない、という背景はご留意ください。

正式なサポート対象についてはヘルプをご確認ください。

mackerel.io

2022/2/8 追記

現在は、特別な手順を踏まなくても Homebrew tap 経由で Apple Silicon Mac 上で mackerel-agent を動かすことができます。
mackerel.io

Apple Silicon への対応はこのエントリで告知されていました:
mackerel.io

以下の内容は2020年末時点での古い内容となります。

おさらい: Intel Mac 上で mackerel-agent を動かす

まずは Intel Mac 上で mackerel-agent を動かしましょう。簡単にセットアップできるように Homebrew tap を公開しているので、 Homebrew の利用を避けたいということでない限りはおそらくこれが一番便利でしょう。

github.com

$ brew tap mackerelio/mackerel-agent
$ brew install mackerel-agent

Homebrew をデフォルトの /usr/local にインストールしているのであれば、mackerel-agent.conf は /usr/local/etc/mackerel-agent.conf にあります。APIキーなどを設定すれば、 Homebrew の brew services サブコマンド経由で agent を起動することが出来ます。

$ brew services start mackerel-agent # 停止するときは brew services stop mackerel-agent で


ログは /usr/local/var/log/mackerel-agent.log に出力されます。

Apple M1 Mac 上で mackerel-agent を動かす (Rosetta)

冒頭で触れた Apple M1 Mac で Go を動かす - 平常運転 でも触れましたが、 Apple M1 Mac 上では Intel Mac 向けのバイナリはネイティブには動作せず、Apple M1 Mac (arm64) 向けにビルドするか、あるいは互換レイヤーの Rosetta を経由して動かす必要があります。また、 mackerel-agent は Go言語で実装されているため、ビルドするための環境の制約もこのエントリ通りとなります。

qiita.com

Intel Mac 向けのバイナリの多くがそうであるように、 mackerel-agent も実は Rosetta を経由することで動作します。これも昨日のエントリそのままになりますが、 Homebrew を Rosetta 経由でインストールすれば、 Intel Mac と同様に動作します。
また、(mackerel-agent 自身が特別何かやってる訳ではないのですが) Rosetta がうまいことハンドリングしてくれているのか、 Intel バイナリの mackerel-agent から arm バイナリのプラグインを呼び出したり、あるいはその逆も問題なく動作してるように見えます。

f:id:astj:20201217001508p:plain
グラフを見ても何も分からないと思いますが、これは arm 向けにビルドした mackerel-plugin-uptimeRosetta の mackerel-agent から呼び出されています

ただし、maxOS 11.0.x で Rosetta 経由で mackerel-agent を動かしていると、時折 mackerel-agent がクラッシュする症状が確認されていました。こういう感じのログを吐いて止まってしまいます。

assertion failed [abi_info.kind == AbiKind::TranslatedCode]: emulated forward to an arm pc that isn't in translated code. arm_pc=0x101c574d8 abi_kind=6 emulation_interval=[0x101d7df68,0x101d7df7c) instruction_interval=[0x101d7df54, 0x101d7df7c) x86_rip=0x1043ab1
(ThreadContextRegisterState.cpp:677 move_to_instruction_boundary)

Rosetta が arm 向けに変換したコードを渡すべき場所で違うものを渡している、というログを読むにいかにも Rosetta の問題のように見受けられます。

おやおや……と思っていたのですが、本件とは直接は関係ない ARM Mac での Go の挙動に関する issue #42700 において、 macOS のバージョンが上がったことで Rosetta にも更新が入って挙動が改善したコメントがついているのを見かけています。手元の Mac mini (M1, 2020) の macOS を 11.1 に更新してから実際このクラッシュは出なくなっていますが、偶々運が良いだけなのか、それとも Rosetta 側に修正が入って無事解決した結果なのかはまだ調べられていません。。

Apple M1 Mac 上で mackerel-agent を動かす (Native)

前述の Rosetta によるクラッシュが確認されているうちは、ここで「ということで ARM ネイティブをビルドしてみましょう」という流れのつもりだったのですが、もし 11.1 で解決していたのならこのセクションは特に不要ということになります。悲しいですね。

arm64 ネイティブで動作する mackerel-agent は現時点ではまだバイナリの提供は行っていません。冒頭でも触れたように正式にサポートしているものではないので今後についてもお約束できる物はなにもないのですが、 Go 1.16 がリリースされて mackerel-agent 全体のビルドに使われるようになれば darwin/arm64 向けのバイナリも提供できるようになるだろうし、少なくともそれまでは提供されることはないだろう、と考えています(私見です!)。

ということで現時点、そしておそらく当面はソースコードから手元でビルドするしかないのですが、 Apple M1 向けの mackerel-agent は Go 1.15 系 ではビルドできず 、最新のソースコードからビルドした環境でビルドすることができます。 Apple M1 Mac 上で Go もコンパイルしたければ何度も言及している昨日の記事をご参照ください。Intel Mac からクロスビルドするなら gotip でセットアップするのが多分一番手軽です(ということにさっき気がつきました。。)

godoc.org

mackerel-agent のビルド自体は、 mackerel-agent のリポジトリトップで make build を行えば ./build/mackerel-agent がビルドされますが、gotip を利用する場合は Makefile の中で呼び出されている go コマンドの呼び出しを適宜 gotip に書き替える必要があるかもしれません。

Apple M1 上で動かす mackerel-agent のホスト情報

arm ネイティブで動かした mackerel-agent は、Mackerel の Web コンソール上のホスト情報ではこのように表示され、 "Apple M1" プロセッサを持つとしてレポートされます。

f:id:astj:20201216235645p:plain

この情報は、 macOS 11.1 では Rosetta 経由で起動していた場合も同じ情報が表示されます。つまりホスト情報だけ見ても区別がつきません。

f:id:astj:20201216235309p:plain

興味深いのは。macOS 11.0.x の時は、 Rosetta 経由で起動すると "VirtualApple" という 2.5GHz の CPU としてレポートされていたということです。

f:id:astj:20201216235402p:plain

mackerel-agent のこれらの CPU 情報は sysctl コマンドから得られ、特に CPU 名については sysctl -n machdep.cpu.brand_string で得られる値を報告しているのですが、この値が 11.1 で変更されていたようでした。 mackerel-agent における CPU 情報の取得コードはこのあたりです。 mackerel-agent/cpu.go at master · mackerelio/mackerel-agent · GitHub

11.1 になったことで Web コンソール上では Rosetta 経由なのかネイティブなのか分からなくなってしまった訳ですが(そもそもこれで困る人はいるのか???)、ホストのメタ情報の JSON 全体を API 経由で取得すれば、これらの違いを識別することは引き続き可能です。
ネイティブで動作している mackerel-agent の場合、ホストのメタ情報のうち kernel に関しては以下の物が格納されています。たとえば machine には実行アーキテクチャである "arm64" が記録されています。

{
  "machine": "arm64",
  "name": "Darwin",
  "os": "Darwin",
  "platform_name": "macOS",
  "platform_version": "11.1",
  "release": "20.2.0",
  "version": "Darwin Kernel Version 20.2.0: Wed Dec  2 20:40:21 PST 2020; root:xnu-7195.60.75~1/RELEASE_ARM64_T8101"
}

いっぽう、Rosetta 経由で実行した場合は、プロセスからは x64 環境で動作しているかのように見えるため、その環境下で mackerel-agent が収集した machine には "x86_64" が記録されています。また、よく見ると version には ARM 向けのカーネルである旨も読み取れそうですね。

{
  "machine": "x86_64",
  "name": "Darwin",
  "os": "Darwin",
  "platform_name": "macOS",
  "platform_version": "11.1",
  "release": "20.2.0",
  "version": "Darwin Kernel Version 20.2.0: Wed Dec  2 20:40:21 PST 2020; root:xnu-7195.60.75~1/RELEASE_ARM64_T8101"
}

これらのカーネル情報は mackerel-agent では uname コマンドや sw_vars コマンドから取得しています。
mackerel-agent/kernel.go at master · mackerelio/mackerel-agent · GitHub

Macの未来へようこそ。

ということで、本稿では Apple M1 Mac における mackerel-agent 事情の話をしました。くどいようですが Mac はそもそも Mackerel で正常に動作サポートしている環境ではない上に、 Apple M1 において簡単にセットアップできる環境の提供もまだ先になりそうですが、お手元に Apple M1 Mac をお持ちで興味がある方はお試しいただければ幸いです。そして、お試していただいた後は不要なホストを退役させることをお忘れなく。。。

前日に引きつづき投稿が24時を越えてしまって無事遅刻となりましたが、明日(今日)は id:missasan さんです。今見たらもう公開されていました。

missasan.hatenablog.com