Raspberry Pi 4 Model B でKubernetes cluster構築した
完成形です。いぇい。 材料 材料 個数 Raspberry Pi 4 Model B 8GB 4 PoE HAT(E) 4 PoE対応 スイッチングハブ 1 無線ルーター 1 MicroSD 128GB 4 LAN (0.15m) 4 LAN (0.3m) 1 ケース 1 追加スペーサー 50個入り 組み立ての感想 見た目をスッキリさせたかったので、ラズパイの電源は PoE HATによりハブからLANで取ってます。 ただ、これだとLANを引っこ抜いてノードを切り離すことが出来ないので失敗したかなって思ってます。 LAN引っこ抜いてノードネットワーク障害ごっこしたいのに、電源も落ちちゃう。 cf. PoE (Power Over Ethernet)。 また、ケースでもPoE HATで失敗しました。 PoE HATを付けると高さが高くなります。(値段も) 買ったケースのファンとPoE HATのIsolation Transformerがぶつかります。 なので、ケース付属スペーサーだけでは足りないのでスペーサーを買い足しました。 (そして、そのスペーサーが付属スペーサーのネジ径と合わない…。付属のはM2だったっぽい…。) 付属スペーサーは高さ20mm。このケース(+ファン) + PoE HAT の場合、30mmでぴったり合います。 Amazonで激安のPoE HATはさらに高くなるので、ご注意を。 k8s cluster 構築 0. 別PCでの準備 無線ルーターを中継機として既存LANに参加させます。 Raspberry Pi Imagerを使ってmicroSDカード4枚にRaspberry Pi OS(64-bit) Liteを書き込みます。 Imagerでホスト名やssh有効化、user/passwd設定等出来るのでここでやっても可。 中継機が192....
hashicorp-forge/hermes
hashicorp-forge/hermes 触ってみた 2023/02/01 の朝、面白いツイートが目に飛び込みました。 Excited to see the HashiCorp document management system become open source! Built on top of Google Workspaces, this has really helped our writing system scale better with the company instead of pure Drive + Groups. https://t.co/7SUrogij0k pic.twitter.com/v8lkbgjL08 — Mitchell Hashimoto (@mitchellh) January 31, 2023 ここ半年、いや 1 年位、いやもっとだったかも。設計工程の進め方にずっと不満がありました。 クラウドストレージに散らばっている 見たか見てないのかわからない、コメントへの反応 バージョン管理されていない そんな不満、いや設計構成に一石投じているように感じました。まるで初めて Packer や golps(現 gopls) に出会ったような時の衝撃が走りました。 私はブランクがあるものの、新卒から現在まで IT 業界にいて、設計書を印刷してマーカーを引いたり、ソースコード管理の自前ソフトを使用したライブラリ管理(通称リブ管)をしていた頃もあります。 それに比べたら、今では信じられないくらい進化しています。CVS や CSV ホスティングサービス、Google Sheet には編集履歴や版を設定出来たり。 そんな私にはまさに夢のツールになり得るプロダクトに見えました。ということで、早速動かしました。...
Neovim + DAP + Go
TL;DR DAP(Debug Adapter Protocol)の力を借りれば、Neovim上でも視覚的にGoのデバッグが出来ました。 ここでは下記については話しません。 DAPの詳細 packer.nvimでのインストール方法 vscode-goのdebugAdapter.jsの使用方法 Neovimでデバッグするモチベーション v0.2.2から色々変わったNeovimを久々に触ってみようかと思いinit.luaへ以降して遊んでいました。 起動が早いだけでなく、LSP系の動作もサクサク動いてここ2ヶ月程快適に過ごしています。 ただ、VSCodeでのデバッグ機能がとても便利なため、デバッガ使用時のみこの快適な環境を離れていました。 どうにかNeovim上で完結させられないか…。 DAP DAPの説明はリンク先や他HPをご参照ください。 イメージを持ってもらうためLSPを引き合いに出すと、LSPがテキスト編集時に定義や変更内容や補完候補等を返すのに対して、DAPはデバッガとやりとりしてデバッグ情報を返す位のイメージを持ってもらえれば大丈夫だと思います。 Neovim + DAP + Go 使うプラグインは下記になります。 mfussenegger/nvim-dap : NeovimのDAPクライアント。VSCodeのlaunch.jsonも使用可 rcarriga/nvim-dap-ui : nvim-dapを視覚的に操作しやすいUI leoluz/nvim-dap-go : DAPのGo用設定(delve dap起動) nvim-treesitter/nvim-treesitter nvim-dap-goでテストをデバッグする際、近くのテストを見つけるのに必要 packer.nvimの設定 VSCodeのlaunch.jsonを使用しない場合、require('dap.ext.vscode').load_launchjs()は不要です。 launch.jsonを読み込めた場合、デバッグ方法の選択時にlaunch.jsonの内容が追加表示されて選択可能になります。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 -- dap plugin installation with packer.nvim ... -- dap use { "rcarriga/nvim-dap-ui", requires = { "mfussenegger/nvim-dap", "leoluz/nvim-dap-go", "nvim-treesitter/nvim-treesitter" }, config = function () vim....
gin + gorm v2でのセッションやトランザクション
TL;DR ginでの各リクエストを1セッションで管理しつつ、トランザクションも管理したい。 ginのmiddlewareで、gin.Contextにgorm.WithContextを用いてGormのセッションを持たせる。 ginの各HandlerFuncの中では、gin.Context内のGormセッションからDBへアクセスする。 モチベーション Gormはv2になり色々と変わった。 Gorm 2.0 Release Note 色々な記事が書かれているがTransactoinに関してあまり書かれていない。 下記疑問を払拭して正しい使い方を自分なりに確かめたかったので試した。 なんとなく動くがこれで正しいのか? ドキュメントを読んでいてSkipDefaultTransaction:trueだと30%もパフォーマンスが上がるというがその設定はtrueにしていいいのか? っていうか、DefaultTransactionって何?ロールバックの単位とかどうやって指定するの? 確認&検証 検証時に作成したソースはgithub.com/lunarxlark/gorm2-tx Context Gorm 2.0 #Context GormはContextサポートを提供し、それを使いたかったらWithContext使ってくれ。 また、Sessionには単セッションモードと継続セッションモードがある。 普通は、継続セッションモードを使って、複数オペレーションをまとめるよ。 …GormのSessionってどんなことできるの? Session Gorm 2.0 #Session Gormは`Session`メソッドをを通して、新しいセッションを提供するよ。 新しいセッションを作る場合、設定がたくさんあるよ。DryRunやLoggerとかね。 …新しいセッションを一々作るのは望んでない。 Contextサポートしてくれるってことなのでgin.Contextへ埋め込む時にセッションを作成してそれを使い回したい。 gorm.WithContextのreturnはdb.Sessionとなっている(下記はgormのソースから抜粋)ので、gin.Contextへ埋め込むだけで新たにセッションを作る必要はない。 1 2 3 4 // WithContext change current instance db's context to ctx func (db *DB) WithContext(ctx context.Context) *DB { return db.Session(&Session{Context: ctx}) } ここまでで下記みたいな感じになる。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 func main() { //....
ISUCON11予選に参加して惨敗した
結果 ISUCON 経験者の 2 名(@Aki_Mineo, @annkara)に誘われてチーム:コバミネとして参加しました。 私は主にインフラ担当でしたが、業務でバックエンドを Go で書いているためインフラの作業を終え次第、合流する作戦でした。 結果は 151 位 29614 点 でした。 悔しい。あそこで気付いていれば…みたいなポイントがクリティカルでした。 反省点 直すところはたくさんあったと思いますが、直すと決断するまでに迷いがありました。 時間内でのアプリケーションへの理解が足りなかった。 ユーザストーリの理解と加点の仕組みが結びつかなかった。 アプリケーションのどこを直したらいいか。 どう直したら加点されるのか。 非効率なポイントがあっても、他の要因ですぐに直せなそうだった。 見つけた時には時間が足りなかった。 修正して試す環境が本番環境のみだった。 大幅な修正をして、他メンバーとコンフリクトが起きるのが怖かった。 ざっくりタイムライン 前準備 private な作業リポジトリ(メンバーを招待) Discord との webhook deploy.sh 各種 tool のインストールスクリプト 10:00 競技スタート。 @annkaraが AWS アカウントを準備してくれたので CFn でスタック作成。 CFn でのインフラ作成完了。 ssh config 配布。全員が接続確認完了。 初回ベンチ回す。ベンチ:2981点 ソースや設定を GitHub へ。 conditionLimit : 20 -> 40。ベンチ:1704点(すぐ Revert) alp, netdata, pt-query-digest をインストール。 11:00 AP の負荷があまりにも高く、CPU100%に張り付いていたので DB を No.3 へ逃がす。ベンチ:8267点 POST /api/condition を bulk insert へ。ベンチ:9452点 nginx のログ出力を ltsv へ。 mariaDB のスロークエリを出力。 DB table isu_conditionのjia_isu_uuidへ INDEX 追加。ベンチ:22746点 DB table isuのjia_isu_uuidへ INDEX 追加。ベンチ:22492点 12:00...
EC2へssh with GitHubに登録している公開鍵
isuconの練習時にGitHubに登録している公開鍵でEC2へssh出来るように、userdataを設定したかった。 sedでのエスケープの仕方でハマったのでメモ。 #!/bin/bash su isucon -c 'mkdir -p /home/isucon/.ssh && touch /home/isucon/.ssh/authorized_keys' su isucon -c "curl https://api.github.com/users/{{github_user_id}}/keys | grep \"key\" | sed -e 's/ \"key\": \"//g' -e 's/\"//g' >> /home/isucon/.ssh/authorized_keys"
2021年版 vim + goplsの設定
goplsが出てから, vimでも定義ジャンプやシンボル検索、ドキュメント参照等が行えるようになった。 たまにVSCodeを触りvimでの作業を改善できないか考える中で、自身の設定が古いことに気付いた。また、ググってもなかなか出てこなかったのでメモとして記述する。 cf. GitHub dotfiles いきなりだが、vimrcとvim-lsp-settings/settings.jsonを抜粋して貼り付ける。 以前、GoではLspCodeAction, LspCodeLens等をサポートしていなかったが、今では使えるようになっている。 キーマップに設定している関数は全てGoで使用出来る。 ただし、カーソルがどこにいても実行出来るわけではないので注意が必要。 LspCodeActionはカーソルの位置によって実行内容が変わるのでそこも注意。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 ... Plug 'prabirshrestha/vim-lsp' Plug 'mattn/vim-lsp-settings' Plug 'prabirshrestha/asyncomplete-lsp.vim' Plug 'mattn/vim-gomod' ... " ------------------------------------------------------------------------------ " vim-lsp " ------------------------------------------------------------------------------ function! s:on_lsp_buffer_enabled() abort setlocal omnifunc=lsp#complete setlocal signcolumn=yes if exists('+tagfunc') | setlocal tagfunc=lsp#tagfunc | endif nmap <buffer> <leader>ac <plug>(lsp-code-action) nmap <buffer> <leader>cl <plug>(lsp-code-lens) nmap <buffer> <leader>df <plug>(lsp-definition) nmap <buffer> <leader>dd <plug>(lsp-document-diagnostics) nmap <buffer> <leader>im <plug>(lsp-implementation) nmap <buffer> <leader>pdf <plug>(lsp-peek-definition) nmap <buffer> <leader>sm <plug>(lsp-document-symbol-search) nmap <buffer> <leader>Sm <plug>(lsp-workspace-symbol-search) nmap <buffer> <leader>rf <plug>(lsp-references) nmap <buffer> <leader>td <plug>(lsp-type-definition) nmap <buffer> <leader>rn <plug>(lsp-rename) nmap <buffer> <leader>en <plug>(lsp-next-error) nmap <buffer> <leader>ep <plug>(lsp-previous-error) nmap <buffer> <leader>ho <plug>(lsp-hover) let g:lsp_format_sync_timeout = 500 autocmd!...
load test with dynamic payload by tsenart/vegeta
負荷テストツールvegetaのコマンドでの使い方ぐはググるとたくさん出てくるが、ライブラリとして仕様している記事が少なく手こずったのでメモ代わりに記事にする。 やりたいこと リクエスト毎にRequestの内容を動的に変えて、負荷をかけたかった。 Headerに持つタイムスタンプがリクエスト時のタイムスタンプになるように。 userIdはuniqueになるように。(同じユーザだと重複リクエストを弾く処理があったため。) 具体的には下記のような感じでリクエストを送りたい。 1 2 3 4 5 {"header": {"timestamp":"1234"}, "body": {"userId": "lunar-1"}} {"header": {"timestamp":"1234"}, "body": {"userId": "lunar-2"}} {"header": {"timestamp":"1235"}, "body": {"userId": "lunar-3"}} ... {"header": {"timestamp":"1240"}, "body": {"userId": "lunar-n"}} vegeta.Targeterは func(*vegeta.Target) error である。 また、vegeta.Attackは、vegeta.Targeterをgoroutineで都度呼び出して、Targeter内からTargetに基づきリクエストしていることから、都度Targetが変わるようなTargeterを返す関数を作成し、それをAttack時に呼び出せば良さそう。 ってことが、 [QUESTION] Sending requests with dynamic body #330に書いてあって何度も行き来した結果やっと理解できた…。 上記を拝借して以下のようにすることで目的を達成できた。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 type yourRequestBody struct { UserID string } targeter := func(id uint64) vegeta....
2020年 ふりかえり
2020年の振り返りと来年にやりたいことをつらつらと書こうと思う。 きっかけは、1on1をしてくれたEMからのアドバイスだ。 年末になると、1年を振り返るが過小評価しがち 何回かに分けてやると良い 謙遜せずやったことはやったと自分に言う そんな趣旨のアドバイスを貰った。実際、いつも自分でやる振り返りでは、今年も結局…みたいな評価になってしまっている。 仕事を頑張っていないわけではない。今年は自分でも頑張ったと思う。そんな、いつもは謙虚な(?)な自分に今年は前向きな評価をしてあげよう。 そう思った。 Dependency Injectionの実装方法を理解した トランザクションマネージャ(DB参照先を捕捉し、rollbackを埋め込んであるmethodを持つinterface)を依存性に注入することでrollback記載不要に。 トップダウンで記述するDIでは、DB参照先もあらかじめ記述しておけるが、トランザクション範囲については自身で記載しなければ出来ないという結論に。 ポインタレシーバにはポインタが、値レシーバには値がコピーされる。 メソッドをinterfaceに指定する際、レシーバにコピーされる値への変更を保持したいか等でポインタ/値レシーバどちらにするかの判断基準になる。 WebFramework Echoのmiddlewareの作り方。 Skipperによるecho.Contextの使い回し方。(structメンバーに、echo.Contextを引数に持つ関数を持たせる) Echoのデフォルトログでは、ヘッダーx-request-idに指定した値がrequest idに出る。 Echoのmiddlewareに対する理解が深まった。(雑) CloudFrontの各項目に対する理解が深まり、通信障害時にどのように調べて、どのメトリクスを見れば良いかがある程度わかるようになった。 CloudFrontのrequest idをoriginのEchoへ出力したい場合、x-amz-cf-idをEchoロガーで出力すればよい。 L@Eの使い方と開発/リリース時の注意点について教訓を得た。 L@Eへの反映には時間がかかるので、テストの仕方を工夫しなければいけない。 L@Eに適用するLambdaのversionはLATESTを指定出来ないので、リリース時にはLambdaのversionを数値指定しなければいけない。 L@Eを修正するにあたり、Node.js v10.xを少し勉強した。(動的型付け言語は好きになれない。結局、undefinedと向き合わなければならず、動的型付けのメリットが感じられなかった。) その点、TypeScriptはちょっと触った感じ楽しかった。トランスパイルという言葉を知った。(言語のversionがどんどん上がっていくECMAScriptに対して、トランスパイルが追従していけるのかちょっと不安を感じた。) AWS StepFunctionは、Lambdaをjsonというインタフェースで繋げていて、Lambdaのフローをjsonで定義しているだけなんだと理解した。 AWS Lambdaをローカルである程度動作確認出来るようにDEBUGフラグを付けた。 Go言語の開発環境が自分の中で固まってきた。(Vimで必要なPluginがある程度固定されてきた) Alfredにより、unixtimestamp変換とbase64エンコード/デコードが素早く行えるようになった。 CI/CD時にdocker pull rate limitによるエラーを、DockerHubへのログインで解消させた。 コネクションプールの生存時間が短すぎることを見つけ、DBstatsからコネクションスパイクに対してプール生存時間を伸ばすことでDBへの負荷とコネクション接続時のlatencyを短くした。
Custome Logger using LoggerWithConfig in Echo
WebFramework EchoのLoggerを弄っていて気付いた点があったのでメモ。 sample code 箇条書き responseログにHeader X-Any-Headerを出力したい場合、ログフォーマットに"any_header":${header:x-any-header}を指定すればいいよ responseログにQueryParamerter ?anyparam=xxxを出力したい場合、ログフォーマットに"any_query":${query:anyparam}を指定すればいいよ デフォルトで出力されるカラム’id’はHeader X-Request-Id を指定すると出力されるよ Skipperを設定することで、path毎にログ出力する/しない等を設定出来るよ 1, 2, 3はEchoのそういう機能だってことで特にありません。 4は結構便利だなと思いました。以下のサンプルコードでは、/healthcheckに来た場合とCI/CD等での自動テスト時にはresponseログを出力しないようにする設定例です。 sample 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 // Middleware e....