k8sをやってみる―Deploymentを作る―

※この記事は私の学習のメモであり、有益な知見は含まれていません。読まないでください。

k8sのクラスタを作る

チュートリアルのnginxのコンテナを立ててスケールさせて…みたいなやつは大昔に一度やった。今回はymlファイルのアレ(何て言うんでしょう?)で宣言的に管理できる状態を目指す。

チュートリアルを読むといきなりMinikubeというやつが出てくる。

https://kubernetes.io/ja/docs/tutorials/hello-minikube/

kubernetesのクラスタを作るのにkubernetes hogeとかkubectl fugaみたいなコマンドじゃなくて別の何かが必要になるのか…

https://kubernetes.io/docs/setup/

kubernetesのクラスタを作る方法を選ぶためのページがある。ローカルでの開発にはminikubeを、プロダクションにはkubeadamということにしよう。

https://minikube.sigs.k8s.io/docs/start/

minikubeを入れた。

minikube start

するとkubectlが見つかりませんと表示された。そこで

https://kubernetes.io/ja/docs/tasks/tools/install-kubectl/#curl%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6linux%E3%81%B8kubectl%E3%81%AE%E3%83%90%E3%82%A4%E3%83%8A%E3%83%AA%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B

に従ってkubectlを入れた。あとでaptで入れればよかったと後悔したが、まあ良い。minikube deleteして再度minikube startするとなんとなく問題なさそうなログが出て作成が完了した。

ymlファイルを書いてなんかアプリケーションをデプロイしたい

k8sのドキュメントの中で情報を探すのに苦労したが、どうやら

https://kubernetes.io/docs/tasks/manage-kubernetes-objects/declarative-config/
https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/

この辺りを読めばいいらしい。ymlで設定ファイルを書ける機能はkubernetesの(というかkubectlの?)標準機能としてありDeclarative Managementと呼ばれていて、kustomizeはその拡張?のようなものだろうか。

そもそもどうやるとアプリケーションをデプロイできるのかというのを忘れてしまっているので、チュートリアルの内容をDeclarative Managementの作法で進めてみる。

チュートリアルによるとまずはDeploymentを作るらしい。

https://kubernetes.io/docs/tasks/manage-kubernetes-objects/declarative-config/#how-to-create-objects

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

というファイルを作って同じディレクトリで kubectl apply -f . してみるとDeploymentが作られた。metadataとかselectorとか無くても動かんかw?と思って削ってみたらダメだった。これがホントの最小構成らしい。

次はこうして立てたコンテナに外からアクセスできるようにしたい。チュートリアルの方はしばらくデバッグ用と思われる kubectl proxy を使いながら基本的な操作の説明をするようだ。

サーバーゼニ節約&kubernetes入門

ふと毎月のサブスク費用を確認したらAWSとさくらインターネットで月額5000円くらいかかっていて、いくらなんでも辛いのでこれを圧縮する。

原因は必要以上に多くのサーバーを稼働していること。現在稼働しているのは3つ。

さくらインターネット 2GB

  • 1738円/月
  • 2017年から借りており、中途半端な技術的挑戦の残骸が最も多い
  • 金額に対するスペックが良い

積載物

AWS EC2 t2.micro

  • 1544円/月

積載物

AWS EC2 t4g.micro

  • 1076円/月
  • AWS謹製のGravitonプロセッサなので安くて高性能。ただしArm。

積載物

  • gotosocialインスタンス

移行計画

どうしたものか…

とりあえずEC2は新世代ほど高コスパの原則があり、t2.microはt4g.microに移行すべき。自分の学習を考えるとさくらはやめてEC2に揃えたい。全部t4g.microに相乗りを狙ってみようか。

そしてどうせならkubernetesに全部載せてみたい。複数のアプリケーションを相乗りさせるときのトラフィック管理をこれまではjwilder/nginx-proxyでやっていたが、もうちょっとナウいやつに移行して監視とかも統一的にやりたい。

ActivityPub用のtwilogみたいなやつを作っている(notestockがあるのは知ってるよ!)

gotosocialからnotestockが使えなくて、少し調べてもわからなかった上にnotestockがソースコードを公開しておらず(してないよね?)調査を進めるのが困難そうだったので、自分で作ってみることにした。もとより自分のデータを自分で管理することは重要だと思っていたので、そういう意味もある。

https://github.com/chao7150/activitypublog

使用技術はGo+Echo+MySQL8.0。まあ正直手慣れたRemix+Prismaでやったほうが早いとは思うんだけど、たまには違うことをやったほうがいい。自分でアプリケーションをGoで書くのはこれが初めて。普段一番書いているTypeScriptに比べると、補間、エコシステム、ドキュメント、ビルドの速さが優れている。型システムは劣っている。module/packageが難しく、挙動もベストプラクティスもよくわかっていない。この辺を読んで参考にしている

また、具体的なGoの書き方の作法はGoToSocialを真似ている。

Goで良いなと思ったのは、timeだ。たとえば

// Go
time.Now().Add(5 * time.Minute)

は間違いなく

// JavaScript
new Date(Date.now() + 5 * 1000 * 60)

よりエレガントだ。

フォーマット文字列も好きだ。大抵は%vでどうにかなるという逃げ道を残しつつ、各データ型の中でも様々な表現を可能にしている。

if err...の洪水については、エラーメッセージを真面目に考える契機になる。すなわち、エラーはerrを通して呼び出し元に順に伝播するわけだが、その過程の各関数の中で徐々に情報を付け加えることができる

if err != nil {
    return c.String(http.StatusInternalServerError, fmt.Sprintf("error GET /: %v", err))
}

具体的に何が失敗したのかはerrの中身をそのまま表示しつつ、この階層では GET / という場所でエラーが起きたという情報を付け加えている。

自分用ActivityPubインスタンスとしてGoToSocialを立てた

ツイッターがいよいよヤバそうなのでActivityPubのインスタンスを立てたくなった。まずMastodonを検討したが、リソースの要求が高いので諦めた。不慣れなRoRだしTypeScriptじゃないし構成も複雑なので個人で管理・改造するのは負担が大きいというのもある。

改めてActivityPub実装の中で軽量なものを探したところGoToSocialが良さそうだったので立てた。AWS EC2のt4g.microで現状問題なく稼働している。と言ってもまだフォローが少ないからかもしれない。ActivityPub、というか分散型SNSという仕組み上フォロー関係が増えると加速度的に通信が増大していくはず。

GoToSocial

GoToSocialはGoで書かれている。シングルバイナリで吐かれるアプリケーションとsqliteで動き、公式に提供されるdocker-compose.ymlを少し調整してリバースプロキシとしてnginxを立てるだけで動かすことができた。

現段階ではアルファリリースという位置づけであるが、大部分の基本的な機能に問題はない。今自分が把握している問題は以下の2つだ。

  • 動画が表示されない
  • notestockが利用できない
    • 利用を開始するためのnotestockのbotアカウントへのメッセージ送信がエラーで失敗する
    • mastodonには送れるのでnotestock側に何か問題があるのではと思っているが、notestockのソースコードは公開されていないので詳細不明

フロントエンドをほとんど持たず、サードパーティのクライアントから叩かれるAPIサーバーに専念している。推奨されているクライアントはpinaforeだが、pinaforeは2023年1月に開発の停止が発表された。webクライアントに限ればこれが最も盛んに開発されていたので先行きが不安だ(しかし作者自身が述べているようにpinaforeもだいぶ技術スタックが尖っていて将来性は怪しかった…)。ActivityPubデビューする人は最初にサーバーに登録してからクライアントを導入するだろうが、GoToSocialはユーザー登録用のフロントエンドも持っていないので一般に公開するにはハードルが高めかなと思う。自分はdockerコンテナに入ってCLIからアカウントを作成した。

自分でちょっとした改造を試みたときにdocker buildが大量のメモリを食ってEC2が落ちた(2GBでは足りなかった)。Dockerfileからswagger関連の処理をゴリッと消してやると直る。

賞味期限切れ

コンビニでおにぎりを買おうとしたら、レジで「申し訳ないがこれは賞味期限が切れているので売れない」と言われた。珍しい体験だった。大昔スーパーマーケットでバイトしていたときに賞味期限切れの食品を捨てる仕事をしていたのを思い出した。僕が働き始める直前にバイトによる廃棄食品の持ち帰りが発覚し数人が辞めさせられたらしい。

これは興味深い問題だと思う。一般的なMOTTAINAIの精神に基づけば廃棄食品を持ち帰って食べるのは良いことだ。しかしそれが許されなかったのは「商品を商品として見られなくなる」からと聞いた。つまり「これが売れずに廃棄になれば自分のものになる」と思ってしまうと、その商品が売れないように隠したりしかねないということだ。なるほど、筋が通っている。店員としての行動を徹底させるために正しくインセンティブを設計している。

最近考えていること@202206

読書

『ザ・ゴール』

スクラムでベロシティを安定化するにはどうしたらよいかで紹介されていたので8割方読んだ。8割方というのは、途中生産管理の話から思考法っぽい話に移ったところで興味を失って止まっているからだ。

この本では問題を抱えた工場の工場長が、学生時代の恩師(作者がモデルのようだ)から断片的なヒントを得ながら、それまでとは全く違う思想の生産管理を取り入れて成功するというストーリーが物語仕立てで描かれる(無職やめ太郎氏のようなものだ)。端的に言えば全員を休みなく働かせるのが最高効率というわけではなく、むしろボトルネックに着目しろという話だったように思う。「ように思う」というのは、教科書ではなく物語だから論理的な筋立てはあまりよくわかっていないからだ。

興味深い読み物ではあったが、単純にソフトウェアエンジニアリングに応用できるかは疑問だ。ソフトウェアエンジニアリングには固定化した生産ラインはないし、在庫コストもないからだ。しかしフロー効率とリソース効率とか、従属事象・統計的変動の概念はなんとなく掴めたので、もうちょっとかっちりした制約理論の教科書を読んでみたいと思った。

『プロを目指す人のためのTypeScript入門』

言わずと知れた有名人uhyo氏の著作。3割くらい読んだ。

僕は既にプロなので9割くらいはもう知ってる知識だ。しかし端々に挟まれる詳細な仕様の知識とか歴史的経緯、さらにuhyo氏の思想などが勉強になる。知っていると思い込んでいるものをもう一度学び直すという意味で価値のある読書だなと思う。思うのだが、やっぱり大体は知ってる話なので退屈になってしまってなかなか読み進められない。

『HTML解体新書』

仕様が広大ゆえに使いこなすのは難しいHTMLの本。全然読めてない。

『データ構造とアルゴリズム(五十嵐健夫)』

連結リストやスタック、木、ハッシュなどから始まり、ソートやグラフや文字列検索なども扱うらしい。これも3割くらい。

C++で実装しながら読み進めている。2-3木は辛かった。コアになるアルゴリズムはシンプルなのだが場合分けがドエラい数になる。平均計算量に関してはある程度計算で求める必要があるが、理解できないほどではなかった(自分で発想しろと言われても無理だが…)。

労働

あまり多くは語れないが、ここ半年くらいはずっと悩んでいる。4年目にもなるとこれまで通りの仕事をしていても学びがなくなってくる。だから更にスコープを広げて何かチャレンジしたいなと思っているけど、なかなかうまくできない。仕事に学びを求めるのが間違いなのかもしれない。

だからまあ、最近本をたくさん買ってみたり個人開発頑張ってみたりというのは、何か突破口が見つからないかなあということですね。

個人開発

最近はもっぱら https://anime.chao.tokyo の開発を進めている。Animetickからしょぼいカレンダー(手入力のアニメ放送予定API)への依存を切って、大量視聴を管理するための可視化などを足してみたいなという狙い。

使用技術はRemix+PrismaでEC2に雑に(DBもEC2で動いてるw)立てている。バックエンドの処理をパイプラインに見立ててfp-tsで書いているのが自分的こだわり。

飽きたら次にやってみたいのはweb componentsとかかなあ。Reactを捨てて生のHTMLと最低限のJSで何ができるのかというところを勉強してみたい。あるいはなんかOSSとかも。GoやRustも触っておきたい。学ぶべきことはいくらでもある。その気になればTypeScript一本でなんでも書けてしまうので、意図的にコンフォートゾーンの外に出るようにはしたい。

料理

以前から美味しいものを食べるなら外食で、自炊は楽で身体に悪くないものというポリシーでやっている。最近は以下のセットで固まっている。

  • ご飯
  • 味噌汁
  • 自作サラダチキン
  • ブロッコリーの惣菜(冷凍食品)
  • スーパーで買ってきたサラダ(ごぼう・コールスロー・切り干し大根のローテーション)
  • 納豆
  • ヨーグルト

サラダチキンを切らしたときは適当に惣菜買ってきたり。ここから50年くらいずっと同じものを食べ続ける可能性すらあるので、自炊は変に偏らないようには気をつけたい(何食っても塩分過多で怒るのであすけんは嫌いです)。

健康

3月末に右足首を捻挫して結構長く歩行で痛んだり疲れやすかったりした。ようやく治りつつある。

アニメ視聴

まあ、そこそこ見てます。

Dota2

ちょっとやる気なくなってます。4月頃は調子よくて3880まで上がったけどしばらくやらなくなって今3430。

自分の持ちキャラのメタ変動の話をすると、Dazzleの7.31の変化が気に入らない。タイミングの概念を捨てて単にCD上がるたびにスキル撃つのを推奨するようなメカニクスになっていて、こんなの人間がプレイする必要ないじゃんと思ってしまう。

ということでプロの間で大流行していたPugnaばかり使っていた。癖はあるもののスキルセットが強力。サポートでも積極的にタワーを折れる1番、SavingにもDisableにもなる2番、設置するだけで大きなダメージを叩き出せるNether Ward、そしてダメージにも大回復にもなるUlt。Shardは弱いと思うけど…(相手にPLかNagaがいたら買うかも)。

ただPugnaも7.31dでかなりお仕置きを受けてしまったのでやめる。またDazzleに戻ることも検討しているが、単に数字上のbuffがあったというだけでメカニクスは改善していないので悩ましい。あるいはEnchantressもいいかもしれない。これもプロで猛威を奮っていたので7.31cでEnchantにレベルキャップがついてしまったが(なかったほうがおかしいだろ!)、それでもタンクやラットができるサポートというのは貴重だ。

Stunがないサポートは嫌がられるのでHoodwinkを使っていた時期もあったが肌に合わず全然勝てなかったのでやめてしまった。

二分探索木の平均計算量(WIP)

二分探索木の形は、要素の数が同じでも、入れる順番によって変わる。
探索に必要な比較の回数も、木の形によって変化する。

1,2,3

  • 要素1を探すときの比較回数は1
  • 要素2を探すときの比較回数は2
  • 要素3を探すときの比較回数は3
  • 平均比較回数は(1+2+3)/3=2

2,1,3

  • 要素1を探すときの比較回数は2
  • 要素2を探すときの比較回数は1
  • 要素3を探すときの比較回数は2
  • 平均比較回数は(2+1+2)/3=1.7

要素n個に対して作れる木の形がxパターンあるとする。
それぞれの木の形T1~Txに対して平均比較回数が求まる。
それらの平均比較回数の平均をT(n)とする。

T(n)をnの関数として表すことはまだできない。
なぜなら木の形から平均比較回数を算出する方法が曖昧だから。
nからxを求める方法がわからないし、木の形(どうやって数学的に表現する!?)から平均比較回数を算出する一般的な方法もまだない。

問題を分割する…

では木の形から平均比較回数を計算する方法を考える。
上でやったように、ひとつひとつの要素に対して何回の比較で到達できるかを求め、その平均を出せばよい。
ここで、木の形を抽象化する。

あらゆる二分探索木は、親と左部分木と右部分木に抽象化できる。

木の形も抽象化する。
つまり、n個の要素からなる二分探索木を、左部分木の要素数(0~n-1)によってn通りに分類する。
部分木の中の形はわからないんだけど、今はわからなくていい。

左の部分木の要素数をiとする。
i=1のとき、この部分木は、親要素があり、左部分木には1つだけ要素があり、右部分木には形はわからないけどn-2個の要素が入っている。そういう木の形をしている。
実はそれだけわかれば、この木の平均比較回数はT(n)を用いて表せる。
繰り返すが、T(n)がどういう関数なのかはまだわかってない。でもT(n)を用いて表す方法はあるということだ。
それはこうなる
(略)

n個の要素を適当な順番で木に挿入したとき、木がどんな形になるかはわからない。
つまりiがどんな値になるかはわからない。
でもここでiは0からn-1まで同じ確率で現れると考える(本当???)と、平均値は求められる。
この平均値というのは、つまりn個の要素からなる二分探索木の平均比較回数だ。つまりT(n)だ。
T(n)をT(n)で表す式ができた。