ishikawa_pro's memorandum

若手webエンジニアの備忘録です.

Swift Node.js Docker AWS etc...色々やります。

2022年振り返り

こんにちは。 2022年も終わりなので今年も振り返りブログを書きます。
2022年に書き始めましたが、今年も年内に書き切れなくて年を跨いでしまいました。

仕事・エンジニア編

まずは仕事やプライベートでの技術的な取り組みなどの振り返りです。
月単位とかで書こうと思ったのですが、長期スパンでやってたこととかが多かったので、適当なトピックごとにまとめて振り返ろうと思います。

先輩エンジニアの退職

今年は、入社時からお世話になっている先輩が何人か退職された年でした。
なかでも1月に、サーバーサイドに関して困ったら大体その人に相談するという存在の上司が退職されたのは大きな出来事でした。
ぼくも普段から色々と技術的な相談をしていたので、退職すると聞いた時はびっくりしました。
なので、1月は色々と引き継ぎ作業などをやっていました。
社内の頼れる先輩エンジニアはいつまでもいてくれるとは限らないので、みなさんの周りにもそういう人が居たら、居るうちに可能な限り色々なことを吸収しましょう。

普段の業務の変化

昨年までは、新規サービスの開発や新機能の開発などを主にやっていましたが、昨年の10月くらいから社内のサービス開発基盤的なのを改善したり色々保守したりするようなチームに異動しました。

日常的な業務内容は主に

  • マイクロサービスで構築された開発基盤のコードレビュー
  • パフォーマンス改善
  • 開発基盤を使ったサービス開発などの設計相談役 & レビュー
  • 内製ツールキットのメンテ
  • 色々とバージョンアップ
  • 必要に応じて開発基盤を使ってプロダクト開発をしているチームのサポート

などをやっています。
明確なポジションとかはないですが、多分テックリード的な役割が近いんじゃないかと思いながら仕事をしています。

コードレビュー

上司が退職して色々と役割を引き継いだこともあり、コードレビューをする量が昨年と比べると多分2倍くらいになりました。
最初は勘所が分からなくて大量のコードレビューで1日のほとんどが終わっていた時期もありましたが、慣れてきて早くなったのと、レビューフローやレビュワーの見直しなどもして負担が軽減されたのもあって、最近は結構コードレビューに使う時間も減りました。

SRE と関わる機会が増えた

会社には SRE のチームが別であるのですが、 SRE のメンバーと連携し仕事をする機会も結構増えました。
去年、 k8s や分散システムの本や記事を読んで勉強していて、アプリケーションだけでは解決が難しい問題も、インフラ側でやればもっと簡単に解決できることもあるから、インフラも含めて色々考えられるようにならないとなと思うようになりました。
そういう気持ちもあって、今年は自分で k8s を見る機会も増えたし、 k8s や istio などの情報を接種する機会が圧倒的に増えました。
twitter の TL も気づいたら SRE や k8s を触ってそうな人が増えたので、自分の興味関心もそっちに移ってきたんだろうなと思いました。
ただ、もっと基礎的なインフラの知識が浅いので、来年はインフラの基礎も勉強し直したいなと思っています。

今年取り組んだこと

Next.js ホスティング基盤の構築
社内でフロントエンドが新たに Next.js を採用するということになり、社内用の Next.js ホスティング基盤のようなものも構築していました。
詳細は会社のテックブログでまとめたので、是非読んでください。

cam-inc.co.jp

developers.cyberagent.co.jp

初めて Google Cloud Run を採用したり、インフラの設計もゼロからやるのは初めてだったので、学んだ点も多く非常に楽しかったです。

ローカル開発環境の改善
Next.js 関係のことがひと段落した後は、ローカル開発環境に色々課題があったので、ローカル開発環境の改善などに取り組んでいました。
今までは microk8s と内製GUIツールを利用したローカル開発環境を用意していたのですが、 mac での microk8s の不安定さや内製ツールのメンテコストが高いことによりローカルの開発サイクルが遅くなっていたので、 Tilt というツールに移行を決定しました。

tilt.dev

このプロジェクトは 10 月くらいから始めてまだ進行中なので、頑張って来年の早いうちに完成させて開発者体験を向上させたいと思います。

ローカル開発環境の刷新にあたり色々調べていて、この Lyft社の記事がすごく良くて参考になりました。 (最終的に自分がTiltを推した決め手にもなった) eng.lyft.com

Go採用
普段は Node.js しか書いてないのですが、色々あり Go も採用することになりました。
まだ Go製のサーバーはリリースするにまでに至っていないですが、来年の早いうちには何かしら形にしていきたいなと思っています。
ぼくの Go の知識は、公式サイトのチュートリアルをやったことがある程度の知識だったので、ちょっとずつ Go の勉強も始めています。

イベント系

タップル|CAM|アンドパッド 合同勉強会で発表
会社の看板を背負って発表するのは始めてだったので結構緊張しました。
マイクロサービスを採用したサービス開発基盤について話しているのと、後半でパネルディスカッションもやりました。
andpad.connpass.com

speakerdeck.com

www.youtube.com

ISUCON 12 予選に出場
大会の振り返りはこちらのエントリーを参照。
DB が MySQL 8 だったりで、練習していたことが使えないなどもあり、あんまりいい結果ではなかったです。。
来年もあれば是非参加したいと思います!
ishikawa-pro.hatenablog.com

会社のテックブログ書いた
Gatsby.js のサイト生成をするための内製基盤システムをパワーアップさせた時の話をまとめました。
consistent hashing などを活用して分散システムにしたことについてまとめているので是非ご覧ください。
cam-inc.co.jp

会社でベストエンジニア賞を取った
会社では半期に一度、活躍した社員を表彰するイベントがあります。
そのイベントで、半期で最も活躍したエンジニアとして最優秀ベストエンジニア賞に選ばれました。
自分は選ばれないだろうなと思って油断していたので本当にびっくりしました。(その場で発表されるまで本人には知らされないようです)
受賞者のスピーチも当然なにも考えていなかったので、しどろもどろになりながら話してしまいました。

しどろもどろに受賞者スピーチをする様子

色々な人がサポートしてくれて取れた賞だと思います。
これに満足せず、引き続き技術力を高めて組織に貢献できるように頑張ります。
彼女もサプライズでお祝いしてくれました。

サプライズでお祝いしてくれた

いつも支えてくれてありがとうございます。
後日お祝いで高いしゃぶしゃぶを食べに行きました。

お祝いのしゃぶしゃぶ

個人的な取り組み

週一でニュースレターを書いてみた。
ブログとの棲み分けは、個人的にブログはしっかりまとまった中身のある文章を書きたいなと思っています。しかし、そういう文章を書くのは時間とエネルギーが必要で、どうしても書く頻度が落ちてしまうため、もう少し雑な内容でもいいからアウトプットを増やす場所としてニュースレターを選んでみました。

www.getrevue.co

しかし、仕事が忙しい時にお休みしたらそのまま更新しなくなってしまいましたw
週一という制約を自分に課したら、まあまあ負担になってしまったので、来年は何かしらスタイルを変えてアウトプットを増やしていきたいと思います。

勉強

技術書
買った本

www.oreilly.co.jp

www.oreilly.co.jp

gihyo.jp

www.oreilly.co.jp

最後まで読み切れたのは並行プログラミング入門だけでした。。
技術書を読む時間が捻出できず、ほとんど読み切れずに終わってしまいました。。
僕はなるべく隅々まで熟読したいのですが、そういう読み方をしているとどうしても時間がかかってしまうので、全体に目を通しつつ興味がある部分はしっかり読むようにするとか、読み方も工夫が必要かなと思ったりしています。
また、場所を取るのと重いという理由で物理本から電子書籍に移ったのですが、やっぱり紙の本の方が存在感があって読まないといけないと思えるのと、パラパラと流し読みしたり読みたいページにジャンプしやすい気がしているので、来年は物理本に戻ろうかなと思っています。
あとは、会社で輪読会をしてみるとか、仕事の一部にしてしまってうまく読み切れる本を増やしていきたいなと思っています。

技術の勉強に関して
技術書の方でも触れましたが、あんまり腰を据えて勉強する時間が今年は取れませんでした。
仕事も入社当時よりはポジションが上がっているので忙しくなっていますし、プライベートも勉強だけに費やせる訳ではなくなっているので、バランスを取るのが難しいですが、来年は色々やり方や考え方を変えて、勉強する時間も増やしたいなと思います。

英語の勉強
アプリで英語の勉強も始めました。
きっかけは、彼女が趣味で韓国語の勉強をしていて、自分も語学を勉強するかと思い、仕事で読むことの多い英語を勉強し始めました。
やっているアプリは、 duolingo と スピークバディです。
とりあえず毎日継続することを目標にして、頑張りすぎないスタイルでゆるゆるとやっていて、 12月31日までで132日継続しています。
(たまに飲み会とかでできない日もありましたが課金してれば大目に見てくれるw)

duolingo の記録

ぼくの duolingo の進め方は、大きなセクションごとに飛び級試験が用意されているので、毎日1個飛び級試験を受けていって、飛び級試験がパスできないセクションは何個か問題を解いて理解したらまた飛び級試験を受ける、というのを延々と繰り返しています。
おかげで duolingo で英語学習者の上位 11% に入ったようです。継続は力なりですね。
スピークバディーは、1日1レッスンを受けています。
スピークバディーのいいところは、話す相手が人間ではなくプログラムなところです。ぼくはコミュ障なので日本語でも初対面の人と話すのは得意では無いので、プログラムが話し相手になってくれるのは心理的障壁が少なくて継続しやすいです。また、いくらでも相手が話していることを聞き返すことができるし、何度でも納得いくまでスピーキングの練習ができるのもいいところです。
英語学習の効果として、すごく英語が読めるようになったとかはないですが、毎日英語を一定量接種するので、仕事で英語を読む時の心理的ハードルは下がりました。
あと、スピークバディーで英語のリスニングとスピーキングをするようになって、バイリンガルニュースというよく聞いている podcast で前よりちょっとだけ聞き取れる文章が増えたきがします。

プライベート編

ここまでは技術と仕事的な振り返りで、次はプライベート編。
これも適当なトピックごとにまとめます。

彼女できた

厳密には、去年の 12/25 から付き合い始めました。
付き合う前は、大体休日は昼すぎまで寝て、気が向いたら勉強するかダラダラする生活でしたが、付き合ってからは色々なところにデートしにいくようになりました。
他にも色々といい影響を与えてくれて、おかげでとても変化の多くよい一年になりました。

引越し

新卒として上京して以来ずっと住んでいた部屋から引っ越しました。
前々から引っ越そうと思っていましたが、彼女ができたので会いに行きやすい地域へ引っ越しました。
リモートで仕事をすることも多いので、仕事するスペースを別で確保できる広めの部屋がいいなと探していたら、築1年の1LDKの部屋が比較的安く空いていたので、その部屋に即決しました。
不動産屋に安い理由を聞いたら、元々入居予定だった人が転勤になってキャンセルになってしまって、ずっと空いていたから値下げしたらしいです。
事故物件じゃなくてよかったです。笑
ちょっと想定外だったのは、部屋が広いと電気代が思ったより高くなることでしたが、それ以外は問題なく快適に過ごしています。

自炊はじめた

今年から自炊し始めました。
凝った料理をするわけではないですが、引っ越したことでキッチンが広くなり、しないのも勿体無いので、彼女に教わりながら自炊し始めました。
今までコンビニ飯ばかりだったので、健康的な体になったんじゃないかと思います。

整体に通い始めた

肩こりと首の痛みがひどくて辛くなってきたので、ついに整体へ通い始めました。
最初の1 ~ 2ヶ月くらいは毎週通っていて、少しよくなり始めてから隔週で通うようになりました。
本当は、もっと良くなって月1で通う程度にまで頻度を落としたいのですが、首周りがすぐに悪くなるので隔週で通っています。

ジムに通い始めた

ジムに通いはじめました。
これも彼女が anytime fitness に契約していてそそのかされたのと、整体師さんに運動した方がいいですよと言われたので始めました。
これも英語学習と同じで、継続することを目標に週2で頑張りすぎない程度に続けています。
内容は、簡単そうな器具を使って首肩まわりのコリに効きそうなやつもやりつつ、まんべんなく筋トレしています。
あとは体力も付けたかったのでルームランナーでランニングもしています。
正直ランニングの方がスッキリしてストレス解消にもなるので好きです。
ジムに通い始めてから、睡眠の質がすごく上あがったのでよかったです。
来年も継続してやりたいとおもいます。

(買って|もらって)よかったモノ

最後に買ってよかったものです。

HUAWEI EyeWear

HUAWEI が出している、Bluetoothのスピーカーとマイクが内蔵されたメガネです。
非常に良くて記事も書いたので詳細はそちらをご覧ください。
買って以来ずっと愛用していて、ミーティングには必須のアイテムとなりました。
ishikawa-pro.hatenablog.com

oura ring

oura ring という sleep tracking ができる指輪型ガジェットです。
彼女が誕生日プレゼントに贈ってくれました。
それまでは apple watch と garming vívosmart の2個を使っていましたが、 vívosmart の方をやめて oura ring に変えました。
スリープトラッキングの精度は結構高いし、充電も 3 ~ 4 日に1回でいいので便利です。
デザインもシンプルで気に入っています。
ouraring.com

電動昇降式デスク

ikea の電動昇降式デスクを買いました。
整体師さんに、ずっと座って作業するのは腰や首の負担になるからよくないと言われたので、簡単に昇降できる電動式のものを奮発して買いました。
ボタン一つで上下してくれるので非常に便利で、モニターアームも付けて基本的に立って PC 作業をするようになりました。
www.ikea.com

ドラム式洗濯乾燥機

何人か知人がドラム式洗濯乾燥機を持っていて、すごく便利だと言っていたので、引っ越しを機に買いました。
これも奮発して高めのやつを買ったので、洗剤や柔軟剤を自動投入してくれるし、洗濯が終わったらスマホに push通知してくれるのでとても便利です。
QoL 上がるのでおすすめです。

ななめドラム洗濯乾燥機 NA-LX129AL 商品画像 | 洗濯機/衣類乾燥機 | Panasonic

まとめ

今年は仕事もプライベートも変化の多い年になりました。
2023年も振り返った時に、色々なことをやったなと思える年にしたいとおもいます。

オンラインミーティング用に HUAWEI の Eyewear を買ってみた

こんにちは。
今日は HUAWEI の Eyewear というガジェットを買ってみたのでその紹介です。

consumer.huawei.com

Eyewear とはメガネにスピーカーとマイクが内蔵されており、スマホとペアリングすることで音楽を聴いたり通話したりすることが可能なガジェットです。

買ったきっかけ

僕は普段ソフトウェアエンジニアをしています。
会社ではリモートの人もオフィスへ出社する人もいます。
そのためミーティングをする場合、参加者のうち1人以上はリモートから参加される場合が多いので、必然的にオンラインでのミーティングになります。
僕は通常、毎日1 ~ 3時間くらいミーティングをしているのと、コーディング中はイヤホンで音楽を聴いて過ごしていました。
その生活を続けていたら先日、外耳炎になってしまい耳垂れが出てしまうようになってしまいました。
それをきっかけに耳に負担のかからないいいヘッドセットがないか探し始めました。

どこで見つけたか

たまたま backspace.fm という podcast を聴いていたら、ゲストのテクノエッジ編集長の Ittousai さんが HUAWEI の Eyewear が素晴らしいと紹介されていて見つけました。
後編で Eyewear の話が出ますが、他の話も面白いので是非前編から全部聴いてください。

backspace.fm

他のエピソードも面白いのでガジェット好きの人にはおすすめの podcast です。

スペックや特徴など

細かいスペックなどは公式ページを見ていただきたいですが、簡単に紹介します。

バッテリー

  • 音楽連続再生時間: 約6時間
  • 連続通話: 約4.5時間

もう少し長いとありがたいですが、連続通話時間が 4.5 時間あれば、お昼休憩中に充電すれば日常業務ではギリギリ耐えられそうかなと思います。

充電端子

メガネの両テンプルの先端に充電用の特殊端子を装着し、反対側は Type-C のケーブルを挿すようになっています。

Eyeware を充電する様子

耐水性

IPX4 です。
雨の日にかけてても大丈夫なくらいですかね。

通話

通話ノイズキャンセリング対応

ペアリング

マルチポイント対応です。
2台のデバイスまで同時接続できます。
マルチポイントで肝心なのは切り替えのスムーズさですが、まあまあです。
macスマホの2台をペアリングしていると、 macスマホでうまく切り替わらない時がたまにあります。 mac のデフォルトのオーディオ出力を別の物にしておき、 meeting の時だけ Eyeware に変えるとおおむねスムーズに切り替わります。

メガネの種類

3種類あります。

後述しますが、 OWNDASY とも提携していて OWNADYS では別のデザインを用意しています。
※ 画像は公式ページより拝借しました

質量

装着感としてはかなり軽くていいです。

感想など

箱やケース

箱は iPhone くらいのサイズで、高級感のあるいい感じな箱でした。
専用のケースも付いてきます。柔らかいケースなので、バッグに入れて持ち歩きたい人は別途ケースを買った方がいいかもしれないです。

装着感

装着感はとても軽くて楽です。
スピーカーなどのデバイスが入っているとは思えないほど軽いです。
過去にメガネを何回か作ったことがあるのですが、長時間つけていると大体耳の後ろが当たって痛くなりますが、 Eyeware は 1日かけていても痛くならなかったです。

操作

操作は、左右のテンプルにセンサーが入っており、スワイプして音量調整や曲を前後に送ったり、ダブルタップで音楽の停止や電話に出たりすることができます。
HUAWEI のアプリを入れることでカスタマイズも可能です。
ワイヤレスイヤホンと同じような操作性なので特に戸惑うようなことはなかったです。

音質

音質はあまり期待していませんでしたが、意外と良い音です。
指向性のあるスピーカーを使っていて、テンプルの上下にある穴から音が出ています。
個人的には shokz などの骨伝導型イヤホンよりは良い音な気がします。
この記事を書いてる間ずっと装着して音楽を聴いてみましたが、作業に集中してあまり音質を気にしないような状況では丁度良さそうです。
僕は podcast も良く聞くのですが、音声に関してもとても聞き取りやすいです。

音漏れ

音漏れは、結構な音量にしないと分からないです。
かなり静かな場所でないと多分隣の人とかにも聞こえないと思います。

マイク性能

マイク性能は、やはり bluetooth 接続なのであまり良くないです。
僕がハキハキ喋らないのもあると思いますが、ノイズキャンセルで発話時の頭が削られるような感じになっている場合がたまにあるみたいです。 (meeting で他の人が僕の声を聞いた感想)
meeting 時のマイクの音質は譲れないという人は、マイクだけPC内蔵のマイクなど別デバイスを接続する方がいいかもしれないです。

その他

日本では、 HAUWEI のオンラインストアでも購入することができますが、 OWNDAYS というメガネショップと提携していて、店舗で購入することも可能です。
HAUWEI の公式ストアとは違うデザインが用意されているのと、OWNDASY だと度入りのレンズ込みで購入することができます。
僕はOWNDASYの渋谷の店舗で購入しましたが、お店に行ってから視力検査込みで1時間ちょっとで持ち帰ることができました。

www.owndays.com

マグネットで装着できるサングラスのプレートも 1700円くらいで別売されています。 僕はサングラスを付ける習慣はないですが、安かったので一緒に買ってしまいました笑

価格は、税込32780円なのでちょっと良いメガネを買ったと思えば良い買い物をしたと思います。

ISUCON 12 予選にNode.js実装で参加しました

今年も ISUCON が開催されたので予選に参加しました。
色々忙しくてブログに起こすのに時間がかかってしまいましたが、来年のためにしっかりやったことを記録しておきます。

予選までにやったこと

さくらインターネットさんが参加者にクーポンを発行してくださっていたので、VPS を使って過去問を解いたりしていました。
内容としては MySQL の slow query の設定であったり、 nginx のログフォーマットを変えて alp で解析できるようにするなど、大会開始後にやる下準備をスムーズにできるように練習したりドキュメントにまとめたりしていました。
あとは、 普段 MongoDB しか使ってないせいで MySQL の作法をほぼ覚えてないので、 index の見方や貼り方なども一通り復習してよく使うクエリとかはドキュメントにまとめたりしていました。
今年は複数台のインスタンスを活用しようと思って、インスタンスを2台立てて1台を MySQL サーバー用でもう一台をアプリケーションサーバー用にして、アプリケーションから外のMySQL に接続しにいく練習などもしました。

当日

細かい時間などは記録していなかったので、やったこと順で記述していこうと思います。

言語の切り替え

まずはセットアップを完了したら、初期設定の Go でベンチを試しました。
初期スコアを記録していませんでしたが、 3000 ちょっとくらいのスコアでした。
次に Node.js 実装に切り替えてベンチを実行しました。
一気に 2500 くらいまでスコアが下がって少し悲しくなりましたが、Node.js の名誉のためこのまま Node.js 実装で進みました。  

コードのバージョン管理

まずは作業に入る前に、コードを git 管理して github 上に push しました。
github.com

DB の設定などは面倒だったので別リポジトリに分けて管理しました。
github.com

基本的に作業単位でブランチを切って PR 作成して、セルフマージするスタイルで進めていました。

visit_history のインデックス追加

alp や MySQL の slow query log の設定をしたところで、とりあえず pt-query-digest を使って slow query の集計をしてみました。
初期の状態だと、 visit_history の SELECT がかなり遅かったので、

# Profile
# Rank Query ID                            Response time  Calls R/Call V/M
# ==== =================================== ============== ===== ====== ===
#    1 0x676347F321DB8BC7FCB05D4948FC2248  120.8258 55.1%  1311 0.0922  0.06 SELECT visit_history
#    2 0x94A9E43DFAAFA029A1FC19A5563AD0F5   91.4036 41.7%  8626 0.0106  0.00 REPLACE id_generator
# MISC 0xMISC                                7.0060  3.2%  2393 0.0029   0.0 <11 ITEMS>

解析結果の詳細を確認しつつコードの方も見て、

# Query 1: 16.39 QPS, 1.51x concurrency, ID 0x676347F321DB8BC7FCB05D4948FC2248 at byte 1400628
# This item is included in the report because it matches --limit.
# Scores: V/M = 0.06
# Time range: 2022-07-23T02:34:33 to 2022-07-23T02:35:53
# Attribute    pct   total     min     max     avg     95%  stddev  median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count         10    1311
# Exec time     55    121s   214us   563ms    92ms   230ms    76ms    65ms
# Lock time      0     3ms     1us   306us     2us     2us     8us     1us
# Rows sent     97 103.91k       0     199   81.16  174.84   51.71   62.76
# Rows examine  88  24.05M       0  49.19k  18.79k  49.01k  13.36k  13.78k
# Query size    25 182.98k     141     144  142.92  136.99    0.73  136.99
# String:
# Databases    isuports
# Hosts        localhost
# Users        isucon
# Query_time distribution
#   1us
#  10us
# 100us  ####
#   1ms  ###
#  10ms  ################################################################
# 100ms  ######################################
#    1s
#  10s+
# Tables
#    SHOW TABLE STATUS FROM `isuports` LIKE 'visit_history'\G
#    SHOW CREATE TABLE `isuports`.`visit_history`\G
# EXPLAIN /*!50100 PARTITIONS*/
SELECT player_id, MIN(created_at) AS min_created_at FROM visit_history WHERE tenant_id = 79 AND competition_id = '55bf3a2d2' GROUP BY player_id\G

とりあえず tenant_idcompetition_id の複合index を貼りました。

github.com

結果はベンチを回すたびにばらついていましたが、2452 -> 2699 と思ったより上がりませんでした。
ただ、Count が 1311 から 2801 に上がっていたのと、 query_time distribution も 10ms の分布が一番多かったが 1ms の分布に移っていたので、結構効果自体はあると判断してそのまま先へ進みました。

# Query 2: 38.37 QPS, 0.65x concurrency, ID 0x676347F321DB8BC7FCB05D4948FC2248 at byte 2910547
# This item is included in the report because it matches --limit.
# Scores: V/M = 0.34
# Time range: 2022-07-23T03:02:40 to 2022-07-23T03:03:53
# Attribute    pct   total     min     max     avg     95%  stddev  median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count         21    2801
# Exec time     34     48s   218us      2s    17ms    36ms    76ms     7ms
# Lock time      0     6ms     1us    64us     1us     2us     2us     1us
# Rows sent     98 329.53k       0   4.88k  120.47  174.84  367.49   80.10
# Rows examine  62   5.15M       0  78.96k   1.88k   2.76k   5.78k   1.26k
# Query size    42 391.02k     141     144  142.95  136.99    0.71  136.99
# String:
# Databases    isuports
# Hosts        localhost
# Users        isucon
# Query_time distribution
#   1us
#  10us
# 100us  #####
#   1ms  ################################################################
#  10ms  ###########################################
# 100ms  #
#    1s  #
#  10s+
# Tables
#    SHOW TABLE STATUS FROM `isuports` LIKE 'visit_history'\G
#    SHOW CREATE TABLE `isuports`.`visit_history`\G
# EXPLAIN /*!50100 PARTITIONS*/
SELECT player_id, MIN(created_at) AS min_created_at FROM visit_history WHERE tenant_id = 1 AND competition_id = '547f03113' GROUP BY player_id\G

[GET] /api/player/player/[0-9a-z]+ api の改善

次に alp の結果を眺めつつ、さっと直せそうな場所を探して、

+-------+-----+-----+-----+-----+-----+--------+----------------------------------------------+-------+--------+--------+----------+--------+
| COUNT | 1XX | 2XX | 3XX | 4XX | 5XX | METHOD |                     URI                      |  MIN  |  MAX   |  AVG   |   SUM    |  P99   |
+-------+-----+-----+-----+-----+-----+--------+----------------------------------------------+-------+--------+--------+----------+--------+
| 537   | 0   | 498 | 0   | 39  | 0   | GET    | /api/player/competition/[0-9a-z]+/ranking    | 0.004 | 14.488 | 1.889  | 1014.383 | 13.556 |
| 461   | 0   | 432 | 0   | 29  | 0   | GET    | /api/player/player/[0-9a-z]+                 | 0.004 | 15.336 | 1.679  | 774.176  | 13.724 |
| 106   | 0   | 95  | 0   | 11  | 0   | GET    | /api/player/competitions                     | 0.004 | 0.112  | 0.026  | 2.804    | 0.108  |
| 55    | 0   | 47  | 0   | 8   | 0   | POST   | /api/organizer/competition/[0-9a-z]+/score   | 0.004 | 13.140 | 2.788  | 153.356  | 13.140 |
| 38    | 0   | 37  | 0   | 1   | 0   | POST   | /api/organizer/competitions/add              | 0.004 | 0.064  | 0.029  | 1.096    | 0.064  |
| 34    | 0   | 33  | 0   | 1   | 0   | POST   | /api/organizer/competition/[0-9a-z]+/finish  | 0.004 | 0.048  | 0.019  | 0.644    | 0.048  |
| 24    | 0   | 24  | 0   | 0   | 0   | GET    | /api/organizer/players                       | 0.004 | 0.032  | 0.008  | 0.184    | 0.032  |
| 20    | 0   | 20  | 0   | 0   | 0   | GET    | /api/organizer/billing                       | 0.004 | 1.168  | 0.179  | 3.584    | 1.168  |
| 14    | 0   | 13  | 0   | 1   | 0   | POST   | /api/organizer/player/[0-9a-z]+/disqualified | 0.004 | 0.024  | 0.016  | 0.228    | 0.024  |
| 11    | 0   | 6   | 0   | 5   | 0   | POST   | /api/admin/tenants/add                       | 0.004 | 0.092  | 0.047  | 0.520    | 0.092  |
| 10    | 0   | 8   | 0   | 2   | 0   | GET    | /api/admin/tenants/billing                   | 3.720 | 25.909 | 11.587 | 115.870  | 25.909 |
| 8     | 0   | 8   | 0   | 0   | 0   | POST   | /api/organizer/players/add                   | 2.040 | 5.964  | 4.025  | 32.200   | 5.964  |
| 1     | 0   | 1   | 0   | 0   | 0   | POST   | /initialize                                  | 2.648 | 2.648  | 2.648  | 2.648    | 2.648  |
| 1     | 0   | 1   | 0   | 0   | 0   | GET    | /css/app.83b4c321.css                        | 0.000 | 0.000  | 0.000  | 0.000    | 0.000  |
| 1     | 0   | 1   | 0   | 0   | 0   | GET    | /js/app.3a4ec98c.js                          | 0.000 | 0.000  | 0.000  | 0.000    | 0.000  |
| 1     | 0   | 1   | 0   | 0   | 0   | GET    | /index.html                                  | 0.000 | 0.000  | 0.000  | 0.000    | 0.000  |
| 1     | 0   | 1   | 0   | 0   | 0   | GET    | /api/organizer/competitions                  | 0.004 | 0.004  | 0.004  | 0.004    | 0.004  |
+-------+-----+-----+-----+-----+-----+--------+----------------------------------------------+-------+--------+--------+----------+--------+

[GET] /api/player/player/[0-9a-z]+ が結構叩かれていて、直せそうなところがあったので改善に取り組みました。

やったことは、player の詳細情報取得 api で、その player が属する tenant の competition を全て取得後に、 大会情報と 大会毎の player_score を for...of で1個ずつ直列に取得していたので、Promise.all を使って並列実行するように直しました。
今ブログを書きながらコードを見て思ったのですが、処理の最初の方で tenant に属する competision を全て取得してるので、ここで再度competisionを取得すること自体が無駄ですね。。

github.com

スコアはなぜか 2195 と落ちてしまいましたが、

+-------+-----+-----+-----+-----+-----+--------+----------------------------------------------+-------+--------+-------+----------+--------+
| COUNT | 1XX | 2XX | 3XX | 4XX | 5XX | METHOD |                     URI                      |  MIN  |  MAX   |  AVG  |   SUM    |  P99   |
+-------+-----+-----+-----+-----+-----+--------+----------------------------------------------+-------+--------+-------+----------+--------+
| 533   | 0   | 503 | 0   | 30  | 0   | GET    | /api/player/player/[0-9a-z]+                 | 0.004 | 19.148 | 1.301 | 693.451  | 14.260 |

リクエストの Count が増えていたのと、Latency も下がってはいたので、悪くはなっていないと判断して先にすすみました。

visit_history index の修正

最初の visit_history の index を貼ったことでそれなりに改善はしましたが、 pr-query-digest でみるとまだ SELECT visit_history が遅いようだったので、再度チューニングポイントがないか確認しました。

# Profile
# Rank Query ID                            Response time  Calls R/Call V/M
# ==== =================================== ============== ===== ====== ===
#    1 0x94A9E43DFAAFA029A1FC19A5563AD0F5  111.6499 66.4%  8822 0.0127  0.01 REPLACE id_generator
#    2 0x676347F321DB8BC7FCB05D4948FC2248   48.2423 28.7%  2908 0.0166  0.25 SELECT visit_history

該当のクエリはこういうクエリで、

SELECT player_id, MIN(created_at) AS min_created_at FROM visit_history WHERE tenant_id = 1 AND competition_id = '547f03113' GROUP BY player_id\G

tenant_id と competition_id の複合index を貼っているので WHERE 句は index が効いてそうでしたが、player_id で GROUP BY している部分で index が効いてなさそうでした。
そのため、tenant_id と competition_id の複合index から、 tenant_id, competition_id, player_id の複合indexへ変更しました。
before

# Query 2: 39.30 QPS, 0.65x concurrency, ID 0x676347F321DB8BC7FCB05D4948FC2248 at byte 2728622
# Scores: V/M = 0.25
# Time range: 2022-07-23T04:07:39 to 2022-07-23T04:08:53
# Attribute    pct   total     min     max     avg     95%  stddev  median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count         19    2908
# Exec time     28     48s   173us      2s    17ms    40ms    65ms     7ms
# Lock time      0     6ms     1us   129us     2us     2us     3us     1us
# Rows sent     98 331.91k       0   4.88k  116.88  183.58  361.27   76.28
# Rows examine  62   5.17M       0  78.96k   1.82k   2.89k   5.68k   1.20k
# Query size    40 405.93k     141     144  142.94  136.99    0.69  136.99
# String:
# Databases    isuports
# Hosts        localhost
# Users        isucon
# Query_time distribution
#   1us
#  10us
# 100us  #######
#   1ms  ################################################################
#  10ms  ###############################################
# 100ms  #
#    1s  #
#  10s+
# Tables
#    SHOW TABLE STATUS FROM `isuports` LIKE 'visit_history'\G
#    SHOW CREATE TABLE `isuports`.`visit_history`\G
# EXPLAIN /*!50100 PARTITIONS*/
SELECT player_id, MIN(created_at) AS min_created_at FROM visit_history WHERE tenant_id = 1 AND competition_id = '59cb9aad2' GROUP BY player_id\G

after

# Query 2: 40.55 QPS, 0.53x concurrency, ID 0x676347F321DB8BC7FCB05D4948FC2248 at byte 2180291
# Scores: V/M = 0.17
# Time range: 2022-07-23T05:56:48 to 2022-07-23T05:58:06
# Attribute    pct   total     min     max     avg     95%  stddev  median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count         23    3163
# Exec time     24     41s   184us   872ms    13ms    31ms    47ms     6ms
# Lock time      0    10ms       0     5ms     3us     1us    82us     1us
# Rows sent     98 365.81k       0   4.88k  118.43  183.58  346.65   80.10
# Rows examine  64   5.72M       0  78.96k   1.85k   2.89k   5.45k   1.33k
# Query size    46 441.47k     141     144  142.92  136.99    0.66  136.99
# String:
# Databases    isuports
# Hosts        localhost
# Users        isucon
# Query_time distribution
#   1us
#  10us
# 100us  ####
#   1ms  ################################################################
#  10ms  #################################
# 100ms  #
#    1s
#  10s+
# Tables
#    SHOW TABLE STATUS FROM `isuports` LIKE 'visit_history'\G
#    SHOW CREATE TABLE `isuports`.`visit_history`\G
# EXPLAIN /*!50100 PARTITIONS*/
SELECT player_id, MIN(created_at) AS min_created_at FROM visit_history WHERE tenant_id = 1 AND competition_id = '547f03113' GROUP BY player_id\G

結果は、 latency が少し改善されたのと、Query_time distribution で 100ms の分布が少し減って、 100us と 1ms の分布が少し増えたので、遅めのクエリが改善されたようでした。
スコアは記録を忘れていましたが、そこまで上がらず 2000 前半くらいで留まっていました。

csv upload を改善

csv upload で score を一括 upload するエンドポイント( POST /api/organizer/competition/:competition_id/score ) は、加点されるポイントが多い api だったため、改善に取り組みました。
SQLite を真面目に取り扱ったことがなかったですが、 for...of で一行ずつ直列に insert するのは明らかに良くないだろうと思い、改善してみることにしました。
調べると、bulk insert するときは transaction を貼った方が良いとのことだったので、とりあえずトランザクションを貼って、 insert を Promise.all で並列実行するように修正しました。

github.com

スコア 2642 と思ったほど上がらなかった(多分 flock のせい) ですが微増したので、マージしました。

id をライブラリで生成するように修正

当初から気になっていた、 REPLACE id_generator の方を改善みてみることにしました。

# Profile
# Rank Query ID                            Response time  Calls R/Call V/M
# ==== =================================== ============== ===== ====== ===
#    1 0x94A9E43DFAAFA029A1FC19A5563AD0F5  111.6499 66.4%  8822 0.0127  0.01 REPLACE id_generator
#    2 0x676347F321DB8BC7FCB05D4948FC2248   48.2423 28.7%  2908 0.0166  0.25 SELECT visit_history

これが何をやっているか調べてみたところ、 dispenseID というシステム全体で一意なIDを生成する関数で

REPLACE INTO id_generator (stub) VALUES ('a')\G

を実行して、 id_generateor の id を auto increment させて一意なIDとして使っているようでした。
REPLACE文 を発行してデッドロックで失敗したら再度 REPLACE 文を発行するというforループで、スピンロック的なことをやっていました。
この対応に関しては横着してしまおうと思い、 DBは使わずに uniqid という npm pacakge を使ってid生成するようにしました。

github.com

依存の無いシンプルなライブラリで node_module の管理が面倒だったので、アプリケーション内に uniqid ライブラリを内包するような形にしてしまいました。

スコアは、DBを使わなくなったぶん良くなり 2908 となりました。

その他

id_generator の対応をし終わったところで 17:00 手前でした。
残り時間もすくないため、細々とした対応でできそうなものだけやってみようといくつか取り組みました。
1つは、 MySQL のクエリキャッシュの設定をしようと思いました。
これは事前に練習していたので、設定方法などをメモっており、メモ通りに設定してみました。
ところがうまく再起動してくれません。
よくよく調べると今回は MySQL 8 が動いており、 MySQL 8 からクエリキャッシュは廃止になったそうです。。
MySQL 8 は実務でも全く使ったことがなく予習もしていなかったので、残り時間で何かするのは無理だと判断して、改善を諦めました。

2つ目は、 node cluster 対応しました。
node cluster とは、Node.js は本来シングルスレッドのイベントループを回して処理をするデザインパターンで実装されていますが、 cluster という標準モジュールを使うことで、メインプロセスから fork してワーカープロセスを起動することができます。
この機能を利用して、今回のサーバーアプリケーションをワーカー化し、複数スレッドを利用してリクエストを捌けるようにしました。  

github.com

起動するワーカー数は調整してみましたが、 3個が一番スコアが高く、 3317 でした。
この対応でちょうど finish となってしました。

まとめ

下記がスコアの推移です。

スコアの推移

Golang の初期スコアを少ししか越えられなかったのが、ちょっと敗北感を感じましたw 昨年は、あんまりできることがなくて時間を持て余していた感がありましたが、今回は全然時間たりないな〜という感じだったので、まあ去年よりは成長したかなと思いました。
あとは去年から業務で、Datadog APM とか色々ツール使って計測したりすることが増えて、計測した結果を眺める力は前より付いたなと実感しました。
ただ成績は結構イマイチだったので、また来年までしっかり業務も生かしながらスキルを伸ばしていこうと思います。

さいごに運営の皆様、今年も運営お疲れ様でした!

2021年振り返り

こんにちは。
2021年も終わりなので今年は振り返りブログを書こうと思います。

1月

今年も相変わらず Node.js や TypeScript でサーバーサイドのコードを書いてました。
1月末くらいまでは、昨年リリースしたかった案件がなかなか完成せずに、死にそうになりながら追い込み的なことをしていました。
その頃作った機能は、上司と一緒に会社のテックブログにまとめました。
初めて amazon chime sdk を使ったサービスを作りましたが、webRTC とかについて詳しくなくても簡単にビデオ通話機能が実装できて便利でした。
cam-inc.co.jp

その後、まだ日本での amazon chime sdk を使ったサービスの事例も少なかったことなどもあり、 aws の公式ブログでも紹介していただきました。
自分の名前も載せて頂けてとてもうれしかったです。死ぬまで自慢すると思います。
aws.amazon.com

2~7月

その後2月以降は、そこまで技術的になにかやった記憶はあまりないですが、仕事自体はそれなりに忙しかったです。

8月

8月は今年も ISUCON に参加しました。
細かいやったことなどは、別の記事にまとめてあります。
ishikawa-pro.hatenablog.com 記事にも書いたと思いますが、去年やれたことは今年もスムーズにやれたので前半は結構いいペースで進めた気がしますが、そこから先が全然スコアを上げることができなかったです。あと、前日の仕事の疲れが出てしまい、後半で集中力が切れてしまったのもありました。
ISUCON は、前年の自分のやったことや結果と比べて自分の成長を測れる機会だと思ってるのですが、あまりいい結果ではなかったので、最近仕事はこなしてるけど技術成長できていないなと色々悩むようになりました。

9 ~ 10 月

ISUCONもイマイチ結果が出なかったことや2~7月が特に技術的なことが何もできなかったことなどから、今後どうしていくか色々考えたりするようになってました。
そして、技術力を上げるために転職して環境を変えるのも1つの手かもしれないと思い、とりあえず相談するアテもなかったのでTwitter で転職希望ツイートをしたところプチバズってしまいました。
思ったより色々な人に声をかけていただき驚きました。
当然社内の人の目にもとまったので面談が入りました笑
結果的に転職はせず、現在は前とは違うチームに異動して、今は自分の伸ばしたいことなどとマッチしていて楽しく仕事をしています。
皆さんも悩んだ時はTwitterではなく、まずは信頼できる上司などに相談しましょう。
異動後は、結構心のゆとりができたので、今年まだ1冊も読めていなかった技術書を読み始めたり色々技術をキャッチアップしたりするようになれました。

11 ~ 12月

異動後は、社内のプロダクトの改善周りに取り組んでいます。
ちょうど読んでいた技術書を参考に、改善できたりしたこともあって色々勉強しながらできてるなと感じています。
あとは AWSGCP などインフラ周りは苦手だったのであまり触ってこなかったですが、最近は機会があれば自分で触って勉強したりしてます。

今年読んだ技術書

今年読んだ本はこちらです。

読んでる最中なのは、

  • データ指向アプリケーションデザイン
  • 並行プログラミング入門

です。 来年はもう少し沢山読みたいと思います。

まとめ

いろいろ振り返ると、アレはまだ1年も経ってないのかと驚くことが結構あります。
それだけ濃い1年だったということだと思うので来年もそうできるように頑張ろうと思います。
色々迷惑をかけた人が多いと思いますが、今年1年ありがとうございました。
来年精進するのでよろしくお願いいたします。

「分散システムデザインパターン」を読んだ

こんにちは。
最近はかなり日も短くなって寒くなり始めましたね。
今日は、ちょっと前に読み終わった「分散システムデザインパターン」についてメモです。

読んだモチベーション

この本を読もうと思ったきっかけは、最近 container 技術や k8s に関しての本を読んでいて、この本もよくおすすめに出ていたのがきっかけです。
あとは、普段の業務でマイクロサービスアーキテクチャであったり k8s や ECS を採用しているので、分散システムデザインについてもちゃんと知識をつけておきたいなと思っていたのもあります。

感想など

今回も電子版で読みましたが、物理本でA5サイズの200ページなのですぐに読めると思います。

本の構成はこんな感じでした。

1章 はじめに
第Ⅰ部 シングルノードパターン
2章 サイドカー
3章 アンバサダ
4章 アダプタ

第Ⅱ部 マルチノードパターン
5章 レプリカがロードバランスされたサービス
6章 シャーディングされたサービス
7章 スキャッタ・ギャザー
8章 ファンクションとイベント駆動処理
9章 オーナーシップの選出

第Ⅲ部 バッチ処理パターン
10章 ワークキューシステム
11章 イベント駆動バッチ処理
12章 協調的バッチ処理

13章 まとめ:新しい始まり?

第1部では、シングルノードでのデザインパターンを紹介して、2部ではマルチノードでのザインパターン、3部は分散システムでのバッチ処理デザインパターンについて紹介されていました。
まったく知らないデザインパターンとかはなかったですが、それぞれのパターンごとにサンプルもまじえて詳しく解説してあったのでとてもよかったです。
サンプルでは k8s を使っているので、k8s の基本的な部分の理解とかはあった方がより内容が理解しやすいかもしれないです。
個人的には、シャーディング、マスタの選出、ロックについてあまり詳しくなかったので、それらについて深くしることができたのはよかったです。

本自体は結構ページ数が少ないですが、内容としてはかなりよかったのでおすすめです。
ちょうどこの本を読み終わった頃に、たまたま業務でアプリケーションをシャーディングする機会があったのでめちゃくちゃ役に立ちました。
次は「データ指向アプリケーションデザイン」を読んでいるのですが、結構読みごたえあるので分けてブログにメモしていこうかなと思っています。

「Kubernetes 完全ガイド」を読んだ

こんにちは。
読書の秋ということで、小説・技術書ともに消化が捗っています。
小説は村上春樹にはまってます。
今日は、「Kubernetes 完全ガイド」を読んだのでその記録です。

読んだモチベーション

読もうと思った理由は、業務でk8s (GKE) を使っているのですが、普段はインフラ専門のエンジニアの方に管理して頂いてるのもあり、あまりガッツリ触る機会もなく、ふんわりとした知識しかなかったためです。僕が携わってるサービスは、マイクロサービスアーキテクチャを採用しており、k8sの理解を深めておくことで、よりよいアプリケーションの設計をするのにも役立つと思ったのも理由の1つです。

感想など

ページ数は650ページ以上あるので中々読みごたえがありました。

構成は、

  1. Docker の復習と「Hello, kubernetes
  2. なぜ Kubernetes が必要なのか?
  3. Kubernetes 環境の選択肢
  4. API リソースと kubectl
  5. Workloads APIs カテゴリ
  6. Service APIs カテゴリ
  7. Config & Storage APIs カテゴリ
  8. Cluster APIs カテゴリと Metadata APIs カテゴリ
  9. リソース管理とオートスケーリング
  10. ヘルスチェックとコンテナライフサイクル
  11. メンテナンスとノードの停止
  12. 高度で柔軟なスケジューリング
  13. セキュリティ
  14. マニフェストの汎用化を行うオープンソースソフトウェア
  15. モニタリング
  16. コンテナログの集約
  17. Kubernetes 環境での CI/CD
  18. マイクロサービスアーキテクチャとサービスメッシュ
  19. kubernetesアーキテクチャを知る
  20. kubernetes とこれから

1 ~ 3章はDockerの復習やk8sとは何かという感じでした。
4章がいきなり kubectl や k8s のリソースなどについて解説がされていて、僕がまだあんまりk8sの全体像が分かってない状態だったので、ちょっとこの本は早すぎたかもと思って一旦読むのをやめました。それで前の記事でも書いた 「イラストでわかるDockerとKubernetes」 を読んでから、 続きを読みなおしました。
ishikawa-pro.hatenablog.com 「イラストでわかるDockerとKubernetes」を読んだおかげで、コンテナ技術や k8s が裏で何をしているかなどについてある程度理解したおかげで、それ以降の章は特に苦戦することなく読むことができました。
4 ~ 8 章がk8sのリソースに関する説明を1章ごとに分けて説明されていました。 k8sを扱ったり理解するうえで大事な基本的な部分だったので勉強になりました。
9 ~ 12章も実際にk8sで開発するうえで関わってきそうな内容が多かったです。
13章のセキュリティ関しては、SericeAccountなどの基本的なところから 、SecurityContext とか普段あんまり触らないところも多かったので、部分的に軽めに流したりしながら読みました。
14 ~ 18章は、k8s に関する周辺のツールやサービスなどの紹介で、実際に業務で使ってるものや知らないものなどもあって結構楽しく読めました。
19 ~ 20章は、 「イラストでわかるDockerとKubernetes」 の内容と重複してる部分が多かったので復習がてら読みました。
僕は、実際に業務で使ってるマニフェストなどを見たり、こう書き直したりもできるかななど考えながら、理解を深めていく感じで読み進めました。
かなりページ数が多くて読みごたえのある本ですが、おかげでk8sに対する苦手意識がかなりなくなったのでよかったです。
最近は技術書を読む習慣がついてきたので、この調子で継続して勉強していきたいと思います。

「イラストでわかるDockerとKubernetes」を読んだ

こんにちは。
今日は、「イラストでわかるDockerとKubernetes」を読んだのでその記録です。
余談ですが今回は、iPad air4 を使って電子書籍で読んでみたのですがApple Books アプリは結構使い勝手が良くて便利ですね。電子だといいアプリないしなんか読みずらいなと思って最近は物理本に戻っていたのですが、Apple公式アプリがこんなに便利になっていたとは思いませんでした笑

読んだモチベーション

最初にこの本を知ったのは fukabori.fm で著者の徳永航平さんがゲスト出演されていてコンテナランタイムについてお話されていて、この本が紹介されていたからです。

fukabori.fm

このエピソード内でのコンテナランタイムなどのお話もとても面白くて、コンテナランタイムについて興味がわいてきて、本もわかりやすいとiwashiさんが紹介されていたので、エピソードが終わった後に即ポチしました。
あとは、k8sの勉強をしようと思って 「Kubernetes 完全ガイド」 を買ったはいいものの、思ったよりk8sに関する仕組み的な部分は書いてなさそうで、この本を読む前にもう1ステップはさみたいなとちょうど思っていたところだったのもあります。

感想

最初に読みやすさ的な部分ですが、タイトルの通りでイラストが多めなのと、ページ数も200ページくらいなのでサクッと読めました。(2日くらい)
タイトルからは初心者向けの本なのかなと思ってしまいそうですが、中身はコンテナランタイムに関する話やコンテナ技術とは何で、DockerやKuberntesが何をしてるのかについて解説してあります。なので、初心者というよりはある程度Dcokerなどを使い慣れててDockerやk8sが何をしてるのかしっかり理解したい人向けかなと思います。
構成は、

  • 1章 コンテナ技術の概要
  • 2章 Dockerの概要
  • 3章 kubernetesの概要
  • 4章 コンテナランタイムとコンテナの標準仕様の概要

となっています。
2章での、コンテナのレイヤ構造についての解説は、今までざっくりとした知識しかなかったので勉強になりました。 実際にoverayファイルシステムを使って、ファイルを重ね合わせてマウントしてみたりする部分や、 docker save コマンドでコンテナイメージをtar形式で出力して実際に中身を見てみる部分は、どのようにしてイメージからルートファイルシステムを作成しているのかが理解できてとてもよかったです。
3章は、k8sの役割についてや、Pod, Deployment, Service などについても図を使って分かりやすく説明されていました。 3章の最後の方では、 kubectl apply などを実行したときに k8s がどのようにして Pod を作成・実行してるのかについて説明されていました。正直この辺の知識は全然なかったので、 kubelet がPodの設定などを受け取り CRI ランタイムへ命令して実際にイメージ取得をしたりコンテナ群をPodとして作成したりしていると知りました。
4章では、コンテナランタイムについて解説されていました。 CRIランタイムやOCIランタイムについての役割や、それぞれが実際にどのように協調してコンテナが作成され動いているのかが説明されていました。また、CRIとOCIの仕様に準拠したそれぞれのランタイムについていくつか紹介などもされています。
全体的に200ページとは思えないくらいの内容の濃さで、とても勉強になりました。今までは コンテナ=Docker で、コンテナをいい感じにオーケストレーションしてくれるのが k8s みたいな認識でしたが、コンテナ技術の仕組みなどを理解することで、いろいろな用語の理解や docker run などのコマンドを叩いたときに裏で何が起きているのかなどをしっかり理解することができました!
dockerなどのコンテナ技術について、踏み込んで理解したい人にはおすすめだと思います。
あと、この本を読んだ後に fukabori.fm のコンテナランタイムのエピソードを聞くとより会話についていきやすいかもしれないです。(逆も復習できていいかもしれない)
次は 「Kubernetes 完全ガイド」を読んでみようと思います。