Slide 1

Slide 1 text

闇のBashをGoに 置き換える技術 @nashiox 2017/12/11 golang.tokyo #11

Slide 2

Slide 2 text

@nashiox 水野 拓 (Taku MIZUNO) - インフラエンジニア@リブセンス - オンプレ/クラウドのサーバ構築・運用 - Go歴 - 約3年 - 最近のGo実装 - Mackerel プラグイン - Packer プラグイン

Slide 3

Slide 3 text

身の回りにこんなスクリプト ありませんか?

Slide 4

Slide 4 text

怖くて触れないけどなぜか 動いているBashスクリプト

Slide 5

Slide 5 text

インフラ運用に携わるとよく見かけます - 運用で利用するシェルスクリプト - 長い間メンテナンスされてない - メンテナーがいるかすらわからない - 読み解ける人がいない - 怖くて触れないけどなぜか動いている - Ex - サーバ構築スクリプト - 便利CLI - バッチスクリプト

Slide 6

Slide 6 text

リブセンスにもありました

Slide 7

Slide 7 text

10年を超える運用で積み重なった闇 - なにがどこで行われてるかわからない - けれどなぜか動いてる - それを実行しないと仕事にならない - どこを直せば良いのかすらわからない - 作成者はすでにいない - etc…

Slide 8

Slide 8 text

10年を超える運用で積み重なった闇 - なにがどこで行われてるかわからない - けれどなぜか動いてる - それを実行しないと仕事にならない - どこを直せば良いのかすらわからない - 作成者はすでにいない - etc… 闇を感じていただけたでしょうか?

Slide 9

Slide 9 text

気合を入れて直しています

Slide 10

Slide 10 text

リブセンスの場合 - 積み重なった闇のBash群 - サーバ構築スクリプト - Bash -> Chef -> Ansible と変遷 - 便利CLI - PythonやGoに置き換え - バッチスクリプト - Goに置き換え

Slide 11

Slide 11 text

リブセンスの場合 - 積み重なった闇のBash群 - サーバ構築スクリプト - Bash -> Chef -> Ansible と変遷 - 便利CLI - PythonやGoに置き換え - バッチスクリプト <- 今日はここの話 - Goに置き換え

Slide 12

Slide 12 text

強敵のバッチスクリプト

Slide 13

Slide 13 text

その名も開発DB構築スクリプト

Slide 14

Slide 14 text

こんな動作をします

Slide 15

Slide 15 text

10 ファイル 2128 行におよぶ Bashスクリプト

Slide 16

Slide 16 text

※ 事実ではありません

Slide 17

Slide 17 text

読めるわけがない

Slide 18

Slide 18 text

スクリプトの動作 - データ加工 - 元データのリストア - 並行で加工処理 - ダンプ - データ加工後のデータをテーブルごとに並行でダンプ - DBを一度に作れるフルダンプも生成 - インポート - フルダンプからの開発DB生成 - 日次更新が必要なテーブルを並行で部分インポート

Slide 19

Slide 19 text

他にはこんなことをしています - 失敗した時点から再実行するためのファイルキュー - Bashで書かれたファイルキュー実装 - それを利用したリトライ処理 - GNU parallel を使った並行実行 - データ加工 - ダンプ - インポート

Slide 20

Slide 20 text

※ 事実ではありません

Slide 21

Slide 21 text

読めるわけがない

Slide 22

Slide 22 text

よしGoに置き換えよう 読めるわけがないと言ったが読むしかない

Slide 23

Slide 23 text

Goの選定理由 - 並行実行の実装が容易 - Goroutineを使うだけで並行処理の実装が可能 - バッチなのでGoroutineのコストを気にしなくていい - Goの言語仕様のシンプルさ - 実装も利用するのもインフラエンジニア - コードを書くことが本職ではない - 複雑な実装が出来るよりも制約されるほうがいい - go testが言語仕様に組み込まれてるのもよい - IDEが使える - 補完・コードジャンプは重要

Slide 24

Slide 24 text

リプレースの方針 - いきなり全部Goに置き換えない - 読み解ける範囲、置き換えやすいところから - 難しいところはos/execでのBashの実行を許容 - Goらしさよりもまずは読み解けることを優先 - 置き換え中はBashっぽくなることを許容 - 徐々にGoらしく置き換えていく

Slide 25

Slide 25 text

ファイルキュー実装(Bash版)

Slide 26

Slide 26 text

ファイルキュー実装(Go版)

Slide 27

Slide 27 text

並行実行実装(Bash版)

Slide 28

Slide 28 text

並行実行実装(Go版)

Slide 29

Slide 29 text

Bash実行 - パイプ・リダイレクトに対応するためbash -cを使用

Slide 30

Slide 30 text

Bash実行(ログつき)

Slide 31

Slide 31 text

最近ハマった - io.MultiReader() は複数Readerの”連結” - stdoutとstderrを時系列順でログに吐きたかった - “連結”なのでstdoutがcloseされてからstderrを書く - stdoutがほとんど出ないコマンドを実行していた - 実行後30分ほどたってドバっとログが吐かれた

Slide 32

Slide 32 text

初回リプレースから約9ヶ月 - 動作は順調 - 問題なく動いています - 開発・リプレースも順調 - 現在 v0.0.8 - 読める・手を入れやすくなったため、変更が容易 - 外部コマンドに頼っていた部分もリプレース開始 - ダンプ・インポート部分(mysqldump) - Pure Goで実装してOSSとして出すつもり - (今日に実装間に合わなかった)

Slide 33

Slide 33 text

まとめ - 闇のBashをGoに置き換えたのは良い選択だった - 読みやすい・書きやすいことは大事 - 無理に全部置き換えようとしないのはもっと大事 - Goroutineのパワーすごい - 1バイナリになるので管理も楽 - 最近自前RPM化もした - メンテナンス出来るって素晴らしい - 動き続けてても放置はダメ - 先々を考えた技術選定も大切