FluentdでYAMAHA RTX1200のログを収集してみる
なんとなく大量に溜め込んでいたYAMAHA RTX1200のログを死蔵するのではなく、勉強に使ってみようということでFluentd + Elasticsearch + Kiabanaでイケイケビューなログビューを作りたいと思った。まずはFluentd編ということで。
使用用途として合ってるのか知らないけれども、うまく行けば自宅に物理で140本を超える可愛い女の子と付き合うゲームの整理にも使えないかなと思う。流石に100本を超えだすとわからないですね。
fluentdの流れ
適当に設定して済ませたかったが、やはり無理だった。なので、fluentdの処理の流れを理解する必要がある。
FluentdにてやってきたデータがどのようにしてDBなどに保存されるかの流れを公式のスライドで示す。
fluentdでは基本的に(1)データを取得(source
, where all the data come from?)し(2)fluentdでそのデータに対して何をやらせるか(match
, tell fluentd what to do)を記述していく。なお、このデータ取得からデータ処理の間でなにか別の処理をさせる(ex: ホスト名を追記する)といったこともできる(filter
, Event processing pipeline)。
source
: Where all the data come from
fluentdにデータ(=ログデータ)がどのように入力されるかを記述する。 難しい話ではなく、ログデータのを取得するために純粋にファイルで入力しますか、標準入力ですか、HTTP APIを叩きますかを指定するということ。
例えば、公式ドキュメントに例として以下のようなconfigが示されている。
# Receive events from 24224/tcp # This is used by log forwarding and the fluent-cat command <source> @type forward port 24224 </source> # http://this.host:9880/myapp.access?json={"event":"data"} <source> @type http port 9880 </source>
1個目の source
は fluent-cat
という echo '{"message":"hello"}' | fluent-cat debug.log
といった形でパイプでfluentdにログを飛ばすことができるコマンドからログを取得するという設定。2個目は http://this.host:9880/myapp.access?json={"event":"data"}
というようなAPIエンドポイントをHTTPで叩いてログを取得するという設定。
ここまでで「何をするためにsourceを書くのか」はわかったが「じゃあ、どう書くのか」が実際にコンフィグを書く段になって困ってくる。そこで登場するのが公式ドキュメントの"Plugin Common Parameters"と'Input Plugins" 。基本的に、ここにあるプラグインを使って source
を記述していく。
例えば、ファイルからログデータを取得するとなると in_tail
プラグインを使う。
<source> @type tail path /var/log/httpd-access.log pos_file /var/log/td-agent/httpd-access.log.pos tag apache.access <parse> @type apache2 </parse> </source>
Fluentdではプラグインを @type
で指定し、そのあとに各プラグイン依存の設定を行っていくのがお作法感がある。
Routing
ここで、fluentdではルーティング(Routing)という概念が存在する。ネットワークのルーティングと同じ概念。fluentdでは tag
, time
, record
の3つの要素でルーティングを制御していく。これらのうち、最もよく使用する tag
のみをここで述べる。
tagは.(ドット)で区切られた文字列でFluentd内部でのルーティングに使用される。例えば myapp.access
といったようなフォーマットになる。なお、小文字の英数字とアンダースコアのみを使用することが推奨されている。 このtagに応じて、後ほどのファイル出力などを行う match
節などが実行されていく。
match
: Tell fluentd what to do
source
にて指定した方法で取得したデータをどう処理するかを tag
毎に指定していく。
この match
節でデータの出力などを行うので、このmatch
節で使用するプラグインをFluentdでは "output plugins" と呼ぶ。じゃあ、説の名前もmatchじゃなくてoutputにしろよ。
例えば、ファイルに出力したい場合には、 out_file
プラグインを使います。
https://docs.fluentd.org/v1.0/articles/output-plugin-overview
<match pattern> @type file path /var/log/fluent/myapp compress gzip <buffer> timekey 1d timekey_use_utc true timekey_wait 10m </buffer> </match>
filter
: Event processing pipline
source
と match
の間でデータ処理をしたいときは、この filter
を使う。だから、やることと節の名前が対応してないって。 フィルタは入力(source)と出力(match/output)の間にいくつでも挟むことができる。
filter
で使用できるプラグインは以下の通り。
https://docs.fluentd.org/v1.0/articles/filter-plugin-overviewdocs.fluentd.org
また、parser
にもまたプラグインがある。
例えば、 {"event": "data"}
という入力を source
で受け取り、 filter
で {"host_param" : "ホスト名"}
を追加して、match
でファイルとして出力するコンフィグは以下のようになる。(なお、fluentdはRubyで書かれているので、 Socket.gethostname
はRubyのメソッド ref: https://docs.ruby-lang.org/ja/latest/method/Socket/s/gethostname.html )
# http://this.host:9880/myapp.access?json={"event":"data"} <source> @type http port 9880 </source> <filter myapp.access> @type record_transformer <record> host_param "#{Socket.gethostname}" </record> </filter> <match myapp.access> @type file path /var/log/fluent/access </match>
label
: bring order to chaos
label節自体はなくても動作するが、tagでの制御が複雑化していってしまうのを防ぐ事ができる。
なお、"label"自体は最初から入っているプラグインのパラメーターであるので、label節を使用する際には @
が頭に必要になってくる。
例えば、source
にてtailプラグインで取得したデータを @SYSTEM
というタグ付けをしたとするとき、 @SYSTEM
というタグがつけられたデータの filter
や match
をlabel節を使ってまとめると、以下のような形になる。
<source> @type forward </source> <source> @type tail @label @SYSTEM </source> <filter access.**> @type record_transformer <record> # ... </record> </filter> <match **> @type elasticsearch # ... </match> <label @SYSTEM> <filter var.log.middleware.**> @type grep # ... </filter> <match **> @type s3 # ... </match> </label>
とりあえず試す
既に自宅のRTX1200ではsyslogサーバにログを吐き出させていたので、それを素材にとりあえず試してみる。
インストール方法はドキュメントで様々なやり方を解説しているので、好きなのを選ぶ。
自分は面倒だったので、Dockerでやることにした。
適当に以下のようなファイル構成にしたディレクトリを作成
. ├── fluentd │ └── fluent.conf └── log ├── rtx1200.log └── rtx1200.log.org 2 directories, 3 files
このディレクトリ全体を /docker
としてコンテナ内部でマウント
docker run -it --rm -v /path/to/docker:/docker fluent/fluentd "/bin/sh"
fluentの公式イメージには最小限の構成しかないので、シェルがshしかない。まぁ、ホストでコンフィグいじったりして、コンテナ内部ではfluentdを実行するだけなので大きな問題はない。(というか、インタラクティブに実行することを想定しているものではない)
fluentdのインストール自体が終わったら、「Kibana|elasticsearchでイケイケでウェイウェイしたい」という気持ちを抑えて、とりあえずは以下の方針のようにシンプルな構成で試す。
結果として、以下のようなコンフィグを fluentd/fluent.conf
に記述した。
# YAMAHA RTX <source> @type tail @id yamaha_rtx_input_tail path /docker/log/rtx1200.log <parse> @type syslog </parse> tag yamaha.test.log </source> <match yamaha.test.*> @type file path /docker/yamaha_test.json <format> @type json </format> </match>
ここでfluentでは実行前に source/path
で指定した読み込むログファイルに存在するデータは処理されないので、まずは touch
等で空のファイルを作成しておき、以下のコマンドで1回fluentを起動して、初期化処理が終わったら終了させる。
fluentd -c /docker/fluentd/fluent.conf -v
その後、実際に読み込ませたいログファイルを置き、再度起動。そうすると、以下のような元のsyslog(抜粋、一部マスク済み)
Jul 22 06:25:23 192.168.12.1 PP[01] Rejected at IN(1012) filter: TCP ***.***.***.**:***** > ***.***.**.**:**** Jul 22 06:51:52 192.168.12.1 PP[01] Rejected at IN(1030) filter: UDP ***.***.***.**:***** > ***.***.***.**:***** (DNS response) Jul 22 07:00:00 192.168.12.1 [SCHEDULE] ntpdate ntp.nict.jp syslog Jul 22 07:00:00 192.168.12.1 2018/07/22 07:00:00 +0second
がfluentdのsyslogプラグインで解析すると、以下のようなJSONになる。
{"host":"192.168.12.1","ident":"PP","pid":"01","message":"TCP ***.***.***.**:***** > ***.***.**.**:****"} {"host":"192.168.12.1","ident":"PP","pid":"01","message":"UDP ***.***.***.**:***** > ***.***.***.**:***** (DNS response)"} {"host":"192.168.12.1","ident":"","message":"[SCHEDULE] ntpdate ntp.nict.jp syslog"} {"host":"192.168.12.1","ident":"2018/07/22","message":"00:00 +0second"}
一応、読み込めてJSON化できていることがわかる。ただ、RTX向けの設定を加えていないので重要な内容(ここでいうとRejectの内容)が message
として丸められてしまっている。
このままでは困るので、filter
を追加してmessageをもう少し細分化していく。
source
やmatch
などの記法はさくらのナレッジがわかりやすく解説しているので、そちらを参照。但し、情報が少し古いのでそこは注意。新旧のdiffはFluentdの公式ドキュメントを参照してほしい(まぁ、でもQiitaやらの記事を見た感じではWARNが出るだけっぽい? ref:td-agentをv1からv2にバージョンアップした話 - Qiita)
上記を参考に、方針に沿ってやりたいことを/etc/td-agent/td-agent.conf
の末尾に書いてみる。結果は以下の感じ。
書き終わったら/etc/init.d/td-agenet configtest
で書き損じがないかチェックしてから/etc/init.d/td-agenet restart
でリスタート
正しくファイル等が配置されていれば、結果は以下のような感じになる。
fluentdでパースして吐き出せはしたが、だいぶ虚無な感じになっているのがわかる。無ですね。このままではだめそう。
Grokフィルターというものを使う例が以下のサイトにあるが、正規表現ゴリゴリ書きでやってみたいと思う。理由は様々です(主に仕事関係で慣れておきたいので)。面倒な人は素直に既にあるのを利用した方がいいかも(戒め)
正規表現をゴリゴリ書く
まず、いちいち/etc/td-agent/td-agent.conf
に書いて云々なんてやってられないので、Fluentdの正規表現エディタを使う。
Fluentular: a Fluentd regular expression editor
なお、このエディタはHerokuの無料枠でやってるらしく、稀に落ちているらしい(ref:Fluentdの正規表現を攻略する - Qiita)。Dockerイメージがあるそうなので、落ちてた場合にはそっちを使う方がいいかも(GitHub - tomohiro/fluentular: Fluentular is a Fluentd regular expression editor)。
書き方の参考には以下のサイトが非常に有用なので、困ったら見てみるべき。
また、Ruby自体の正規表現の書き方は以下の公式ドキュメントを参考。
日付を取り出す。
まずはログから日付を取り出す。ここで、RTX1200のログにおける日付のフォーマットは以下のような感じになっている。
Jul 1 00:00:00 192.168.12.1 [SCHEDULE] ntpdate ntp.nict.jp syslog
Jul 22 07:00:00 192.168.12.1 [SCHEDULE] ntpdate ntp.nict.jp syslog
まず、日付はログの行頭に現れるので、行頭にマッチする^
をつける。
次に月がJun
, Jul
のようにアルファベット3文字の省略表現となっているので、書くべき正規表現はRubyのドキュメントでいうところの単語構成文字\w
が3回連続({3}
)するものを表す \w{3}
となる。
そして日が2桁の場合は普通に22
のように表すが、1桁の場合には2桁目をスペースでパディングして1
のようにしている。そのため、書くべき正規表現はスペース(\s
)が0個、あるいは1個({0, 1}
)のあとに10進数(\d
)が1個あるいは2個({1, 2}
)現れるものを表す\s{0, 1}\d{1, 2}
となる。
最後に時間は日付のあとにスペース1個開けてから時間、分、秒ともに十進数2桁(\d{2}
)が:
で区切られて表現されているので、書くべき正規表現は\s\d{2}:\d{2}:\d{2}
となる(まぁ、\s(\d{2}:){2}\d
でもいいけど)
以上をまとめると、結果としてFluentdで書くべき正規表現は
^(?<time>\w{3}\s{1,2}\d{1,2}\s\d{2}:\d{2}:\d{2})
となる。
ここで、Fluentdでは時間time
は特別な扱いをされるので(どうされるかはドキュメント参照:https://docs.fluentd.org/v1.0/articles/parser_regexp)、上記で取り出した日付のフォーマットに合わせたRubyのTime formatをtime_format
パラメータとして記載する。実際に書くと、以下のようになるはず。
%b %e %T
実際に先程のエディタに書けると以下のような感じになる(URLパラメータにすべて持たせていてすごい)
ホスト名を取り出す
まぁ、今回はホスト名ではなくRTXの持っているIPアドレスなのだけれども。syslog的にはこれをホスト名と呼ぶらしいので、それに則ります。
これはIPv4のアドレスなので、日付に比べれば大変楽。大体いつもIPv4の正規表現で使ってる以下を使う。
(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)
(ref:IPアドレスの正規表現 [IPv4] – 黒川仁の文具堂ブログ三昧)
Fluentdに記録する際には、このRTXのIPアドレスを host
というkeyで登録したいので、結果としてFluentdで書くべき正規表現は今までのと合わせて
^(?<time>\w{3}\s{1,2}\d{1,2}\s\d{2}:\d{2}:\d{2}) (?<host>(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))
となる。
configtest
で記法エラーは出ないが[FAIL] td-agent ... failed!
だけ出てくる
ほとんどのケースで設定ファイルで指定したファイル出力先のパーミッションが不適切な場合にこうなってしまう。「(パーミッションがだめだと)そう言えや」感がすごい。
Example
/etc/td-agent/td-agent.conf
# YAMAHA RTX <source> @type tail @id yamaha_rtx_input_tail path /home/vagrant/log/rtx1200.log format syslog tag yamaha.test.log </source> <match yamaha.test.*> @type file path /home/vagrant/fluentd_test/yamaha_test.json <format> @type json </format> </match>
このとき、<match>
で/home/vagrant/fluentd_test/
を指定しているので、このディレクトリのパーミッションが不適切だったりすると[FAIL] td-agent ... failed!
だけ出てくる。いい感じに設定してあげよう。
whywaita Advent Calendar 2021 17日目:人はなぜ飛行機に乗るのか
皆が目指し始める沖縄には一体何があるのか?
その謎を解明するため、我々調査隊はプレミアムポイント/FLY ONポイントシミュレーターへ向かったーー。
この記事はwhywaita Advent Calendar 2021 - Adventarの17日目の記事です。
16日目は id:tochikuji さんでした。Tweetに重みがあってエモいですね...
自分はゲーミングチェアを使っているのですが、正直ゲームをあまりやらないので、次はプロの店員さんにおまかせして見繕ってみたいですね。(アーロンチェア、コンテッサ程度しか知らなかったので、椅子の世界も奥深くて驚きです。)
さて、去年は沖縄那覇の話をしましたが、今年は沖縄つながりで飛行機の話です。
whywaitaと那覇へ異常行動をしに行きたい2020冬 - Coyote vs Loadbalancer https://t.co/nHyVwqkV2g whywaita Advent Calendar 4日目!何が一体彼をここまで掻きたてるのか、沖縄の魅力とは、それはそれとして無限に沖縄行ってるのヤバいですね!!
— why/橘和板 (@whywaita) December 4, 2020
皆さん、飛行機に乗っていますか?
基本的に皆さん、飛行機には月1回以上乗ると思うのですが、今年自分は41回飛行機に乗っていたようです。 特に沖縄には14回も行ったようですね。
Date | Departure | Destination | Fare type | ||
---|---|---|---|---|---|
2021/02/06 | HND | 14:30 | OKA | 17:25 | SUPER VALUE 21 |
2021/02/06 | OKA | 20:50 | HND | 23:00 | SUPER VALUE 21 |
2021/02/20 | HND | 14:30 | CTS | 17:25 | SUPER VALUE 55 |
2021/02/22 | CTS | 20:50 | HND | 23:00 | SUPER VALUE 55(アップグレード) |
2021/03/27 | HND | 7:25 | OKA | 10:10 | SUPER VALUE 28 |
2021/03/27 | OKA | 12:15 | HND | 14:35 | SUPER VALUE 28 |
2021/03/27 | HND | 15:30 | OKA | 18:15 | SUPER VALUE 28 |
2021/03/27 | OKA | 19:10 | HND | 21:30 | SUPER VALUE 28 |
2021/04/03 | HND | 8:30 | OKA | 11:25 | SUPER VALUE 28 |
2021/04/03 | OKA | 15:45 | HND | 18:15 | SUPER VALUE 28 |
2021/04/10 | HND | 15:40 | OKA | 18:25 | SUPER VALUE 28 |
2021/04/10 | OKA | 20:40 | HND | 23:00 | SUPER VALUE 28 |
2021/04/17 | HND | 7:25 | OKA | 10:15 | SUPER VALUE 28 |
2021/04/17 | OKA | 11:05 | HND | 13:25 | SUPER VALUE 28 |
2021/04/17 | HND | 15:40 | OKA | 18:25 | SUPER VALUE 28 |
2021/04/17 | OKA | 19:20 | HND | 21:40 | SUPER VALUE 28 |
2021/05/22 | HND | 8:30 | OKA | 11:20 | SUPER VALUE 45 |
2021/05/22 | OKA | 18:10 | HND | 20:35 | SUPER VALUE 45 |
2021/05/23 | HND | 8:30 | OKA | 11:20 | SUPER VALUE 45 |
2021/05/23 | OKA | 14:30 | HND | 17:00 | SUPER VALUE 45 |
2021/05/29 | HND | 8:30 | OKA | 11:20 | SUPER VALUE 55 |
2021/05/29 | OKA | 20:10 | HND | 22:30 | SUPER VALUE 55 |
2021/06/05 | HND | 8:30 | OKA | 11:20 | SUPER VALUE 75 |
2021/06/05 | OKA | 15:40 | HND | 18:15 | SUPER VALUE 75 |
2021/07/25 | HND | 8:00 | CTS | 9:30 | 特典航空券 |
2021/07/25 | CTS | 17:00 | HND | 18:40 | 特典航空券 |
2021/09/18 | HND | 9:30 | CTS | 11:05 | SUPER VALUE SALE |
2021/09/18 | CTS | 12:50 | RIS | 13:40 | 株主優待 |
2021/09/19 | RIS | 14:15 | CTS | 15:10 | 株主優待 |
2021/09/19 | CTS | 18:30 | HND | 20:05 | SUPER VALUE SALE |
2021/09/21 | HND | 8:00 | ITM | 9:05 | 特典航空券 |
2021/09/21 | ITM | 19:00 | HND | 20:15 | 特典航空券 |
2021/10/09 | HND | 14:30 | OKA | 17:15 | SUPER VALUE 28 |
2021/10/09 | OKA | 20:10 | HND | 22:30 | SUPER VALUE 28 |
2021/11/13 | HND | 13:10 | OKA | 16:00 | SUPER VALUE SALE |
2021/11/13 | OKA | 20:00 | HND | 22:20 | SUPER VALUE 45 |
2021/11/22 | HND | 8:00 | CTS | 9:30 | 特典航空券 |
2021/11/22 | CTS | 19:30 | HND | 21:10 | 特典航空券 |
2021/12/11 | HND | 7:35 | OKA | 10:35 | 特典航空券 |
2021/12/11 | OKA | 20:05 | HND | 22:20 | 特典航空券 |
沖縄に至っては日帰りで行くのになれすぎて、今年は一泊もしていないようです。
なぜ飛行機に乗るのか?
自分の身の回りにも飛行機にいっぱい乗っている人が多くいて、先日も都内の大学時代の先輩と、ゆいレール 小禄駅の改札でばったりお会いするという経験もしました。
そんなところから、なぜ人は飛行機に乗るのか?というところを自分なりに深堀りしてみました。
1. 非日常が味わえる
年間40回以上も飛行機に乗っていても、飛行機に乗るたびに非日常感が味わえます。これが一番の醍醐味でしょう。
飛行機に乗れば空高くから都心を眺めたり、富士山を見ることができます。数時間乗るだけで沖縄や北海道など、はるか遠くの土地まで行くことができます。飛行機に乗ったおかげで味わえる非日常感ですね。
2. 行った先でうまいものが食える
都心でもたいていなんでも食えますが、やはり行った先でその土地のものを食べると美味しいです。利尻で雲丹を食べたら、今まで食べていた雲丹はなんだったんだ・・・と思うくらい美味しかったです。沖縄では、裏路地のお店で在日米軍のお兄さんたちにまぎれてタコスを食べましたが、これも驚くほど美味しくて、気がついたら消えているレベルでした。これも飛行機に乗ったおかげです。
3. いい風景が見れる
行き先次第ですが、離島などはすごくいい景色が見れます。平日にディスプレイを眺めて過ごしているのに反して、海や空、山などを眺めることができて、とても心が洗われますね。これも飛行機に乗ったおかげです。
4. 新たな出会いがある
コロナ禍でなかなか現地の人と仲良くなることが今は難しいですが、現地の居酒屋でおじさんと意気投合して「時価」がある日本料理をおごってもらったり、離島をロードバイクで走ってたら現地のおばちゃんとなぜか一緒に観光をしたりと、新たな出会いが旅先でもあるのも旅行の醍醐味です(すべて実話)。これも飛行機に乗ったおかげです。
5. プレミアムポイント/FLY ONポイントがたまる
飛行機に乗ると各航空会社のステータス取得に必要なポイントを貯めることができます。1つ1つ積み重ねて目標に向かって進んでいる感が味わえます。これも飛行機に乗ったおかげです。(海外へ行ったこともないのに、地球3周分くらい飛行機に乗ってますね)
6. 1日に那覇羽田2往復すると虚無感が味わえて気持ちがいい
ステータス獲得のために、1日に那覇羽田2往復をして家についたとき「6000kmも1日で移動したのか〜と、でも今は振り出し・・・」と虚無を感じるとき、とても気持ちが良いですね。これも飛行機に乗ったおかげです。
結論
最後あたりが怪しくなりましたが、やはり非日常感を味わえる、旅行先で楽しむ、初めての人/会いたかった人に会えるというところが、やはり人が飛行機に乗って飛んでしまう所以なのでしょうね。特に最後の虚無感に気持ちよさを感じるのはやばいと思うので、ほどよく飛行機に乗るのがいいと思います。
コロナ禍でなかなか旅行に行くこともままならない世の中ですが、近いうちにまたwhywaitaとともにどこかに旅行に行きたいですね。身の回りがJAL派ばかりで、知り合いにスイートラウンジでイキれないのが無念なので、今度ANAに乗っていきましょう。
ちなみに、来年もすでにいっぱい飛行機に乗ることになっていますが、来年もこのAdvent Calendarがあったときには違うネタが用意できるようにしたいなぁと思います。
明日は kyontan です。まだ彼のマイカーに乗ったことがないのですが、修理を繰り返すあまり、テセウスの船みたいになっているので、新車になった頃に乗りたいですね。
蛇足
どうでも良いのですが、先日、社で同期の女性の方と研修でご一緒することがあり、アイスブレイクとしての自己紹介タイムで「飛行機によく乗ってて、この間も1日に那覇羽田2往復したんですよ〜」と言ったところ、ドン引きされました。
M1 MacでTensorflowを使う
院生時代に使ったっきりのTensorflowがM1に対応したのを今更見つけて、久しぶりに触ろうと思ったらちょっとハマったので備忘録的に書く。
Python環境構築(雑メモ)
当初はPyenvでAnaconda or minicondaを入れればよいかと思ったが、pyenvではApple Silicon版のAnacondaは未対応なためインストールできず。今のナウいARMに生きている若者の間ではMiniforge(Mambaforge)が使われているとのことで、そちらを利用することにした。
今回はpyenvでmambaforgeをインストールし、globalにmambaforgeを設定した。別にpyenvを入れずに、ダイレクトにMiniforgeのリポジトリにあるインストーラーでインストールしても良かった気はする。
pyenv install mambaforge pyenv global mambaforge
pyenv versions system 3.9.1 * mambaforge (set by /Users/user/.pyenv/version)
これはいらないかもしれないが、インストール時に.zshrcの掃除もしていたので、Miniforgeでcondaコマンドを使うには(というよりも、普通にcondaを使うには)以下も追加する必要があった。 conda init
でいい感じに挿入されるのだが、condaのバイナリのパスなどがベタ書きされており、ちょっと気持ち悪かったので環境変数に押し出した。
export PYENV_ROOT="$HOME/.pyenv" export MAMBA_HOME="$PYENV_ROOT/versions/mambaforge" # conda(mamba/miniforge) __conda_setup="$("$MAMBA_HOME/bin/conda" 'shell.zsh' 'hook' 2> /dev/null)" if [ $? -eq 0 ]; then eval "$__conda_setup" else if [ -f "$MAMBA_HOME/etc/profile.d/conda.sh" ]; then . "$MAMBA_HOME/etc/profile.d/conda.sh" else export PATH="$MAMBA_HOME/bin:$PATH" fi fi unset __conda_setup
とりあえずこの辺で普通にPythonが使えるようになるはず。
Tensorflowのインストール
基本的にはApple公式のARM64版手順のうち、Miniforgeをインストールし終えたあとからに従えばOK。
おもむろに仮想環境を作成
mamba create -n tensorflow_m1 python=3.9 conda activate tensorflow_m1
依存関係のインストール。
conda install -c apple tensorflow-deps python -m pip install tensorflow-macos python -m pip install tensorflow-metal
おわり。
試す
学部4年で研究室配属されたときに指導教官の顔よりも見たMNISTでサクッと試す。
感触として、結構早い気がする。あと学習中もMac miniの発熱も少なく、ファンの音も変わらず、なかなか。
もっと難しいモデルを食わせたときにどうなるかは今後試したい。
M1 MacでTensorflowが動いて満足している pic.twitter.com/JJkg45Hbxc
— 結納エンジニア (@twismiko) December 4, 2021
トラブルシュート:h5py
python -m pip install tensorflow-macos
時に依存関係でインストールされる h5py
が、brew install hdf5でインストールしていても hdf5のライブラリが見つからずにこけてしまう。
error: Unable to load dependency HDF5, make sure HDF5 is installed properly error: dlopen(libhdf5.dylib, 0x0006): tried: '/Users/user/.pyenv/versions/mambaforge/lib/libhdf5.dylib' (no such file), '/Users/user/.pyenv/versions/mambaforge/lib/libhdf5.dylib' (no such file), '/Users/user/.pyenv/versions/mambaforge/lib/python3.9/li b-dynload/../../libhdf5.dylib' (no such file), '/Users/user/.pyenv/versions/mambaforge/lib/libhdf5.dylib' (no such file), '/Users/user/.pyenv/versions/mambaforge/bin/../lib/libhdf5.dylib' (no such file), 'libhdf5.dylib' (no such file), '/usr/local/lib/libhdf5.dyli b' (no such file), '/usr/lib/libhdf5.dylib' (no such file), '/private/var/folders/1t/8rwk7l5x4ssf753522k2d5v40000gn/T/pip-install-jq0sx82l/h5py _d3e3046cd7134f25a2ade50e9f4a162e/libhdf5.dylib' (no such file), '/usr/local/lib/libhdf5.dylib' (no such file), '/usr/lib/libhdf5.dylib' (no su ch file) ---------------------------------------- ERROR: Failed building wheel for h5py Failed to build h5py ERROR: Could not build wheels for h5py, which is required to install pyproject.toml-based projects
理由は、ARM64版とx86/64版ではbrewでインストールした際のインストール先ディレクトリが違うらしく、h5pyがそれを終えていない模様。
ワークアラウンドとして、x86/64でbrewをインストールしてHDF5をインストールする方法があるらしいが、あまりバイナリを混在させたくなかったので、h5pyインストール時にarm64のbrewでインストールしたHDF5のディレクトリを環境変数(HDF5_DIR
)で指定の上、pipでバイナリパッケージを使用しないことを明示(--no-binary=h5py
)してインストールして対応した。
export HDF5_DIR=/opt/homebrew/Cellar/hdf5/1.12.1/ pip install --no-binary=h5py h5py
参考:
- python - How to install h5py (needed for Keras) on MacOS with M1? - Stack Overflow
- M1 Macでのlibtorch、HDF5、Boostその他のintel版をインストール - Qiita
Juniper Telemetry Interfaceをfluentdで受ける
作業メモ
環境
- Juniper vMX on AWS EC2(BYOL/Trial)
- JUNOS 19.4R1.9
- fluentd
したいこと
Junosから送られてくるJuniper Telemetry Interface(over UDP)をfluentdで受けたい。とりあえずはテキストでローカルに吐いてくれれば良い
作業
前提条件
- fluentdはパッケージでインストール済み
- Installation: Install by RPM Package (Red Hat Linux) - Fluentd
- EC2でAMIにてインスタンスを立てていたのでので、AMIのセクションの記載でインストール(といってもcurlでshellとってきてパイプでsh叩いてるだけなので、何もすることはないが)
Junosの設定
AWS Marketplaceで取得したJunos vMXにはrootパスワードが設定されておらず、commitが出来ないのでよしなに設定
普段、Junosを触らないが、ドキュメント通りに設定すれば出来た
- Configuring a Junos Telemetry Interface Sensor (CLI Procedure) | Junos OS | Juniper Networks
- Export Profile, Streaming Server Profile, Sensor Profileの設定が必要
- Export Profile
- Junos自身がどういうIP/ポート...でテレメトリを出すか?を指定
set local-address
にはJunosのマネジメントIPを指定したset local-port
は適当に12345
set transport
は今回、UDPにした- DSCP, forwarding class, packet loss priorityはoptionalで今回は作り込む気はないので、スキップ
- Streaming Server Profile
- Sensor Profile
- どういう情報を持つテレメトリを出すかの設定
resource
には/junos/system/linecard/cpu/memory/
をとりあえず指定- その他のものの詳細はこのへん(Understanding OpenConfig and gRPC on Junos Telemetry Interface | Junos OS | Juniper Networks)を見れば良さそう
- Configuring a Junos Telemetry Interface Sensor (CLI Procedure) | Junos OS | Juniper Networks
最終的には以下の感じのconfigになった
services { analytics { streaming-server ec2 { remote-address 10.0.1.63; remote-port 22000; } export-profile fluentd { local-address 10.0.1.164; local-port 12345; reporting-rate 5; format gpb; transport udp; } sensor interface-1 { server-name ec2; export-name fluentd; resource /junos/system/linecard/cpu/memory/; } } }
Pluginのインストール
- fluent-plugin-udp-native-sensorsを使う
- JTI Plug-ins for Open Source Data Collectors | Junos OS | Juniper Networksでリストアップされているが、UDP/gRPC版も2021/5現在ほぼ更新がないどっこいどっこいの状態。UDP版はPull Requestで最新版のfluentdに対応するようなものが他の人から出ているので、それを使う
git clone https://github.com/Juniper/fluent-plugin-udp-native-sensors # 普通にclone git fetch origin pull/3/head:with_keys_1.0 # fluentd最新版に対応したPRを取得 git checkout with_keys_1.0 sudo td-agent-gem build fluent-plugin-udp-native-sensors.gemspec # fluentd内蔵のgemでビルド sudo td-agent-gem install fluent-plugin-udp-native-sensors-0.0.1.gem # fluentd内蔵のgemでインストール
Pluginの設定
- GithubのREADME通りだが、
/etc/td-agent/td-agent.conf
に以下を追記- もしJunosの設定でStreaming Server Profileにあるremote-portを22000以外にしていたら、その変更したポートを指定する
<source> @type udp tag juniperNetworks format juniper_udp_native port 22000 bind 0.0.0.0 </source> <match juniperNetworks> @type file path /home/ec2-user/junos/ </match>
- td-agentを再起動
参考文献
- パッケージでインストールしたfluentdで自前ビルドしたpluginをインストールしたい
- td-agentとrbenv/gemでインストールしたfluentdのディレクトリ構成の比較 - suzuki-navi’s blog
whywaitaと那覇へ異常行動をしに行きたい2020冬
これはwhywaitaの人徳ゆえになんだかんだで埋まる、不思議なwhywaita Advent Calendarの2020年版、4日目の記事です。
昨日はkyontanでした。本記事は平日に時間がないと思い先週の土曜日に書いたのですが、まさかの以心伝心で今日は那覇とANAダイヤモンドメンバーの話になります。
一日に羽田-沖縄を2往復して何が楽しいんでしょうか?
那覇と羽田を1日2往復すると、1日の半分以上を空にいられるので事実上のあおかなというわけです。ましろちゃんとこの辛く厳しい現世でも会いたいと思い、空を飛んでいるのかもしれませんね。人は古来より、空を飛んでみたいと思い生きているのです。
from: https://www.ana.co.jp/ja/jp/amc/reference/premium/
今年、ダイヤモンドになるために行った行程をご紹介しましょう。
Date | Departure | Destination | Fare type | ||
---|---|---|---|---|---|
- | - | - | - | ||
2020/05/16 | HND | 7:30 | OKA | 10:10 | 株主優待 |
2020/05/16 | OKA | 11:00 | HND | 13:25 | VALUE 3 |
2020/05/16 | HND | 15:40 | OKA | 18:15 | VALUE 3 |
2020/05/17 | OKA | 11:00 | HND | 13:25 | VALUE 3 |
2020/05/22 | HND | 7:30 | OKA | 10:10 | VALUE 3 |
2020/05/22 | OKA | 11:00 | HND | 13:25 | VALUE 3 |
2020/05/22 | HND | 15:40 | OKA | 18:15 | SUPER VALUE 55L |
2020/05/23 | OKA | 11:00 | HND | 13:25 | SUPER VALUE PREMIUM 28 |
2020/05/24 | HND | 10:45 | OKA | 13:30 | SUPER VALUE 55M |
2020/05/24 | OKA | 14:30 | HND | 17:00 | SUPER VALUE 55M |
2020/05/30 | HND | 7:30 | OKA | 10:10 | VALUE 3 |
2020/05/30 | OKA | 11:00 | HND | 13:25 | VALUE 3 |
2020/05/30 | HND | 15:40 | OKA | 18:15 | VALUE 3 |
2020/05/30 | OKA | 19:05 | HND | 21:30 | SUPER VALUE 45M |
2020/06/27 | HND | 7:30 | OKA | 10:10 | 国際線乗り継ぎ(SYSERROR) |
2020/06/28 | OKA | 14:25 | HND | 17:00 | SUPER VALUE 75M |
2020/07/03 | HND | 15:40 | OKA | 18:10 | SUPER VALUE 75M |
2020/07/05 | OKA | 14:25 | HND | 17:00 | SUPER VALUE 75L |
2020/08/01 | HND | 7:30 | OKA | 10:10 | VALUE 1 |
2020/08/01 | OKA | 20:35 | HND | 23:00 | VALUE 1 |
2020/08/22 | HND | 7:30 | OKA | 10:05 | VALUE 3 |
2020/08/22 | OKA | 10:55 | HND | 13:25 | VALUE 3 |
2020/08/22 | HND | 14:30 | OKA | 17:05 | VALUE 3 |
2020/08/22 | OKA | 19:00 | HND | 21:30 | VALUE 3 |
2020/08/28 | HND | 20:00 | OKA | 22:30 | VALUE 3 |
2020/08/30 | OKA | 8:00 | HND | 10:20 | プレミアム株主優待 |
2020/08/30 | HND | 12:55 | OKA | 15:30 | VALUE 3 |
2020/08/30 | OKA | 16:25 | HND | 19:00 | VALUE 3 |
2020/09/04 | HND | 7:30 | OKA | 10:10 | VALUE 3 |
2020/09/04 | OKA | 11:00 | HND | 13:25 | VALUE 3 |
2020/09/04 | HND | 15:40 | OKA | 18:10 | VALUE 3 |
2020/09/04 | OKA | 19:05 | HND | 21:30 | VALUE 3 |
2020/09/05 | CTS | 12:35 | RIS | 13:25 | SUPER VALUE 45L |
2020/09/06 | RIS | 14:05 | CTS | 15:00 | SUPER VALUE 45L |
2020/09/12 | HND | 7:30 | OKA | 10:10 | VALUE 3 |
2020/09/12 | OKA | 11:00 | HND | 13:25 | VALUE 3 |
2020/09/12 | HND | 15:40 | OKA | 18:10 | VALUE 3 |
2020/09/12 | OKA | 19:05 | HND | 21:30 | VALUE 3 |
2020/09/13 | HND | 7:30 | OKA | 10:10 | VALUE 3 |
2020/09/13 | OKA | 11:00 | HND | 13:25 | VALUE 3 |
この修業ですっかり沖縄が好きになってしまいました。なので、ぜひ仲良しのwhywaitaと一緒に沖縄に行きたいと最近思っています。しかし、お互いに社会人で仕事もあり、時間がなかったりするのも事実。そこで、自分がこの修業で編み出した超短時間・爆速・満足度の高い(当社比)、那覇観光について記事を書きたいと思います。
本記事を参考に沖縄に行かれる方は、GOTOトラベル事務局作成の「新しい旅のエチケット」等をご覧になり、十分に対策をしてください!
続きを読むYAMAHA RTX1200のログをElasticsearch+logstash(+Grok)+Kibanaで可視化する話 on Docker
9割ポエムなサイトに唐突に現れる技術記事です。
完成図
とりあえず最終的に得たいもののイメージ。IPフィルターで破棄した通信の送信元国と回数、ポート番号をDashboardで表示しています。
(詳しく見るとChinaにTaiwanが含まれててアツいですね)
前提条件
以下の行程が終了していることを前提とします。適当にググるとやり方が載っているので、いい感じにしてください。
. ├── docker-compose.yaml ├── elasticsearch_data └── pipeline └── pipeline.conf
docker-compose.yamlの準備
なにかいろいろなサイトを参考にして作ったdocker-compse.yamlは以下のような感じ。とりあえずで volumes
が相対パスになっているので、変えたい人はよしなに。 また、logstash
のvolumes
でマウントしている /var/log
は、自分のRTXのログが /var/log/rtx1200.log
という名前で出力されるようにしているからなので、もし違う人はそこも合わせてあげてください。
version: "3" services: elasticsearch: image: elasticsearch:7.2.0 container_name: elasticsearch environment: discovery.type: single-node ports: - "9200:9200" - "9300:9300" volumes: - ./elasticsearch_data:/usr/share/elasticsearch/data logstash: image: docker.elastic.co/logstash/logstash:7.0.1 container_name: logstash volumes: - ./pipeline:/usr/share/logstash/pipeline - /var/log:/var/log depends_on: - elasticsearch kibana: image: kibana:7.2.0 container_name: kibana environment: ELASTICSEARCH_URL: http://elasticsearch:9200 ports: - "5601:5601" depends_on: - elasticsearch
(どうでもいいですが、KubernetesでYAMLが推奨されている理由が「Write your configuration files using YAML rather than JSON. Though these formats can be used interchangeably in almost all scenarios, YAML tends to be more user-friendly. 」ですが、この滅茶苦茶読みにくい、ゴミみたいな形式がJSONよりユーザーフレンドリーとは思わないんですけどね・・・。)
logstashのpipeline.conf作成
Pipelineの流れはElastic社の概念図がわかりやすいです。
つまり、雑多なData Sourceからログを取得するために適切な方法をInput pluginで指定して、Filter pluginで整形、そのあとにOutput pluginでログを保存したいところに応じた保存方法を指定してあげるという流れ。その処理で適切なプラグインを指定して、プラグイン毎の設定をしてい\けばパイプラインの出来上がりというわけ。
今回の場合はsyslogでファイルとして取得できているRTX1200のログを読み込みたいので、Input pluginにfileプラグインを用います。細かい設定は公式ドキュメントに詳細が載っているので、そちらを参照。
今回はとりあえずという形なので、ファイルパス path
と start_position
のみを指定します。
path
は普通にsyslogが吐かれるファイルパスを指定すればOK。 start_position
はlogstashがファイルのどこから読み込むかという設定になります。実運用時には前回取得時からの差分だけ、つまりファイル末尾だけを見たいので end
を指定しますが、今回は古いデータをまとめて取得したいので beginning
を指定します。
そんな流れでpipelineを書くと以下のような感じになります。
input { file { path => "/var/log/rtx1200.log" start_position => "beginning" } }
これでRTX1200のログがlogstashのpiplineに乗るので、次は内容をどう整形するかを filer
で指定します。今回は充実した正規表現リストが予め組み込まれている、お手軽プラグインのgrokを使って整形していきます。
grokプラグインで使用できる正規表現リストは以下を参照。ほとんどこれで良いんじゃないか?というレベル。
https://github.com/logstash-plugins/logstash-patterns-core/blob/master/patterns/grok-patternsgithub.com
まず、syslogのヘッダー部を取り出します。つまりは、以下のようなsyslogの出力で言うところの日付とsyslogを発したホストIP、ログ内容のうち日付とホストのIPアドレスを抜き出す。
Aug 11 03:09:46 192.168.**.** [DHCPD] LAN1(port1) Allocates 192.168.**.**: **:**:**:**:**:** Aug 11 03:54:50 192.168.**.** PP[01] Rejected at IN(1012) filter: TCP **.**.**.**:**** > ***.***.***.***:*** Aug 11 03:54:51 192.168.12.1 PP[01] Rejected at IN(1012) filter: TCP **.**.**.**:**** > ***.***.***.***:***
grokを使って日付を time
、ホストIPアドレスを hostname
、ログ内容を message
というラベルをつけて抜き出すと以下のような感じになります。
grok { match => { "message" => "%{SYSLOGTIMESTAMP:time} %{IPV4:hostname} %{GREEDYDATA:message}" } overwrite => [ "message" ] }
ここでoverwrite
を使って日付とホストIPを除いた、ログ本文をmessage
ラベルとして上書きしています。こうすることで、未処理のログ範囲を狭めていっています。
で、ここで細かくやっていくべきなのですが、いきなりドカンと一気に内容をパースしていきます。
- 定期実行処理のログ
- cronで定期実行されるログを取り出す。自分の場合はNTP同期のログ程度しか出力されないので、定期実行された内容程度を取り出すだけにしている。
- Inに対するIPフィルターで破棄された通信ログ
- Outに対するIPフィルターで破棄された通信ログ
- DHCP割当ログ
- ログイン履歴
- 残り
- 上記フィルターで該当したなかった雑多なログ
以上の項目をフィルターに設定すると、以下のような感じになります。
grok { match => { "message" => [ "\[SCHEDULE\] %{GREEDYDATA:schedule_what}", "%{GREEDYDATA:in_rejected_interface} Rejected at IN\(%{NUMBER:in_rejected_filter_num:int}\) filter: %{WORD:in_rejected_protocol} %{IPV4:in_rejected_src_address}\:%{NUMBER:in_rejected_src_port:int} > %{IPV4:in_rejected_dst_address}\:%{NUMBER:in_rejected_dst_port:int}", "%{GREEDYDATA:out_rejected_interface} Rejected at OUT\(%{NUMBER:out_filter_num:int}\) filter: %{WORD:out_rejected_protocol} %{IPV4:out_rejected_src_address}\:%{NUMBER:out_rejected_src_port:int} > %{IPV4:out_rejected_dst_address}\:%{NUMBER:out_rejected_dst_port:int}", "\[DHCPD\] %{GREEDYDATA:dhcp_allocate_interface} Allocates %{IPV4:dhcp_allocate_address}: %{MAC:dhcp_allocate_mac_address}", "%{GREEDYDATA:interface}: %{GREEDYDATA:interface_what} ", "\'%{WORD:login_succeeded_user}\' succeeded for %{WORD:login_succeeded_protocol}: %{IPV4:login_succeeded_src_address}", "%{GREEDYDATA:other_logs}" ] } }
ごちゃごちゃと書かれているけれども、基本的にはログ文中の取り出したい文字列部分を %{}
で括り、中に該当する正規表現リストの名前とラベルを記載しているだけ。多少クセはあるが、ちょっとずつ書いていくとなんとなく慣れます。
なお、自分がハマったポイントだけ解説しておきます。ポート番号やIPフィルターの番号など、Int型が来るものに対して上記では %{NUMBER:hogehoge:int}
としています。このようにしないと、Int型が文字列として扱われてしまい、Elasticsearch側で文字列として扱われて数値統計などができなくなってしまいます。
そして、今回の主目的である「フィルターに該当した通信の発信/送信元を地図にマッピングしたい」を実現するため、 geoip
プラグインを用いてIPアドレスを地理情報に変換します。ここで、if
でIPフィルターに該当して破棄された通信のIPアドレスがある場合のみにgeoipプラグインで地理情報に変換するようにしています。こうしないと、エラーが出力されてしまいます。
if [in_rejected_src_address]{ geoip { source => "in_rejected_src_address" target => "in_rejected_src_geo" } } if [out_rejected_dst_address]{ geoip { source => "out_rejected_dst_address" target => "out_rejected_dst_geo" } }
そして最後にelasticsearchに記録するためoutputを指定します。今回はdocker-composeでelasticsearchを立ててよしなにするにで、以下のような非常にかんたんな記述になります。
output { elasticsearch { hosts => [ "http://elasticsearch:9200" ] }
なお、Elasticsearchに直接突っ込まずにデバッグのために一旦ファイル出力したいなどの場合であれば以下のようにすればファイルに出力されます。
output { file { path => "/foo/bar/hogehoge.json" } }
以上をすべて繋げると、YAMAHA RTX1200のログをElasticsearchに突っ込むpipelineは以下のような感じになります。
input { file { path => "/var/log/rtx1200.log" start_position => "beginning" } } filter { grok { match => { "message" => "%{SYSLOGTIMESTAMP:time} %{IPV4:hostname} %{GREEDYDATA:message}" } overwrite => [ "message" ] } grok { match => { "message" => [ "\[SCHEDULE\] %{GREEDYDATA:schedule_what}", "%{GREEDYDATA:in_rejected_interface} Rejected at IN\(%{NUMBER:in_rejected_filter_num:int}\) filter: %{WORD:in_rejected_protocol} %{IPV4:in_rejected_src_address}\:%{NUMBER:in_rejected_src_port:int} > %{IPV4:in_rejected_dst_address}\:%{NUMBER:in_rejected_dst_port:int}", "%{GREEDYDATA:out_rejected_interface} Rejected at OUT\(%{NUMBER:out_filter_num:int}\) filter: %{WORD:out_rejected_protocol} %{IPV4:out_rejected_src_address}\:%{NUMBER:out_rejected_src_port:int} > %{IPV4:out_rejected_dst_address}\:%{NUMBER:out_rejected_dst_port:int}", "\[DHCPD\] %{GREEDYDATA:dhcp_allocate_interface} Allocates %{IPV4:dhcp_allocate_address}: %{MAC:dhcp_allocate_mac_address}", "%{GREEDYDATA:interface}: %{GREEDYDATA:interface_what} ", "\'%{WORD:login_succeeded_user}\' succeeded for %{WORD:login_succeeded_protocol}: %{IPV4:login_succeeded_src_address}", "%{GREEDYDATA:other_logs}" ] } } if [in_rejected_src_address]{ geoip { source => "in_rejected_src_address" target => "in_rejected_src_geo" } } if [out_rejected_dst_address]{ geoip { source => "out_rejected_dst_address" target => "out_rejected_dst_geo" } } } output { elasticsearch { hosts => [ "http://elasticsearch:9200" ] } }
docker-compose up
以上で概ねの設定は終わったので、docker-compose.yamlがあるディレクトリで docker-compose up
してElasticsearchその他を立ち上げましょう。
無事に立ち上がればdockerを動かしているマシンのIPアドレスの5601番でKibanaが立ち上がるはずです。結構、立ち上げに時間がかかります。
まだKibana側でElasticsearchのログを紐付けていないので、適当にサイドバーのDiscoverをクリックしてウィザードを立ち上げます。
適当にinedx patternにlogstashと打って、logstashで整形したログを登録します。
タイムスタンプを指定
登録終わり
実際にIPフィルターで破棄した通信を地図上にマッピングしていきます。Visualize→Create new visualizationでダイアログから Region Mapを選択、先程登録したlogstashのログを指定
遷移後、 サイドで Meric
の Value
で Count
を選択。その後、国毎に検出数をまとめたいので Buckets
で Aggregation
から Terms
を選択し、 Filed
からin_rejected_src_geo.continent_code.keyword
を選択。
ここでデフォルト設定では直近15分のログからしか可視化をしないので、適当に上部からhoursではなくdaysに変更、UPDATE
そうすると、欲しかった地図マッピングが完成。
wrapup
最後あたり、凄まじく雑になりましたね。息切れです。そのうち、もうちょっとちゃんと書こう・・・。
Macintosh HDのイメージをディスクユーティリティで作成できない件
自分の備忘録用。
Genius BarにMacBook Proを持っていきたくて、その前にバックアップのためにmacOSの入っているMacintosh HD自体のイメージを作成しようとしたところ、 ファイル
-> 新規イメージ
-> "Macintosh HD" からイメージ作成
がグレーアウトしていてクリックできなかった。
FileVaultを有効にしているせいなのかなんなのかよくわからないが、対処法は以下の通り。
(いらないかも)Command + Rを押しながら再起動して、リカバリーモードで起動。その後、ディスクユーティリティを起動する。
表示
->すべてのデバイスを表示
(あるいはCommand + 2)を押して、ボリューム表示のみではなくすべてを表示させる。
MacBook Proの場合、
コンテナdisk1
がサイドバーに登場するので、それをクリックその後、
ファイル
->新規イメージ
->"コンテナdisk1" からイメージ作成
でイメージを作成する
macOSはわけのわからないところですごい不親切なので、謎。