ayumin.log

読みにくかったら脳内sedで整形してね

gqlgenがinitした瞬間エラーを出していた話

Graph QL の素振りがしたかった

SecHack365 に今年参加することが決まったため、色々技術選定をしている。

まだ決まっていないことも多いが、とりあえずフロント-バック間の通信はGraphQL使ってみるかなと思い、

github.com

を試していた。スキーマドリブンな設計してみたかった。

gqlgen init したらなぜかエラーが出る

$ gqlgen init
validation failed: packages.Load: /home/shoumoji/graphql-tutorial/graph/prelude.resolvers.go:19:44: __DirectiveResolver not exported by package generated

🤔🤔🤔

tutorial 読んだけどそんなのなかったよなぁ…? と思いつつ、prelude.resolver.go を眺めてみる。

何がおかしいんだろう…と小一時間悩んだ末、ふとサンプルリポジトリを見てみた。

github.com

そんなファイルないらしい。この辺でなんとなくおかしさに気づいたので、issues を辿ってみる。

github.com

ということで、gqlgenの依存ライブラリに互換性の問題があったらしく、そのままでは無理そうだった。

解決策

先ほどの issue にもあるが、バージョンを上げる。とりあえずHEADまで上げれば解決した。

go install github.com/99designs/gqlgen@HEAD

あとは go mod tidy したり init し直せば OK。

Goで圧縮しながら非同期的にS3にデータ送信する

Goの非同期IO

Goはgoroutineによって非同期処理ができるが、ちゃんと使ったことがなかったので色々やりながら機能を把握した。

とりあえず今回は直接 channel を使わず、シンプルなIOのみの処理をする。

目的はtar.gzに固めながらのAWS S3へのデータ送信だったが、ライブラリを使ってAWSに直接送信する部分以外は、全部標準ライブラリでこなせる。

io.Pipeについて

readPipe, writePipe := io.Pipe()

とすることで、パイプを作れる。

書き込みたいデータのストリームをwritePipeに流し、readPipeでそのストリームを取り出していく。

注意点としてはwritePipeに書き込み終わったらwritePipe.Close()すること。忘れると一生処理が終わらない。この辺りはLinuxのreadシステムコールの挙動に近い。

あとはそこまで難しいことはなく、書き込みをgoroutineを使って非同期的に行えば、直感的に動くはず。

S3への送信は

&s3manager.UploadInput{
    Bucket: aws.String(bucketName),
    Key:    aws.String(keyName),
    Body:   readPipe,
})

のようにパイプを繋げるだけ。とてもお手軽。

tar.gzに固める

Goはtarもgzipも標準ライブラリにあるので、Goだけでシェルなどを叩かずともtar.gzを作れる。

gzipの方は簡単で、writePipeを使ってwriterを作るだけで良い。そのwriterにtarのデータを流すと、gzipで圧縮したデータがパイプにストリームとして送られる。

余談だが ふつうのLinuxプログラミング を読んでてよかった。ちょうど最近パイプの章を読んでいたので、直感的に理解ができた。

コードにするとこんな感じ。

gzipWriter := gzip.NewWriter(writePipe)
tarWriter := tar.NewWriter(gzipWriter)

ちょっと複雑なのはtarで、ディレクトリの配下をtarで固める場合、filepath.Walkを使う必要がある。

IsDir()でディレクトリを無視しながら、ファイルのみ相対パスでtarのHeaderに情報を渡す。

あとはパスを使ってos.Openで*os.File型を受け取り、それをtarWriterにデータをio.Copyでコピーする。

io.Copy(tarWriter, file)

なお、path/filepath はこれを見るととても参考になる。パス名によるOSの依存性も減らせるため、積極的に使うようにしている。

このコードを書くには相対パスの作成などfilepathを操作する必要があるため、かなり便利。

みんなのGo言語のCLIツール作成編とかもとても参考になるのでおすすめ。

mattn.kaoriya.net

近況

大学の学年が上がった

これについては本当に実感がないが、学年が上がったっぽい。

単位数もちょっと少な目ではあるがまぁ平均的ではあるので、割と普通の大学生活はしている。

学力がもう少し欲しい感はあるが、まぁそれはそれ。適度な感じで勉強しながら乗り切りたい。

サークルの部長になった

長らく活動?していたHUITの部長になった。

未だに学外生が部長ってどうなのという感情はあるものの、運営のメンバーも問題ないと言ってくれてる(優しい…)のでなんとなくでやっている。

1年間なんとなくで頑張る所存。

2020年度を思い返して

1年間、学内よりもはるかに多く学外の人と関わった感想として、閉鎖的な大学内より色々な人を知れてずっと面白い。

大学内にも頑張ってる人はいるけど、分野を極めてるような人は極々限られるので話が通じないのが悲しい。

とはいえ一定以上広がると、ネットで知り合いを増やすと自分の興味のある分野を中心とした人に知り合いが偏るなぁという気がした。

知り合いの知り合いはもう知ってる人だったりするので、まぁそんなもんだろうとは思う。

これは性格上なんだろうけど、新しいものに飛びつけない(ミーハーになりたいけどなりきれない)のもある。

技術的に新しいものには飛びつくから、なんとなく思想的なものなのかも。

何が言いたいのかというと、オンラインコミュニケーション難しい。

2021年度

まずSecHackに出たい。これが一番の目標。

作りたいものはあるので、いい感じに大学と両立していきたいところ。

あとはサークル運営。せっかく部長になったので、いい状態でサークルを引き継ぎたい。

できれば大学はオンラインのままでいてくれると助かるなぁ。対面講義されると一日が通学だけで終わるので。

秘匿情報を隠しながら React 製静的サイトを GitHub Actions で firebase に自動デプロイした話

フロントエンド超入門

所属しているサークルで簡単な静的サイト(TypeScript + React製) を作った。(大部分手伝ってもらってるので、作ってもらったの方が正確かもしれない)

機能として必要なことは json を特定の URL に POST するだけだったので、静的サイトにして firebase とかに乗せれば楽そうだなぁというノリで進めた。

とりあえずまずは GitHub をば。

github.com

秘匿情報

初めからパブリックリポジトリに置くつもりだったが、POST する URL を公開したくなかった。

というのも、この URL にPOSTした情報はそのままサークル内 Discord に流れるため、不特定多数に公開すると面倒なことになりかねない。

コードに URL ベタ張りはできないが、とはいえサークル内からのプルリクとかは受け付けたいし、firebase に自動デプロイもしたい。

ということで GitHub Actions を用いて秘匿情報を隠したまま自動デプロイする方法を探ってみた。

GitHub と React の機能を組み合わせる。

GitHub の Settings にある Secrets タブには、秘匿情報を入れられる Repository Secrets という機能がある。

これ単体だと何にも使えないが、ここに入れた情報は GitHub Actions で扱える。

更にReact では、 process.env.REACT_APP_<環境変数名> とすることで、環境変数をビルド時に埋め込める。

これを併用することで、

  1. Repository secrets に秘密情報を設定
  2. その情報を用いて GitHub Actions に環境変数を設定
  3. actions でのビルド時に環境変数をデプロイするコンテンツに埋め込み
  4. そのままactions で firebase にデプロイ

という流れを作れる。

これであれば、コード内に残るのは REACT_APP_<環境変数名> だけなので、隠したい情報は公開しなくて済む。

GitHub Actions が思ったより便利

GitHub Actions は色々できるっぽい。 すごい。

サーバチューニングコンテストインフラ担当のAnsible設計書

去年の9月のisucon10予選、今年の2月のN-PTCなどに参加して、ツールの使い方や初動をまとめたくなったので記事を書いていたが、書きながらこの辺をうまいことやるplaybookを書いて、Ansibleで3サーバ同時に叩き込んだ方が良いのでは?と思った。

どういう構成にするか考えながら、大まかな設定を忘れないうちに書いておく。

あとでplaybook書いたら公開する(予定は未定)

サーバの配分について

3人チームなら勿論1人1台。

最近の傾向を見ると、isuconなどでは1チームに3台のサーバが割り振られる。ただし、ベンチを向けられるサーバは1台しかないこともある。

この場合、ベンチサーバは作業が終わってもインフラが持った方がよさそう。(nginxなどのチューニングのため)

前準備

何より先にGit管理。複数人だとGit使えないとコードに触ることもできないので、急いでセットアップする必要がある。

セットアップで必要になるスクリプトの流し込みとkataribeなどのインストールはAnsibleで行い、インストールまでできるようにしておくと楽そう。

まずSSHしてディレクトリ構成を把握、playbookをwebapp/などのディレクトリを対象にできるよう微調整する。 .gitごとwebアプリケーションのディレクトリに全部Ansibleで叩き込む。

このAnsibleのplaybookに入れておくべき処理は以下

  • webapp以下に入れるベンチ前setupスクリプト/ベンチ後summarizeスクリプト
    • どこに入れるかは変数(git_dir)にしておき、当日サーバにSSHしてから変数にパスを入れる
    • setup/summarizeについては自作する
  • Nginx/Apacheの設定ファイルをwebapp以下に持ってくる
    • ↑↑の変数のディレクトリ(git対象リポジトリ)にコピーしてくる
      • 普通にコピーするとsu権限になるので、その辺もAnsibleでちゃんとやる
      • 必要な変数はgit対象リポジトリ↑↑↑(git_dir)と設定ファイルのあるディレクトリ(original_conf_dir)
  • kataribe, pprofなどのインストール
    • 主にgo get -u が必要になるもの
  • (mysql8などのインストール)
    • これは状況によるが、以前mysql8へのアップデートが効くことがあったので、一応入れておくと良いかも

nginx,Apacheの設定ファイルの場所は決め打ちしない方が良い(ミスるとgit管理が面倒になるため)

Nginxなら

$ sudo ls /etc/nginx

Apacheなら

$ sudo ls /etc/apache 
$ sudo ls /etc/apache2

あたりにあるので要チェック。このファイルを基準にAnsibleでgit対象ディレクトリに持ってきて、ベンチ前に使用するsetupスクリプトapacheなどの設定ファイルをコピーする処理を入れたい。

3台にとりあえず最低限必要ファイルを叩き込めたら、メインとなるサーバで作業する。

git監視対象の設定

ここからはサーバにSSHして直接ファイルに触る。

まずはgitの設定。
このタイミングで大きなファイル等がgitに入ると時間がかかって面倒なので、gitで共有するファイルは

  • apache/nginxの設定ファイル
  • 初期設置スクリプト
  • アプリケーションのコード部分のみ

に絞った方が良い。後から必要なファイルがでてきたら、適宜.gitignoreから除外する。
下手に広範囲にgitの監視対象にすると、ミスったときに大変になる。

ここで.gitignoreを作ったらすぐpush -fして、チームの人に他2台にpullしてもらう。

kataribe

Apache, NginxなどのWebアプリケーションサーバのログをいい感じに整形してくれるツール。

github.com

過去2回とも使用している。
ほぼ必須レベルのツールで、これがあればWeb APIエンドポイントの呼び出し時間、回数などの情報が可視化できる。

使い方は以下であるが、セットアップまではAnsibleで行えそう。

$ go get -u github.com/matsuu/kataribe
$ ${GOPATH}/bin/kataribe -generate 
#GOPATHは普通は/home/${username}/go にある。go env GOPATHで表示可
$ cat <logFile> | ${GOPATH}/bin/kataribe 
# 整形されて呼び出し回数やかかった時間などでランキング形式になった結果が出てくる

kataribeの注意点としてkataribe -generateで出来たkataribe.tomlの中にLogFormatの例がある。

それをApacheやNginxなど、それぞれ使用するアプリケーションサーバのログフォーマットにする必要があるため、この時点でapacheなどのconfigファイルはgit管理しておきたい。

他にはkataribe側の設定を必要とすることはあまりない。

ここで得た結果を見て、○○のAPIが重そうだ→何が原因なんだろう?という流れで検証する。

kataribeのメリットは基本的にどの言語、競技にも対応できること。

NginxとApacheは大体どっちか使われるし、実装言語に依存しないツールなので、ここまでは完全なルーチンワークにして良い。

自分はここで吐き出されたログファイルを、Goで作った自家製ツールでDiscordに飛ばすことが多い。 そのためにsummarizeスクリプトが必要になる。

pprof

Goのプロファイリングツール。Go以外の実装には使えない。
このツールの便利さは、コードの何行目にどの程度かかってるかまで可視化できるところにある。

kataribeは「このエンドポイントが遅い」までしか分からないが、pprofは「○○行が遅い」あたりまで出力してくれる。

じゃあpprofだけでいいじゃんと思うかもしれないが、画像配信などが原因になっていることもあるので、切り分けのためにkataribeは必要。

使い方はここで書くより参考になる資料があるので、リンクをおいておく。

インストールに

$ go get -u github.com/google/pprof

が必要だが、Ansibleにまとめられる。

使い方は以下が参考になる。

medium.com

pprofは使うのにmain関数に一文追加する必要があるので、ブランチを切って行いたい。

またここで絶対ベンチが必要になる。(計測のため)

pprofを動かしてベンチを取っている最中に、pprofを適用したブランチからのプルリクを送り即マージ。他の人にpullしてもらう。

pt-query-digest

スロークエリの集計。aptリポジトリを追加してapt installでインストールできる。

これもAnsibleでインストールまでは行きたいが、aptリポジトリの追加がAnsibleでできるかが未確認なので、手打ちが必要になる可能性がある。

www.percona.com

に乗っているので、後で読む(実はまだちゃんと使ったことがない)

その他

この辺でDBスキーマを把握しておきたい。

initとかの初期化ファイル関係にパスワードが入ってるか、コードの中に埋め込まれていることが多い。

おそらくテーブルはそんなに多くない(2-8程度)なので、全部

show full columns from <table名>;

とかで取得して、スクショなどで共有する。

アプリ担当にこの辺りまで任せられると少し楽かも。

top, dstat, iotopとかでioやcpuの挙動も見ながら、適宜どこを修正すべきかを伝えていくことがインフラの仕事な気がする。

まとめ

ここまでのツールがあればgit管理、エンドポイントの処理時間、プログラムの重そうな部分の把握、SQLのスロークエリの分析ができる。

ここまで行えば、パフォーマンスチューニングに必要な計測は全て行えるので、アプリ側に集中できる。

できれば開始1時間で計測関係のセットアップは片付けたい。

今月の積読録(2021/1)

今月の方向性

主にクラウド面の知識拡充。本ではないがフロントの学習も少し。

年始ゆっくり羽を伸ばしたが、春休みどうしようかな。

新しいLinuxの教科書

新しいLinuxの教科書

新しいLinuxの教科書

自分で読むというよりは、ハンズオン資料作成の参考に買った。

ほとんど知っていることばかりだったが、スクリプト再帰を扱うところはコード書き慣れてないと難しそうに思えた。

実践Terraform AWSにおけるシステム設計とベストプラクティス

Terraform本。IaCの知識拡充のためと、クラウドについての知識を広めるために買った。

今月はクラウド技術の知識拡充を図った月だったが、その初めの一冊がこれだった。

Amazon Web Services インフラサービス運用大全

AWSの本。AWSは今月OSS絡みで話題に上っていたが、それとは特に関係ない。

ハンズオン形式なので、今あるタスクを片付け次第に進める。

Serverlessを支える技術 第3版

booth.pm

とりあえず一回全部読んだ。主要クラウドごとの違いなどを知れて面白かった。

同人誌はページ数だけ見れば割高感はあるが、実際に使った感想なども入っていてとてもありがたい。

AWS本読んだらもう一回読むことになりそう。

Ansible実践ガイド 第3版

Ansibleの本。これは半額だからとりあえず買った感じ。

雰囲気でOAuth2.0を使っているエンジニアがOAuth2.0を整理して、手を動かしながら学べる本

booth.pm

OAuth2.0の本。Twitter APIで必要だったので買ってみた。

認証、認可の違いとかは読んでて面白いなと思う。100ページちょいだったけど結構難しかった。

SQL 第2版 ゼロからはじめるデータベース操作

SQLの初心者本。今月に買った中では一番面白く読んでいる。

この人の本をもう一冊持ってるが、そちらが難しいので試しに初心者本を買ってみた。

SQLごとの方言について記載があるのが良い。

kindle oasisでもePubが読みたい

kindleのつらみ

電子書籍の標準フォーマットといえばePubだ。これがそのまま読めるのが本来あるべき姿だ。

しかしなぜかkindle電子書籍用端末kindle oasisではePubがそのまま読めない。3万するのに…。

ということで、色々調べながら検証してみた。

kindle電子書籍を送る方法

kindle電子書籍を送る方法は2つある。

  • USB接続でファイルを流し込む
  • send to email を使う

USB接続は一般的な方式なので何も説明することはない。ただし、これを行うと何をどうしても表紙は出てこなくなる。

一方、send to email ではうまくやれば表紙が出せる。ただしこちらにはファイル形式の制限がある。

自分は表紙がないのが許せないので、send to emailでやることにした。

epubを変換する

普通に調べるとepubをmobiに変換する…という記事ばかりだが、mobiという形式は実はあまり良い形式ではない。

というのもmobiは古い形式で、行間を指定する方法がない。(少なくともcalibreでは)

で、その状態ではどう変換しても字を詰め込んだ電子書籍になる。読みにくいことこの上ない。

じゃあこれはどうにもならないのかというと、実は最近は改善する方法がある。

kindle previewerでmobiファイルをエクスポートすれば良い。やり方は調べれば簡単に出てくる。

これであれば行間が空いていて読みやすい。calibreより簡単だし、こちらを使えば何も困ることはない。

ただし kindle previewerには致命的な欠陥がある。こいつで作るとなんと表紙が出ない。

こういうことである。

mobiとazwとazw3と

そんなわけでkindle previewerでお手軽電子書籍変換の夢は潰えた。ここからはなんとか頑張るしかない。

勿論日本語の情報などほとんどないので、手探りで英語の情報をかき集めた。ググり力が試される。

そこで分かったのは以下。

  • mobi

    • 古い形式。HTML3.2(確か) を元にした形式で、CSSが使えない
    • 互換性が高い
    • kindle previewer, calibre両方で出力可
  • azw

    • mobiに比べ新しい形式
    • calibreのmobiで、mobi出力→MOBIファイル・タイプをbothにした場合出てくるのがこれ
    • 古い端末にはmobiとして、新しい端末にはazwとして読み込まれる形式
    • うまくいける気がしたし、実際PCのビューアーではうまくいった
    • でもoasisにはmobiとして扱われたようで、行間問題が解決しなかった
  • azw3

    • azwに暗号化を付けた形式?(未確認)
    • どうやってもsend to emailでは送れない
      • 拡張子変えたり色々したけど無理だったのでこれ以上調べる必要はなさそう

ということで、現状では表紙問題と行間問題を両方解決する手段がないのである。

mobi形式の中身が分かれば、kindle previewerで作ったmobiファイルに表紙だけを追加で入れることができるかもしれない。

しかし残念ながらmobi形式についての詳細がなかったので、自力で解析するぐらいしか方法がない。

情報あればください……。

結論

kindleは2020年にもなって、epubも開けない電子書籍端末を売らないでほしい。epubが読めれば何も苦労しないのに…。