tech.guitarrapc.cóm

Technical updates

ロジクールMX Anywhere3 に変えた

普段からどうしてもほしいものはない、のですがマウスだけはずっと満足いかずたびたび探しています。

ずっと使っているのが、ロジクールMX Master / MX Anywhere シリーズで、職場と自宅などでシリーズ初めから使っています。 MX Master は大きいので、MX Anywhere が好みでここ数年は常に MX Anywhere 2を使ってました。

ふと、マウスに不満を覚えて探して比較するものの、結局 MX Anywhere に戻ってきてしまう。 それは今回もそうなのでした。

MX Anywhere 3

MX シリーズは、大きめサイズでハイエンドな性能詰め込みました的な MX Master と 小さめサイズでなんでもできるけど人間工学的なデザインがない MX Anywhere があります。

https://www.logicool.co.jp/ja-jp/products/mice/mx-anywhere-3.910-006005.html より

youtu.be

youtu.be

私が愛用しているのは MX Anywhere です。

www.logicool.co.jp

以前はUnity 使うときは MX Master で、それ以外は MX Anywhere だったのですが、MX Anywhere を布教しまくってどこでも使ってたら慣れてしまいました。

MX Anywhere 3 は、MX Anywhere の最新版です。 for Mac もあって、こっちは Unifying レシーバーがなく Bluetooth接続対応のみになります。Mac / Windows 両方使うのですが、Macは専用でなくても十分安定しているので通常のを選びました。

Bluetooth 接続は、Windows/macOS のいずれにおいても負荷が極めて高い時に安定性に欠ける一方で、Unifying は安定しており UEFI でも問題ない& USB切り替えで複数接続が気にならないというのがポイントです。(使い込むほどUnifying 一択)

MX Anywhere 2 からの変更点

MX Anywhere 3 にしたのは、MX Anywhere 2 の不満が解消されていたからです。 MX Anywhere 2 には次の不満がありました。

  • ミドルクリックがマウスホイールクリックではなく、ホイール下の小さなボタン
  • 横スクロールのホイール横倒しがしんどい
  • 充電ケーブルが micro-USB
  • 充電しても電池切れ期間が短くなってきた
  • ラバーからシリコーングリップへの変更 (2022/2/13追記)

もっと詳しいMX Anywhere 2 との変更点は書いてる人はたくさん書いてるのでそれを見てください。

news.mynavi.jp

k-tai.watch.impress.co.jp

kakakumag.com

改善点1. ミドルクリック

一番厄介で、慣れてしまうまで MX Master にしていた最大の理由が、「ミドルクリックがマウスホイールクリックではない」ということです。通常ミドルボタンは、マウスホイールであることが多いかと思いますが、MX Anywhere 2 までは違いました。

MX Anywhere 2の マウスホイールクリックは「スムーズスクロールの切り替え」です、意味が分かりません。MX Masterのように、高速スクロールで自動的にフリースピンにシフトすればいいじゃない。

私はWeb画面やコードはミドルボタンで自動スクロールさせて読むので、ミドルクリックを多用する割に使いにくい配置で最悪だと思ってます。

https://www.logicool.co.jp/ja-jp/manuals/11892 より

MX Anywhere 3では、ついにマウスホイールでミドルクリックできるようになりました。高速スクロールで自動的にフリースピンにシフトするし、普通になった。

https://www.logicool.co.jp/ja-jp/products/mice/mx-anywhere-3.910-006005.html#specs より

改善点2. 横スクロールがスクロールホイールになった

MX Anywhere 2 も MX Master もマウスホイールを横に倒すと横スクロールができます。 これ、一見すると直感的でいいんですが、スクロール量の調整ができなくて私には使いにくいです。

MX Anywhere では、ホイールは横に倒せなくなり、代わりに親指付け根あたりの左/右のどちらかのボタンを押しながらスクロールで横スクロールになります。 スクロール量の調整は普通のスクロールと同じなので普通に使いやすいです。普通に使える、大事。

https://www.logicool.co.jp/ja-jp/products/mice/mx-anywhere-3.910-006005.html#specs より

改善点3. 充電ケーブルが USB-C になった

micro-USB がそろろそ根絶したい今日この頃ですがそうもいかないのが続きます。 MX Anywhere 2 もその1つだったのですが、ついに USB-C になったのでまた一つ減りました。普通、大事。

改善点4. 充電を取り戻す

MX Anywhere 2 は毎日ずっと使っているので、一月程度で充電が必要になってきました。 MX Anywhere 3 に変えることでリセットです。

というのはおいておいても、1分の充電で1時間、1日の充電で70日持つので実際いい感じです。(2022/2/13追記)

電池寿命: 1回のフル充電で最大70日使用可能。1分間の急速充電で3時間使用可能

改善点5. ラバーからシリコーングリップへの変更

買うときに気にはしていたもののどうかと思ったのですが、7か月使って問題なさそうなので追記します。 MX Anywhere3 ではグリップ部分がラバーからシリコーンに変わりました。

これにより合成樹脂で起こる時間が経つとべたべたになるやつが起こらないことが期待できます。 以前2年使っていた MX Anywhere2s はべたべたがわかる感じになっていますが、MX Anywhere3 はいまのところ買ったとき同様のさらさらでよい感じ。

k-tai.watch.impress.co.jp

まとめ

MX Anywhere のこれまでの良さである、軽くて小さい、マルチペアリングと切り替え、Unifyingによる高い安定性などのメリットはそのまま。 MX Anywhere 2 の欠点をカバーしてきて、満足度とおすすめできる度が高くなりました。

残りは静音性が次にほしくなる時の鍵になりそうですね。(クリックを静かにしたい欲)

リモートワークで使えるイヤホン

以前の記事で、リモートワークでイヤホンをいろいろ試したことを書きましたが、実際使えるイヤホン、使えないイヤホンの個人的なポイントを書いておきます。 なお、イヤホンといいつつヘッドホンやヘッドセットも含まれます。

なお、イヤホンの接続先は MacBook Air M1 です。

tl;dr;

  • 優先/無線なら、無線を選ぶと便利かつ今なら音質な問題もない
  • スピーカーは、ノイズキャンセリングがあると周りの音よりリモートの音に集中できる
  • 最重要はマイク。ヘッドセットのような口元マイク(ブームマイク) + ノイズキャンセリングがついているのがいい
  • 骨伝導ヘッドセットだと耳を覆わないので、長時間の着用がつらくない、家で周りの音も聞こえつつリモートの音に集中できてよい

(よかった) Sony MDR-1000X

以前買っていた古いヘッドホンを引っ張り出して来たら、マイク、スピーカーともに優秀でした。(2017年2月購入) ワイヤレスノイズキャンセリングステレオヘッドセットとかいうだけあって、マイクの音もしっかり伝わり、スピーカーも問題ありません。 ノイズキャンセリング、大事。

www.sony.jp

今なら、正当進化したWH-1000Xシリーズでいいかと思います。

www.sony.jp

MDR-1000Xは好きだったんですが、筐体が弱く、イヤーパッドの上の本体部分の樹脂が割れてお蔵入りしていました。

壊れやすい箇所

飛行機でも音が気にならないので、本当にいいイヤホンです。(CES で気になって買ったやつでした)

(よかった) AfterShockz OPENCOMM

前回も書いた骨伝導イヤホンです。詳しくはそっちを見ていただければ。

同ブランドにAEROPEX というのもありますが、比較動画でわかる通りマイク性能が違います。

AEROPEXaftershokz.jp

リモートワークで気になるのが、話している相手の声、じゃなくてキーボード音なのですね。 OPENCOMM は、AEROPEX に比べて、スピーカー直と違和感ない程度には声が曇らず、キーボードのタイプ音も小さくなります。 OPENCOMM + Krisp のソフトノイズキャンセリングが組み合わさると、キーボード音がほとんど消えるのでこの組み合わせが気に入っています。 Aeroとの違いはマイク部分なので、なるほどブームマイク + ノイキャン効果ある。

www.youtube.com

ということで、キーボードタイプ音がうるさいか気になっている人は OPENCOMM 使うといいです。Krisp も組み合わせてください。 今一押しはこれですね。

ちなみに、マイク部分を上に上げると、外部の音がマイクから伝わりますが、マイクが口元にあるときは周辺の音がマイクから先に伝わりません。 普通にBGM鳴らしていても伝わらないので結構すごい。

(だめだった) WH-CH710N

いろいろ試そうと思って、MDR-1000Xよかったし、今の下位モデルでもいいのではと思って試しました。

www.sony.jp

スピーカーはいいのですが、マイクが壊滅的で、リモートワークでZoom/Meets/Teams ともに声が小さく、ぶつぶつ切れるという状況になりました。(krisp オフでも変わらず) マイクがほぼ機能しないので致命的でダメです。

(だめだった) HyperX Cloud Stinger

有線で、口元にマイクがあってよさそうじゃないですか。 無線より有線がいいという言説をよく聞くのでどうかなぁと思って試しました。 が、マイクがだめで声が大きくならずぶつぶつ切れるという状況になりました。(krisp オフでも変わらず)

ゲーミングヘッドセットwww.hyperxgaming.com

スピーカーもノイキャン付きの Sony に比べて蒸れて熱くなりやすく、好みではなかったです。

まとめ

いまならオープンエアーかつノイキャン付きのAfterShockz OPENCOMM がいいですね。 部屋で閉じこもって、外の音を気にしたくないなら、WH-1000X でもいいかと思います。

AirPods も知人と試した感じだと問題ありませんでしたが、私は使ってないので記載していません。

そういえば、一時 Bose や Plantronics がリモートワークで使えると話題になったのできになるところですが、OPENCOMMベースで考えると満足できるのかな。 片耳はなんとなくずっと避けているのですが。

リモートワークでの切り替え

リモートワークが続いて1年余り経ちました。 ここ半年余りの課題は、仕事中の集中、切れ目の2つなのですが、解消するために何をしているか残しておきます。

tl;dr;

オフィスで集中で来ているなら、その状況を作れるように努力する、ということでいろいろやっています。

  • 机の上をオフィスと同じようにする
  • 仕事前に身支度を整えて恰好から入る
  • 一日の目標は意図的に細かく書き出して達成目指す
  • Twitter は開かない
  • 骨伝導ヘッドセットを付けて過ごすことにしたところ、以前オフィスで仕事をしていた時のように意識を切り替えるのが楽になった
    • 骨伝導で 16時間使い続けられるのは本当に楽なのでよいです
  • 昇降デスクや昼寝など、自分の癖にあった対策はする
  • ごはんはサラダから (冗談のようで本気)

課題

結果は出す、けど自分が納得いく集中状態に入っていたかというと疑いがあるので、「リモートワークでの切り替え」でいかに集中状態にもっていくかが課題です。

もともと私はずっと仕事をしていても気にならないほうです。 これは、仕事と楽しいことが一致しているからなのですが、夢中になって気づいたら時間が過ぎていることがほとんどです。

ただ、リモートワークだと今までオフィスや深夜の集中で得ていたなにかと別の能力が求められるようです。 オフィスでの仕事だと簡単に集中に入るのが、リモートワークだとあと一歩足りないような。(語彙力) 時間は過ぎているけど、自分が自分に期待するだけの納得いく進捗を感じないような。(表現力)

深夜作業や緊急メンテなどで容易に得ている集中を継続的に再現したいです。

切り替えを促すためにやっていること

意識の切り替えは自分への暗示だと思っているので、いくつかやり方が思いつきます。 太字にしたものは、私が今行っていることです。

  • 机の上をオフィスと同じようにさっぱりと片付ける
  • カメラでずっと映るようにする
  • 常時オンライン雑談部屋に参加
  • 一日、あるいは単位時間の目標を常に示して細かく達成していく
  • 仕事と私生活の場を切り離す
  • スマホを見えないところに置いておく
  • Twitter を開かない
  • 仕事のトリガーを作る
  • 集中切れた、眠くなった対策

知人は、仕事用の部屋に移ってやることで完全に意識を切り替えているということで、これはいいなぁと思います。 ただ、あいにくと私はそういう部屋を設けているわけではないのでなしです。

やっていることを簡単に振り返っておきます。

(集中) 机の上をオフィスと同じようにさっぱりと片付ける

私の普段のデスクの状態です。 仕事場でもそうなのですが、私は極力ものを減らすのが好きなので机の上はキーボード、マウス、切り替え、お茶、スマホのみです。

オフィスと家で、同じように余計なものを置かないので代わり映えしないとも言います。

デスクの上

オフィスだとスマホはカバンにいれているので、スマホはノイズですが、後述します。

(集中/切れ目) 常時オンライン雑談部屋に参加

常時オンライン雑談部屋に参加していると、いつ声がかかってもいいようになります。という意味で、結構切り替えを促してくれています。 一緒の部屋で仕事をしている、というほどではないのですが、一緒にやっているという空気感はあるようです。

もちろん、必ずしも雑談しないといけないわけでもなく、必要な時に相談を行ったりという自由があるぐらいが気楽に感じます。 仕事終わるときに抜けると切れ目にもなります。

経緯

リモートワークが始まって3か月ぐらい経ったころの2020年6月までは朝ミーティングのみオンラインでやって、以降は必要に応じてオンラインにしますが基本オフラインでいました。が、限界を感じたので、常時オンラインをやるようにしてもらいました。(フットワークの軽いチームですごくいい)

リモートワークになることの最大のつらみは、信頼を貯める方法が減る、雑談機会の減少と思っています。

オフィスでの作業が別に最高とは言わないのですが、顔を合わせる以外に人となりを知っていることによる信頼はあったようです。さりげない会話や雑談、相談時のレスポンス、応答の様子をオフラインで行うと、比較的に好意的に受ける情報が想定していたのより大きいのだなぁと思います。1

リモートワークでの作業は、チャットやコード、レビューといったテキストベースのコミュニケーションに偏重していくように思います。 これは、たとえ朝・常時オンラインで話していても、観測範囲では例外なくその傾向があります。 オフラインで得られていた相手を信頼する機会/信頼される機会、オフィスでは自然と周りから聞こえてくる雑談を得る機会は意識してても減りました。失ってみて雑談が仕事上で大きかった、と3か月の間にたびたび感じることがあり危機感を覚えていました。

当時はそういう意味で「オフィスでの信頼貯金を崩しながらリモートワークをしている」と感じており、そろそろ限界を感じで常時オンラインミーティングに参加するというスタイルに切り替えたのでした。

切り替えてしばらくはお互いに遠慮するような「ぎこちなさ」がありましたが、一年もやっていると自然になってきているようで、雑談をする機会も増え、カジュアルなやりとりから相手を信頼をする機会も増えてきているのでいい傾向だと思います。 それでもオフラインのほうが楽なのは、やはり難しい。

よく言われることですが、人間は声だけでは冷たい印象を受けるので、顔や素振りを含めたコミュニケーションが圧倒的に有利です。つまり、オンラインでのコミュニケーションで白熱するとハラハラします。

課題

オフィスでも起こるものの、オンライン雑談のみになるとより起こりやすい課題がいくつかあります。

1つ目は、声が思ったより響いて集中が切れる問題です。 オフィスでもあった? そうですね、ではオンラインミーティングではどうやりましょう問題があります。 今のところ邪魔にならない程度までボリュームを落とすことで、意識に入ってきにくいようにしていますが、気づきにくくなるのが怖いところ。(でもボリューム落とす)

2つ目は、コミュニケーションの乏しい相手ができることです。 これはチャットでも同じ課題があるのですが、やり取りをしない相手とは関わる機会が極端に減ります。2 オンライン雑談でも、何もやりとりの機会がなければずっと同じでしょう。リモートワークでは常時オンライン雑談にいても喋ること自体のハードが高く、難しいものがあります。(伝われ) 別にそれでもいいのかもしれないとも思いますが、どうなんだろう。

3つ目の課題は、雑談の総量の減少です。リモートオンラインって、頑張っても一つしか聞こえないんですよね。オフラインだと複数チャンネルきこえて、たとえ自分がかかわっていなくてもやり取りが聞こえる、というのがありましたが。

4つめの課題は、オンラインで喋った内容をチャットやドキュメントに残す癖がないと取り残される人がどうしても発生することです。これは会話する人ほど気づきにくい問題で、取り残される人は未来の自分も会話を忘れれば該当するのですが、当事者になるまで自覚できないのが厄介です。 オフィスでも起こるんですけど、ほかの人が意外と覚えてて救われた経験ありませんか? 私はあります。 リモートワークだからこそ、チャットなどに会話の内容を要約して書く癖はあるといいと思います。(やる人を尊敬しています) この問題はあるいは、自転車置き場問題とも近いものがあるので、永遠に難しいですね。

2021年になっても、こういう基本的な課題が解決があると感じます。

(集中) 一日、あるいは単位時間の目標を常に示して細かく達成していく

始業時に、今日これやります、とチャットに書いておく、その程度でも効果はあります。 自分自身の予定というメリットもありますが、リモートワークでチームみんながやることを書いているのは、チームの状態共有や相談のきっかけになったりしてて良いと感じます。

コツ

やることを1つ二つ書くよりも、意図的に内訳を細かく書いて、自分で自分の達成を意識するのが好みです。 やりすぎはよくないけど、やることが目の前にはっきりしていると集中できるタイプの人間です。 「これが終わった、次はこれ」、たぶんこれが私が集中するルーティンで一番効果があります。

NOTE

終業時にやったことを書くのは、振り返りという意味でありなきもするけど、私は朝やることをどんどん追記しているのでどっちでも。

Disclaimer

ここではあえて、アジャイルなどの開発手法とは混ぜて書きません。

(集中) Twitter を開かない

これはTwitter に限らず、自分が頻度を高めにをやっているSNSと置き換えてもいいかもしれません。

私は、PC上ではTwitterを「ブラウザで特定のプロファイルを使わないとみれない」ようにしています。 仕事用のブラウザプロファイルでは見れないようにしてあるので、Twitterを見れるプロファイルでブラウザを起動しないルールを自分に課すことで集中の分散を防いでいます。

経緯

よく見かける気がしますが3、Twitter を見るというのは時間が消えます。 自分にはない知見を得られる場なので、おもしろく当然だと思います。 ただ、面白いということは他で使っていた集中が途切れているとも思うので、私は見ないようにすることを仕事との切り替えに利用しています。

(集中/切れ目) 仕事のトリガーを作る

今から仕事、仕事おわり。を示す方法として、物理的に身に着けるものがあるのは有効だと思っています。 出社のように、顔を洗って家仕事用の服に着替えたりといった身支度はしていましたが、それは休日でもあまり変わりません。

ということで、骨伝導ヘッドセットのAfterShokz OPENCOMMを仕事の時に身に着けるようにしました。

OPENCOMMaftershokz.jp

いくつか使ってて良いことを書いておきます、やりたいことができて、細かい不安がないのがいいです。

  • Zoom / Google Meets / Teams でもマイク、スピーカーともに問題なく、ノイズキャンセリングヘッドセットなのもあり、相手からも声がきっちりとどいているといわれており安心して使えます。(私は MacBook Air M1 とつないでいます)
  • イヤホン、ヘッドホンと違って一日つけるのを続けていても痛くなったりしないのは骨伝導のメリットと当時も今も思います
  • 骨伝導は5年前に使っていた頃は2時間あまりしか持たず微妙でしたが、これは16時間つなぎっぱなしもできるので、バッテリーで困ったことがありません。(充電がマグネットなのもよい)
  • もし充電をずっと忘れても急速充電が可能(5分充電するだけで2時間使える)なので適当になんとかなります

ここ半年、特に集中状態にもっていくのに結構悩んでいたのが、これを付けるようにしてオフィスの感覚により近づいているので維持したいところです。

ヘッドセットを外すと仕事終わり、つけると仕事で集中、という自己暗示に便利。

経緯

オフィスにいたときから、集中するためにイヤホン、ヘッドセット、骨伝導イヤホンといろいろ使っていました。 リモートワークになってみると、オフィスと違ってマイク問題が結構課題で、ヘッドセットのマイクだとリモートミーティング時に音が切れたりしたのでつけるのをやめていました。 あと、家だからこそ、周りの音が聞こえないのは主に宅急便などで困る。

リモートワークになってから、このヘッドセットを見つけるまで試行錯誤を繰り返しました。(たびたび試した4品全部だめだった)

(集中) 集中切れた、眠くなった対策

集中が切れたり、眠くなることもあります。(寝ないでいれても、集中が底辺になるのがまずい)

  • 軽く集中が切れたときとかは、昇降デスクなので立って仕事しています。気づくと深夜までたってます
  • 完全に眠い時は、昼ごはん後に15分寝ています。あきらめて寝ると、眠気飛んで集中がすごいので割り切っています

幸い目覚ましを無限にかけるので昼寝で寝過ごしたことはないのですが、夜しっかり寝るのがいいでしょう。4

あ、ご飯はなるべく食べましょう。食べたら眠くなる?これはお得情報ですが、サラダ山盛り食べてからほかのものを食べ始めると、冗談抜きで食後眠くならないのでオススメです。セブンの大根サラダを食べています。

7premium.jp

経緯

オフィスにいるときだと、少し外に出てコンビニ行ったりするやつですね。 リモートワークだと本当に外でないですよね、私のリモートワーク中の徒歩は平均300歩でした。 ということで、試行錯誤してモノで解消できるならする、など打てる手は打つようにしています。

今後やるか検討していること

今はデメリットも感じるのでやっていないものの、間違いなく効果があるので検討しているものです。

(集中) スマホを見えないところに置いておく

オフィスと同様に、目に写らないように片付けようかと思っています。 集中して存在が目に入らないことも多いのですが、チャットの通知など気にしたいことがあり、悩んで一年経ちました。

ただ、通知に気づかないとそれはそれで困るので、果たしてどうするのがいいのかまだ悩んでいます。 オフィスだと、誰かに甘えてたんですね。(どうしても気づかないときは声をかけられていた)

まとめ

いろいろ書いていますが集中は今でも課題で、やっぱりリモートワーク難しいなぁと思っています。 深夜に一人で仕事して、しっかり集中もしていたので、ここまで悩むことになると思ってなかったのですが、どうやらリモートワークはそれとは別の何かが必要なようです。

リモートワークでもできる、けど、よりよい方法を見つけられていないと常に感じます。 ほかの人のやっていることも、見つけると試すのですがなかなかしっくりこない。

もっと細かく自分で分析していかないと改善するのは難しいのかもしれない。

そして、お前は本当にオフィスで日中集中できていたのか?


  1. カメラだとそこまで感じないのはなぜだろう
  2. 私が times チャンネルを嫌う理由は、この問題を加速させるためです
  3. この時点でだめ
  4. それはそう

GitHub Actions の setup-dotnet と ホストランナーの .NET SDK

GitHub Actions で .NET Core ビルドを行いたいときに利用するものといえば、setup-dotnet があります。

github.com

今回は Ubuntu-latest な環境で setup-dotnet がいる場合と、そうでない場合について考えてみます。

tl;dr;

  • GitHub Actions ホストランナーのデフォルト環境で .NET はビルドでき、最新が1-2週で入ってくるのでOSS はsetup-dotnet なしで十分
  • プロダクトなど .NET SDK バージョンを厳密に制御する場合は、setup-dotnet を使うとよい
  • setup-dotnet は global.json を読んでくれるので、バージョン固定するなら global.json 便利

GitHub Actions と ホストランナー

GitHub Actions のホストランナーは環境ごとに特定のツールがインストールされた状態になっています。 例えば、ubuntu-latest である Ubuntu 20.04 LTS 環境 なら、以下のツールが入っています。

https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-README.mdgithub.com

2021年5月13日時点で .NET SDK は次のバージョンが入っており、かなり網羅されていることがわかります。 2.1 / 3.1 / 5.0 に関してはおおむね困らないでしょう。

2.1.300 2.1.301 2.1.302 2.1.401 2.1.402 2.1.403 2.1.500 2.1.502 2.1.503 2.1.504 2.1.505 2.1.506 2.1.507 2.1.508 2.1.509 2.1.510 2.1.511 2.1.512 2.1.513 2.1.514 2.1.515 2.1.516 2.1.517 2.1.518 2.1.519 2.1.520 2.1.521 2.1.522 2.1.523 2.1.602 2.1.603 2.1.604 2.1.605 2.1.606 2.1.607 2.1.608 2.1.609 2.1.610 2.1.611 2.1.612 2.1.613 2.1.614 2.1.615 2.1.616 2.1.617 2.1.700 2.1.701 2.1.801 2.1.802 2.1.803 2.1.804 2.1.805 2.1.806 2.1.807 2.1.808 2.1.809 2.1.810 2.1.811 2.1.812 2.1.813 2.1.814 2.1.815 3.1.100 3.1.101 3.1.102 3.1.103 3.1.104 3.1.105 3.1.106 3.1.107 3.1.108 3.1.109 3.1.110 3.1.111 3.1.112 3.1.113 3.1.114 3.1.200 3.1.201 3.1.202 3.1.300 3.1.301 3.1.302 3.1.401 3.1.402 3.1.403 3.1.404 3.1.405 3.1.406 3.1.407 3.1.408 5.0.100 5.0.101 5.0.102 5.0.103 5.0.104 5.0.200 5.0.201 5.0.202

このため、わざわざ setup-dotnet を使わずともdotnet cli は参照できますし、ビルドも可能です。 つまり、setup-dotnet を使わない場合、GitHub Actions のホストランナーに事前インストールされた複数の .NET SDK から必要なバージョンが参照されます。

setup-dotnet

setup-dotnet がやっていることは、「特定のバージョンの .NET SDK を azure feed からダウンロード、展開して参照できるようにする」ということです。

GitHub ホストランナーは Prerelease の .NET SDK には未対応で、ホストランナーの環境更新も 1週間に一度程度なので待ってられないというケースが稀にあります。 そんなときsetup-dotnet は Prerelease にも対応しており、まだfeed に乗っていないリリース直後の .NET SDK バージョンを利用するときに便利です。

GitHub Actions ホストランナーUbuntu 20.04 LTS の環境更新頻度

また、setup-dotnet はバージョン省略時にglobal.json があればそのバージョンを読む機能もあります。global.json と CI のバージョン固定なら global.json でいいというのはあるので、これはこれで便利です。(global.json の配置場所がリポジトリルートではない場合は少しアレってなりますが)

    if (!version) {
      // Try to fall back to global.json
      core.debug('No version found, trying to find version from global.json');
      const globalJsonPath = path.join(process.cwd(), 'global.json');
      if (fs.existsSync(globalJsonPath)) {
        const globalJson = JSON.parse(
          // .trim() is necessary to strip BOM https://github.com/nodejs/node/issues/20649
          fs.readFileSync(globalJsonPath, {encoding: 'utf8'}).trim()
        );
        if (globalJson.sdk && globalJson.sdk.version) {
          version = globalJson.sdk.version;
        }
      }

setup-dotnet/setup-dotnet.ts at bf3c3eb1fdba530a22805f082a2dcebc125d6ce4 · actions/setup-dotnet · GitHub

setup-dotnet の副作用

さて、この記事をここまで読んでいる人は「setup-dotnet を使うとインストールした以外の SDK が使えなくなる」という状況になったことがあるのではないでしょうか? ホストランナーの環境には、複数の .NET SDK が入っているにも関わらず、です。

これは setup-dotnet が、SDKのインストール時に .NET SDK の参照ルートパスを ホストランナーのデフォルトパス /usr/bin/dotnetから setup-dotnet で入れたSDK のパス $HOME/.dotnetに切り替えているために起こります。 結果、 setup-dotnet でインストールした以外のSDK バージョンは参照できなくなります。 .NET SDK のルートパスは、環境変数 DOTNET_ROOT に任意のパスを設定することでサクッと切り替えることができます。というのが気付きでした。便利。

setup-dotnet は installer.ts でこれを設定しています。

        // 184 行目
        core.exportVariable(
          'DOTNET_ROOT',
          path.join(process.env['HOME'] + '', '.dotnet')
        );

setup-dotnet/installer.ts at bf3c3eb1fdba530a22805f082a2dcebc125d6ce4 · actions/setup-dotnet · GitHub

実際に GitHub Actions で .NET SDK の参照パスと利用可能バージョン一覧を見てみましょう。 setup-dotnet を利用する前は、標準の/usr/bin/dotnetが利用されています。

GitHub Actions ホストランナーデフォルトの .NET SDK 状態

setup-dotnet を利用すると、パスが /home/runner/.dotnet/dotnet になり、利用可能な SDK も限定されていることがわかります。

setup-dotnet利用後の.NET SDK の参照パスと利用可能バージョン一覧

まとめ

一見すると、setup-dotnetを使うとめんどくささが増えてメリットがスポイルされているように見えます。 しかし、プロダクトなど厳密に .NET SDK のバージョンを管理したい場合は、setup-dotnet を使うのは合理的でしょう。 一方で、基本的にホストランナーには最新バージョンの.NET SDKが入っているので、OSS では 脆弱性情報などの対応を除き ホストランナーのデフォルトで十分というのは言えそうです。

  • setup-dotnet を使うと、.NET SDK preview や任意の.NET SDK をインストールができる
  • setup-dotnet を使うと、デフォルトの .NET SDK のパスから、setup-dotnet でインストールした .NET SDK のパスに変更されるため、ホストランナーのデフォルト .NET SDK 達はパス省略で使えなくなる

今日の学びでした。

Terraform の構成

ベストプラクティスといいつつ、どういう風にやりたいかで変わるというのは往々にしてあります。 ベストプラクティスは求めても意味ないのでどうでもいいとして、いろんなパターンのメリット/デメリットを把握して現状に即しているのかどうかは考え続ける必要があります。

ということで、長年頭を悩ませて納得感があまりない代表が Terraform です。 今回は以下の記事を読んでて、普段やっている Terraform の構成について書いてなかったので記録として残しておきます。

blog.serverworks.co.jp

TL;DR;

  • ディレクトリ分離 + モジュールでやっているけど、基本的にローカルモジュールに寄せている
  • locals.tf で差分を完全に抑えて、モジュール内は分岐なしの型で環境の違いを表現している

実は Workspace で分離してもさほど問題ないといえば問題ないことに読み直して、ふと考えが変わってきました。 ただし、Workspace の state後戻りができないのが厳しく、この環境だけしれっと追加みたいなカジュアルさは欠けるというのはあります。 そういう意味で、やはり Workspace は手放しで使う気にはなれないものがあり、微妙だなぁと感じます。

HashiCorp社の Terraform ベストプラクティス

ベストプラクティス自体よりも、開発元がどのようなコンセプトを持っているかは注目に値します。

Terraform開発元のHashiCorp 社(以降、公式)はたびたびBest Practice 的なことを謳いますが、具体的な構成を示していた昔のリポジトリは archive されて久しいものがあります。だめじゃん。

github.com

Nebulaworks の例

公式はさまざまなリポジトリ構成があるといいつつ、具体例をほぼ示していない。と感じつつも、Nebulaworks の例を2020/Jan/18 にブログで紹介しプレゼン動画で構成を見ることができます。(0.11.11 の頃なので0.14の今ではproviderやversions などは古く感じます)

www.hashicorp.com

youtu.be

youtu.be

この中で以下のモジュール構成例を示しています。(いわゆるよくあるモジュール構成) プレゼンの内容はいうほど特筆することはないです。

.
├── env
│   ├── dev
│   │   ├── main.tf
│   │   ├── module.tf
│   │   └── reseources.tf
│   ├── prod
│   │   ├── main.tf
│   │   ├── module.tf
│   │   └── reseources.tf
│   └── staging
│       ├── main.tf
│       ├── module.tf
│       └── reseources.tf
└── modules
    └── resources.tf

Nebulaworks Module Directory Structure

公式では構成は示されないので、仕方ないのでコミュニティに学びにいく旅に出ることになります。(2021年になっても変わってない)

なぜ Terraform の構成は難しいのか

改めて、Terraformの構成が難しいのはなぜか考えてみると、terraform はパスベース + .tf 拡張子で参照ファイルや変数のスコープ1が決まります。 スコープが驚くほど広いわりに、言語機能としてそのスコープ内でファイル限定といった表現力は持たないため、ファイル構造でカバーすることになります。 これが難しい原因の多くを生み出しているように感じます。 具体的にあげると、

  1. 言語としてはシンプル、だけどスコープも広いために収拾がつきにくい
  2. インフラ構成はただでさえブラストラディウスが広いにも関わらず、言語による「影響を限定させるサポート」に乏しい。2
  3. 同じコードを何度も書くのは事故の原因なので、なるべくDRYにいきたいが運用しやすさとのトレードオフはしないようにするサポートが乏しい。3

言語機能が貧弱というほうが適切かもしれないですね。

ということで、今現在よく使っている構成と、きっかけとなったブログのセクションについて考えます。

よく使っている構成

私は実行環境をTerraform Cloud に一本化しています。(以前はatlantis を用いていました)

今現在よく使うディレクトリ構成は次のものです。 EKS は特に悩みやすいのでサンプルを置いておきます。

├── common (VPC分離の場合のみ)
├── dev
│   ├── compute.tf
│   ├── data.tf
│   ├── iam.tf
│   ├── locals.tf
│   ├── modules
│   │   ├── compute
│   │   │   ├── ecr
│   │   │   │   ├── main.tf
│   │   │   │   ├── outputs.tf
│   │   │   │   └── variables.tf
│   │   │   ├── eks
│   │   │   │   ├── iam
│   │   │   │   │   ├── eks_cluster_role
│   │   │   │   │   │   ├── main.tf
│   │   │   │   │   │   ├── outputs.tf
│   │   │   │   │   │   └── variables.tf
│   │   │   │   │   ├── eks_node_role
│   │   │   │   │   │   ├── main.tf
│   │   │   │   │   │   ├── outputs.tf
│   │   │   │   │   │   └── variables.tf
│   │   │   │   │   └── eks_pod_role
│   │   │   │   │       ├── data.tf
│   │   │   │   │       ├── main.tf
│   │   │   │   │       ├── outputs.tf
│   │   │   │   │       └── variables.tf
│   │   │   │   ├── main.tf
│   │   │   │   ├── oidc
│   │   │   │   │   ├── bin
│   │   │   │   │   │   └── oidc_thumbprint.sh
│   │   │   │   │   ├── main.tf
│   │   │   │   │   ├── outputs.tf
│   │   │   │   │   └── variables.tf
│   │   │   │   ├── outputs.tf
│   │   │   │   └── variables.tf
│   │   │   └── kubernetes
│   │   │       ├── main.tf
│   │   │       └── variables.tf
│   │   └── iam
│   │       ├── account
│   │       │   ├── main.tf
│   │       │   ├── outputs.tf
│   │       │   └── variables.tf
│   │       ├── role
│   │       │   ├── main.tf
│   │       │   ├── outputs.tf
│   │       │   └── variables.tf
│   │       └── user
│   │           ├── main.tf
│   │           ├── outputs.tf
│   │           └── variables.tf
│   ├── outputs.tf
│   ├── providers.tf
│   ├── variables.tf
│   └── versions.tf
├── production
├── staging
└── modules
    ├── iam
    │   └── iam_role
    │       ├── main.tf
    │       ├── outputs.tf
    │       └── variable.tf
    └── xxxxx

原則

この構成は、運用においてモジュール構成に分岐や入れ替えなどを起こさないことを目的に組んでいます。 そのため、次の原則に基づいています。

  • Workspace を使った dev/staging/production の環境切り替えは用いない
  • 環境ごとの差分は local変数で表現し、モジュールやdataを含むコードは、構成が全く同じなら同じとする。(./locals.tf)
  • ルートの共通Module には普遍的で必ず環境差分が起こらない共通化するモジュールのみ配置する。(./modules)
  • モジュールには、アプリの事情を込みで記述し、ルートのlocals.tf に記述した環境ごとのパラメーターを variables.tf で受け取る。(./dev/modules など)
  • 環境の違いがある場合、その環境のローカルモジュールのみ変更を加える。(基本的に locals.tf のパラメーターのみで対応できるようにモジュールに改修を入れる)

この原則だけわかっていると、ただのシンプルなModule構成です。 誰が見ても初見ですぐにわかり、影響を分離できるようにするのがゴールです。

要はモジュール構成ではモジュールを共通化するのが前提ですが、初めからローカルモジュールに展開するように割り切った構成です。

terraform ファイルの記載内容

モジュール内部の構成は見ればわかると思うので、ざっくりとdevフォルダ配下のファイル説明だけ見てみます。

  • data.tf: data リソースの定義を行っています
  • locals.tf: local変数定義を行います。環境ごとの定義はここですべて表現されます。環境差分はここだけ発生します
  • modules: ロジックはすべてモジュールに閉じ込めます。compute.tf などにresourceを直接書くことはなしです
  • outputs.tf: よくある出力定義です
  • providers.tf: プロバイダー一覧
    • 0.13 から provider がいい感じになったので、main.tf をやめて providers.tf と versions.tf にきっちり分離するようになりました
  • variables.tf 実行時の variables.tf 差し込みはterraform cloud でのクラウドへの認証差し込みなど必須な情報以外入れない
  • versions.tf: terraform ブロックとプロバイダーバージョン、backend 指定

残りのcompute.tfやiam.tfは、ただのモジュール参照です。 main.tf に羅列していると使いにくいので、いつでもリソースをパージできるように分けています。 tfstate の分離はもちろんしますが、するしないはプロジェクト規模でも変わって来たりするので、ここでは簡単のため同一stateとしました。

NOTE: terraform を使って upgrade とかしていると、providerとversionsはこういう形になる気がします。(0.12で自動生成されたversions.tf にはじめ戸惑いましたが、0.13で納得いく変更がきた)

www.terraform.io

この構成で最も設計しないといけないこと

ローカルモジュールの設計が大事になります。

  • 異なる環境でも同じlocal変数の型でモジュールが受けるようにできるようにすること
  • ローカルモジュールの凝集
  • module のoutput

環境差分は locals.tf にのみ許容することはやってみると全然できます。 しかし、いざやると dev だけ 2つリソース作って、stagingやproduction では 1つだけ、などといった差に出会ったりするでしょう。 そういったものは型でうまく解決するようにします。

例えば、1つ、2つといった数の差異がモジュールで閉じ込められるように mapを使ったり map は型表現が弱いので set(object) を使ったりといった工夫は必要です。 共通モジュールでも、分岐ではなく、こういう型での解決をするほうが望ましいことは多いので別に違いはないといわれるとそうですね。

元記事の迷子

私もいつも迷子なので今時点の考えを書いておきます。

workspace 使うのか使わないのか問題

使いません。

とはいっても、元記事の「今どの workspace にいるのか」という問題が発生しません。 これは、Terraform Cloud の remote apply を必須にしているため、Workspaceを使わずとも環境ごとに Terraform Cloud の Workspaceは分離されているからです。

使わない理由は別にあります。 workspace 機能を用いた場合、環境ごとに差分が生じた場合に、差分を吸収するために分岐を用いたりするのがいやだったからです。 workspace の効果で得られる共通リソースで完結するメリットは、「分岐を見逃した場合など発生することが当然あるであろう状況で環境を破壊するリスク」に比べて割が合わないと思っているからです。

私は人間はミスをすると思っているので、ミスが起こっても影響が抑えられる構成を好みます。

環境の分割方法問題

環境の分割は、見ての通り「環境ごとにディレクトリを作る」です。 シンプルな反面めんどくさくなるのが「漏れがあったら」という問題ですが、それは locals.tf への環境差分の限定とモジュール設計で対応します。

module 設計問題

  • prod/stg それぞれで構築する: ローカルモジュール
    • 将来にわたって完全に同一で差分がない場合のみ、共通モジュールで定義します
  • 環境別に構築したりはしないが両方で利用する: ローカルモジュール
    • 将来にわたって環境ごとの破壊的な変更が起こらず、完全に共通利用でき環境差分がない場合は、共通モジュールへ配置
  • 片方だけ構築する: ローカルモジュール

今行っている構成では、まったく同じ構成なら、diff を行っても locals.tf 以外に差分が出ません。 そのため、devで検証が終わりstagingやprodに適用する場合も、モジュールは丸っとディレクトリごとコピーで構わないので変更もれリスクが抑えられます。(localst.tf だけ残して残り丸っとコピーでいい)

共通Modules + 分岐が必要なものを、ローカルモジュールに振っているので、そういう悩みが起こらない設計にしています。 同じものを複数書くのではなくコピーにしているのは、まったくスマートではないですが、悩むことより事故は起こらないものです。

自作 module か、公式 module か問題

私は自作module が多いようです。

公式module を一時期に優先して使っていたのですが、awsモジュールなどで結構破壊的変更があったので苦しくなってやめました。 とはいえ、vpcなどは公式モジュールでも十分に柔軟で、破壊的変更も起こされた記憶がないので使ってもいいです。(この見極めが難しいのが公式モジュールの問題だと思います)

variable の配置方法問題

これはベストプラクティスに乗らない理由がないので遵守します。

  • ファイル分割: 分割する
  • 格納データの型: 厳密に指定する。map(string) よりは object(型) で定義して、差し込むときは map で指定するのがいいです
  • デフォルトの値有無: 基本的にデフォルト値はなし
    • デフォルト値があってもいいのは、入らなくても動作にまずい影響が起こらない場合のみです
    • デフォルト値をないようにすると、値を意味を持って指定することになるため意図のない設計が発生しないためです

NOTE: 事故があってからデフォルト値なしに考えを変えました。デフォルト値、意図がない限り基本的に避けたほうがいいです。

過去に参考にした構成

コミュニティから学ぶことは多くあります。 今の構成はこれらの構成を自分でやってみて、納得がいかない部分を変えています。

terraform-aws-providerコミッターが公開している 以下の構成はよく見かけるものです。

github.com

small

.
├── README.md
├── main.tf
├── outputs.tf
├── terraform.tfvars
└── variables.tf

medium (large は未完成で medium と同じ)

.
├── README.md
├── modules
│   └── network
│       ├── main.tf
│       ├── outputs.tf
│       └── variables.tf
├── prod
│   ├── main.tf
│   ├── outputs.tf
│   ├── terraform.tfvars
│   └── variables.tf
└── stage
    ├── main.tf
    ├── outputs.tf
    ├── terraform.tfvars
    └── variables.tf

他にもありますが、コンセプト似てますね。

kenzo0107.github.io

dev.classmethod.jp

future-architect.github.io

他にもレイアード構成とかもやってた時期がありました。

書籍としては、「実践Terraform AWSにおけるシステム設計とベストプラクティス 」が良書です。module構成から、ローカルモジュールにもう少し振ってもいいと思ったきっかけは、この本でした。

https://www.amazon.co.jp/dp/B07XT7LJLCwww.amazon.co.jp

他に、「Google Cloud Platformで学ぶTerraform 〜実践編〜」などもテストが手集めに書かれています。(一方で構成はあまり触れていません)

techbookfest.org

おわり

terraformを使い始めて、もう使って5年たつような気がしますが、ディレクトリ構成には今も納得がいかないです。とはいえ、過去に試した構成よりも納得度と、変更の楽さ、影響度の限定ができているので今はこれで。

CDK や Pulumi のような、プログラミングの一般的なルールで構成できるものはこういうところが圧倒的に楽です。 とはいえ、Pulumi や CDK を書いてから terraform に戻ると、型を意識せずに依存関係が解決されて楽極まりないのもあり、なんとも難しいものだと感じます。

どっちもいいし、どっちもまだまだ改善の余地があるので、引き続き迷子を楽しんでいきたいものです。

ベストプラクティスがないのはいいですが、公式でそろそろモジュールの典例はしめしてもいいのではと思いますが、HashiCorp社なのでしないでしょう。残念ですが。

蛇足

リソース名のsuffix

いろんな経験を積んだ結果、アカウント分離だろうと、リソース分離だろうと、リソース名のsuffix には _dev などの環境名を含んで設計するといいと思っています。 あと、CDK や Pulumi のようなランダムリソースsuffix も好ましいですが、文字長制限で怒られたりするので 2021年にもなって各クラウドはいい加減にしてくれと引っかかる度に思っています。

文字種 4もそうだけど、文字長制限5が許されるのは201x年で終わってほしかったけど、現実はそんなに甘くない。

Terraform公式で示しているベストプラクティス

公式は、主に次のようにTerraform をどのように運用に乗せていくかのベストプラクティスを示しています。 とはいえ、内容はどのように現状を把握して使える状態にもっていくかがメインです。

www.terraform.io

具体的なTerraform 構成は触れていないものの、Terraform Cloudの文脈でプラクティスをいくつか示しています。 3.3.4 を要約します。(要約は気になる方はぜひ元文章もどうぞ)

  • VCS リポジトリ/ブランチと Terraform Cloud のWorkspace をマッピングさせて
  • AppやServiceの各環境は、同じリポジトリ/ブランチのTerraformコードで管理し
  • 異なる環境は variables で表現しつつ Workspace 事に適切に設定する

NOTE: 加えて、環境ごとにブランチを分けるのではなく、1つの正規ブランチをもとに全環境に適用することにも触れています。

Part 3.3.4 Create Workspaces

また、この中で自作モジュールの作成基準についてダイアグラムを示しています。(同時にナレッジシェアしようといったことも言っています)

Part 3.2.3 Create Your First Module

また、Terraform のチュートリアルにおいて、モジュールをプログラミング言語によくあるライブラリ、パッケージなどと似たものと触れつつ、ベストプラクティスを示しています。

learn.hashicorp.com

We recommend that every Terraform practitioner use modules by following these best practices:

  1. Start writing your configuration with modules in mind. Even for modestly complex Terraform configurations managed by a single person, you'll find the benefits of using modules outweigh the time it takes to use them properly
  2. Use local modules to organize and encapsulate your code. Even if you aren't using or publishing remote modules, organizing your configuration in terms of modules from the beginning will significantly reduce the burden of maintaining and updating your configuration as your infrastructure grows in complexity
  3. Use the public Terraform Registry to find useful modules. This way you can more quickly and confidently implement your configuration by relying on the work of others to implement common infrastructure scenarios
  4. Publish and share modules with your team. Most infrastructure is managed by a team of people, and modules are important way that teams can work together to create and maintain infrastructure. As mentioned earlier, you can publish modules either publicly or privately. We will see how to do this in a future tutorial in this series

しかし私は構成の例が欲しいのであった。

モジュールのベストプラクティス

モジュールを書く時の注意がいくつかあります。 とはいえ、別に大したことはいってないので普通にやればいいのではないでしょう。

  • Dependency Inversion
  • Multi-cloud Abstractions
  • Data-only Modules

www.terraform.io


  1. せめて local 変数がファイル内部でスコープがとどまるならまだしも
  2. 影響を限定させる手段としてモジュールやstate分割を使っていくことになる
  3. Workspace やモジュール参照で同一ソースを使うなどを使っていくことなる。
  4. - とか _ とか使える文字種がずれたりするのはとても悪い文化
  5. 64文字制限もあれだけど、32文字制限とか許せない