年の瀬なので書きます。
なんか普段のお仕事の内容をあまり書けないのもあって、技術的なアウトプットをあまりできてないなーという気がするのでそれを取り返す意味でもまとめておきます。
意図的にぼかした書き方になっているような箇所は察してください。
Kubernetes
勉強
必要に迫られたので何も知らないところから一から勉強した。
まずは全体像を知りたいなと思ったので体系的にまとまっていそうな本を探した。
評判がよさそうだった↑の本をポチって1~2週間かけて読み込んだ。
何も知らない状態からいきなり理解するのは難しいので、最初はとにかく「こういう概念がある」というのを覚えるために広く浅く読んだ。
最初の時点では細かい点まで覚える必要はなくて、一通り読み終わった後に
- ○○をしたい
- 確かそういう概念があったな
- 確か△△みたいな名前だった
- 本の索引から調べて該当する箇所を読み直したりググったりする
というサイクルを繰り返すことでスッと理解が進んだ気がする。
↑の本はそうした使い方にとてもよくマッチしていて、一からKubernetesを勉強したい人に十分おススメできる。
自宅サーバのKubernetesクラスタ化
とは言っても流石に本を読んだりチュートリアルを試したりしているだけではイメージしにくいので、実際に手を動かして触ってみたくなる。
そこでちょうど趣味の自宅サーバで動かしていたMastodonやらSlackLineBridgeやらをKubernetesで動かしてみることにした。
自宅サーバでKubernetesクラスタを作るとなるとUbuntuあたりにkubeadmをインストールしてって感じで構成するのが一般的な気がするものの、どうも面倒くさい。
せっかく趣味で弄るのでもっといい感じで楽しそうなものは無いかなと探したところK3sというのを見つけた。
Kubernetes準拠の軽量なディストリビューションとのことでとても面白そう。
さらに調べるとK3sを動かすためのLinuxディストリビューションであるK3osというのを見つけた。
昔からこういう機能特化した軽量Linuxディストリビューションみたいなのは大好きなので、一目見た瞬間にコレにしようと決めた。
もともと上に書いたMastodonやらSlackLineBridgeやらといったモノはBargeというDockerコンテナを動かすための軽量Linuxディストリビューションでdocker-composeを使って動かしていた。
ただ、最近Bargeのメンテが途絶えてしまっているので何とかしたいなーと思っていた。
ちょうどここからK3osに置き換える形でKubernetesを導入できたら良いなと思い作業を始めた。
おうちKubernetesクラスタならではの課題と構成
せっかくKubernetesクラスタを組むのにノードが1台だけというのは寂しいので、録画サーバとして稼働しているマシンも加えて2台構成にすることにした。
自宅サーバだと後述するようなストレージを提供するサーバが単一障害点になるので複数台でHA構成を組む意味はあまりないんだけど、勉強という意味ではtaintの挙動を確かめたりとか色々できることが増えるのでおススメ。
K3osの導入とセットアップはすごく簡単ですんなりできたものの、自宅サーバならではの悩みポイントとして
- グローバルIPアドレスが1つしかない
- クラウドサービスみたいに「グローバルIPアドレスが当たったALBをくっ付けておしまい!」にならない
- でもIngressあたりを定義したら自動でいい感じに構成できてほしい
- ノードをまたいだストレージの永続化を何とかする必要がある
- クラウドサービスみたいに「EBSをくっ付けておしまい!」にならない
- 当然それでもPVCでDynamic Provisioningをしたい!
という点がある。
1つ目はファイアウォールで内向きHTTP/HTTPSトラフィックをNAPTして2台のノード宛てにロードバランシングするように構成した。
L4ではあるものの正常性チェックもかけているので、物理的に片ノードがダウンした場合でもトラフィック自体は問題なく正常なノードに届くような構成になっている(はず)である。
LAN内に対しては、今までは単純にコンテナが稼働しているマシンに繋がれば良かったので内向きDNSで向けていたものの、外向きと同様にロードバランシングさせたいのでヘアピンNATを構成した。結果的に今まで外向きと内向きで二重管理していたDNSレコードが一つで済むようになったので管理が楽になった。
Kubernetes側にはTraefikをDaemonSetとして導入*1することで、NodePort的な感じでファイアウォールからのトラフィックを受け取るようにした。
ここにTraefik Kubernetes Ingress providerやらcert-managerやらも導入することでIngressを定義するだけでいい感じにHTTPSなサービスを公開できるようになった。
現状DNSレコードの追加だけは手動なのでここも自動化できたらいいなーと思ってる。誰かPorkbunで使えるいい感じの方法を知ってたら教えてください。APIはあるので無ければ自分で作ればいいんだろうけども。
結果的にこの構成はとても良くできた気がするので気に入っている。
2つ目のノードをまたいだストレージの永続化は、まずは普通にNFSサーバを立ててnfs-subdir-external-provisionerを試してみた。
普通に構成したら普通に動作して、「ストレージ問題はこれで解決!」と思ったのも束の間で、試しにPostgreSQLのDBをNFS経由で永続化して動かしてみたところ、まぁ驚くほどパフォーマンスが出なかった。
それはそうという感じなので、iSCSIによる永続化も導入することにした。
iSCSIに関しては、open-iscsi/targetdを含んだiSCSIターゲットを立ててKubernetes側にはiSCSI-targetd provisionerを導入することで、PVCでDynamic Provisioning可能なiSCSIストレージを構成することができた。
そのままPostgreSQLで試したところ、NFSと違って今度は良い感じにパフォーマンスが出るようになった。
iSCSI周りの構築手順は
をそのままなぞっただけなので、試してみたい人は↑の記事を見ながらトライしよう!
ちなみにiSCSI-targetd provisionerやそれを含むexternal-storageリポジトリはEOLになってアーカイブされてしまっており、Kubernetes v1.20以降とは互換性が無く動作しなくなってしまっている。
そこでKubernetes v1.20でも動くようにパッチを当てたので必要な方は使ってください。
↑のやつは問題が起きている kubernetes/client-go
のコードをピンポイントで修正するといった感じで対応しているのに対して、 @sukukyon がもっと根本的な対応を行ったものもあるので動かない場合はそちらを試してみるのもおすすめです。
NFSとiSCSIの使い分けは、NFSでもスループット自体は出るし内容の管理もしやすいので画像データや動画データみたいなサイズが大きめでファイル内への細かいアクセスが少ないものが置かれる場所はNFSにして、PostgreSQLやElasticsearchのファイルみたいな細かいアクセスが多くてパフォーマンスが求められるような箇所はiSCSIを使うようにした。
こうしていい感じに使えるおうちKuberenetesクラスタを構築することができた。
また、こうして実際に手を動かすことでKubernetes自体やネットワーク周り、ストレージ周りの理解がとても進んだ気がする。
Mastodonの死活監視のログを見るにダウンタイムが171時間なので、1週間ぐらいかけて↑の課題にあーだこーだしながら対応していたようである。
GO言語
こちらも必要に迫られたので一から勉強した。
GO言語を使いこなしているかと言われると大分怪しいが、少なくとも普通に読み書きできるようにはなった気がする。
言語仕様がシンプルなのでCライクな言語を書いたことがあればすんなりと使えるようになる気がする。
- goroutineがすごくいい感じ
- でも無名関数と組み合わせたときのキャプチャの挙動が初見殺し
- cgoがあるのでネイティブライブラリとの連携もバッチリ
- ソースコードにアクセスできないパッケージをimportすると途端に補完周りが死ぬのでつらい
- メモリ管理が楽でいいけどヘビーな使い方をした時のオーバヘッドやらGCの負荷やらがどうなるのか少し気になる
DynamoDB
同じく必要に迫られたので一から勉強した。
- ただのKVSかと思ったら、キーやらインデックスやらで色々な概念があってとっつきにくかった気がする
- まともなトランザクションも制約もなくてつらい
- 単に自分がNoSQLに慣れてないだけな気もするけど、大規模なものはやっぱりRDBMSで作りたいなーって気持ちになった
- AWS SDK for .NETのクライアントでスレッドプールが枯渇するのを早く直してほしい
- DynamoDb .NET threadpool starvation · Issue #1476 · aws/aws-sdk-net · GitHub
- 通常動作は問題なかったのに負荷テストでいっぱいリクエストを投げた途端に動かなくなって1日溶けた
- 集計処理でいっぱいクエリを投げる場合とかも同じ問題に当たりやすい
ThreadPool.SetMinThreads
を盛ればまぁ使えるようにはなるけどなんだかなぁという感じ
Agones
知ったきっかけはOOPartsがらみだったが、ちょうど別件で必要な要件とマッチしていたので使ってみた。
ちなみにOOPartsでの導入については id:yu_suke1994 が詳しく発表しています。
- 「Kubernetesでステートフルなゲームサーバの管理どうすんねん」と思っていたところへのアンサーな感じがして楽しかった
- Kubernetesの拡張性の高さを実感できた
- 「これができるなら何でもできるな」という感じがした
- Agones自体の機能では一部不足しているなと感じる点もあった
- そのまま使うと1Pod内で複数ルームを動かすのに対応してない*2とか
- 待機中のPodにも
safe-to-evict=false
が付くのでスケールインするときにノードが減りきらないで残ってしまったりするとか
その他
最近は自分でプロトコルを作ってUDPでめっちゃ送り合ったりみたいなことをしてます。楽しい。
買ってよかったもの
プロジェクターとスクリーン
在宅勤務で可処分時間が増えたので、思い切って中華プロジェクターやら100インチスクリーンやらChromecastやらを買った。
3万円程度の出費で最高のおうちシアター環境ができたのでとても満足。
スマホゲーム
ブルーアーカイブ
サクサク遊べてとても楽しい。
スクスト以来の長く続いているスマホゲームな気がする。
総力戦トロフィーはこんな感じ
2022年の抱負
とりあえずProtocol Buffersを使いこなせるようになりたいのと、Rustに興味があるので書けるようになりたいと思う。
Rustは何かのエミュレータでも作ってみるのがいいのかな。
他にも引き続きいろいろな新しい技術を学んで身につけていけたらいいなーと思う。
それでは、皆様良いお年を!