Terraform 入門

    参考 10分で理解するTerraform | Qiita Terraform入門資料(v0.12.0対応) ~基本知識から設計や運用、知っておくべきtipsまで~ | Qiita AWSでTerraformに入門 | Developers.io Terraform職人入門: 日々の運用で学んだ知見を淡々とまとめる | Qiita 手を動かしたい方は Terraform ハンズオン with MySQL Provider も参考にしてください。 前提 執筆時点 (2020/01/05) で Terraform の最新バージョンは v0.12.18 です Terraform とは Terraform は Infrastructure as Code を実現する汎用的なCLIツールです。 インフラの状態を設定ファイルに定義し、コマンドを実行することで、 実際のインフラの状態と設定ファイルの差分を検知し、設定ファイルに記述されたとおりになるようにインフラを変更(CRUD)します。 Hashicorp という企業がホストしている OSS になります。 Go で書かれています。 https://github.com/hashicorp/terraform Terraform のインストール Terraform は Go 製なので 1 バイナリをダウンロードしてインストールするだけです。 https://www.terraform.io/downloads.html tfenv を使うと管理が楽です。 https://github.com/tfutils/tfenv tfenv は Terraform のバージョン管理ツールです。 pyenv や rbenv の Terraform 版みたいなものです。

    Terraform の State Locking の概要

    Terraform の State Locking という機能の概要について説明します。 ただし、自分もちゃんと理解しているわけではないので、推測も混じります。 基本的には公式ドキュメントに書いてある内容なのでそちらをご参照ください。 State Locking とは terraform plan などのコマンドは State を変更する場合があります。 その処理は atomic ではないため、同時に複数のコマンドが State を書き換えようとすると不整合が生じる可能性があります。 例えば S3 backend の state を state rm で更新する場合を考えます。 これはコマンド内部で 現在の State を取得する (READ) 修正した State を S3 に push する (WRITE) という処理を行っているはずであり、複数のコマンドを実行した場合、READ と WRITE の間に他のコマンドによって WRITE されると、その WRITE による変更が消えてしまいます。 そこで State Locking を使うと各コマンドで State を変更する前に lock を取り、WRITE 後に lock を解除します。 コマンドラインオプション plan, apply, refresh, state rm, state mv, state push には次のようなオプションがあります。

    dd-time - コマンドの実行時間を Datadog に送るツール

    コマンドの実行時間を Datadog に送る dd-time というツールを作りました。 このツールは circle-dd-bench にインスパイアされていますが、 CircleCI 以外でも需要あると思ったり、他にも幾つか改善したい部分があったので自作することにしました。 circle-dd-bench については circle-dd-bench の作者が書いたブログ https://blog.yuyat.jp/post/circle-dd-bench/ も参考にしてください。 dd-time は Go 製なので GitHub Releases からバイナリをダウンロードしてインストールすれば使えます。 使い方はシンプルで実行時間を計測したいコマンドの前に dd-time -- をつけるだけです。 例えば Docker image のビルドの時間を計測したい場合次のような感じになります。 $ dd-time -t command:docker-build -- docker build . Datadog の API key を環境変数 DATADOG_API_KEY として設定する必要があります。 こうすると Datadog の Post timeseries points API を使い、command_execution_time というメトリックス名(変更可能)でコマンドの実行時間が送られます。 メトリックスの名前や host, tags はそれぞれ --metric-name (-m), --host, --tag (-t) で指定できます。 --tag は複数回指定可能で、 key:value というフォーマットで指定します。

    モブレビューやっていきたい

    最近モブレビュー取り入れたいと感じていて、なんで取り入れたいかなどについて書いてみました。 モブレビュー自体まだ 2, 3 回しかやってないので説得力にかけますが、ご容赦ください。 想定 チームは 6 人以下 Pull Request (以下 PR) をマージするには必ず他の誰かが approve しないといけない 目的 チーム内の情報共有 属人化の解消 退職や異動などによる情報の喪失(誰も分からない状態)を防ぐ チーム外の人とのコミュニケーションにも活用できる レビュー待ちの短縮 レビューの品質の改善 仕事を評価してもらうことで承認欲求を満たす オンボーディングの改善 レビューを通じて必要な知識を吸収してもらう オンボーディングに限ったことではないが、オンボーディングにも有効ではないか 最後までやりきる 箇条書した内容を補足します。 情報共有 属人化の解消は結構重要だと自分は思っていて、特定の人じゃないと出来ないこと、わからないことというのは ボトルネックや技術的負債だったり、障害対応時に致命的になりかねません(深夜に障害が起こってAさんに聞かないとわからないのに、Aさんと連絡が取れないとか最悪)。 チーム全員とはいかなくても 3 人ぐらいは出来る・分かってる必要があるかなと思います。 まぁ、当初は 3 人ぐらい分かってても、時間が経って異動やら退職やらで気づいたら分かっている人いなくなってたというのは ありえなくないので、そういったリスクをどうやって防ぐかというのは考える必要がありますが、今回の話とは外れるので割愛します。 また、チーム外の人とのコミュニケーションにも活用できると思っていて、 例えばランチや飲み会でチーム外の人とのコミュニケーションを取る際に自分のチームの他の人が対応した件とかが話題に上がったときに ちゃんと情報共有できてないと、自分は担当外なので分かりませんとなってしまうでしょう。 知っていればむしろ自分から話題にできるかもしれません。 そこから発展して更に新しいタスクの話もできるかもしれません。 レビューの改善 せっかくいい仕事をしても中々レビューしてもらえないとなると不満がたまります。 モブレビューを実施することでレビューを促進し、レビュー待ちの時間を短くできることを期待します。 レビューしたくても良くわからなくてレビューできないというパターンもあると思うので、 わからない部分をモブレビューで解消されてレビューが進むと良いですね。 また、ちゃんと複数人でレビューすることで目先の問題を解決するだけの本質的でない問題解決を防ぐことが出来ることもあると思います。 「いや、それそもそもPRの前提がおかしくない?前提となっている仕様を見直すべきなのでは」 みたいなこともあるかもしれません。 仕事を評価してもらうことで承認欲求を満たす いい仕事したら他の人にも知ってもらいたいというのは自然なことでしょう。 いい仕事を褒めるのは良いチーム・環境であり働きやすさというところにつながるのではないでしょうか。 ちなみに現職だと Slack で他のチームにも共有して emoji で褒め称えるというのが結構やられていて 気持ちのいい環境だなと思っています。

    go-timeout - command の timeout

    作ったのは 2ヶ月くらい前の話ですが、 Go の command の timeout を実装するためのライブラリを作ったので紹介します。 https://github.com/suzuki-shunsuke/go-timeout 基本的には https://github.com/Songmu/timeout をオススメしますが、これだと上手くいかないパターンがあったので自作しました。 Go の command の timeout に関しては https://junkyard.song.mu/slides/gocon2019-spring/#24 がとても参考になります。 上記のスライドでは 標準ライブラリの exec.CommandContext でも停止できるが、 SIGKILL で強制的に停止することになる 子プロセスが停止しない 公式見解 では、SIGKILL 以外は標準ライブラリではサポートしない。サードパーティでやればよい Songmu/timeout 使えば SIGKILL 以外でより安全に停止できる ということが丁寧に説明されています。 自分は cmdx という task runner を開発していてその中で task の実行時に timeout を設定出来るようにしました。 当初 Songmu/timeout を使って実装したのですが、問題があることに気づきました。 それは、 command の中で fzf を使うと、上手く動かないというものでした。 https://github.com/suzuki-shunsuke/cmdx/issues/52 https://twitter.com/szkdash/status/1165529415238815745 正直この辺の挙動はちゃんと理解できていないのですが、 調べてみると Songmu/timeout だと syscall.SysProcAttr の Setpgid を true に設定していて、そうすると fzf が上手く動かないようでした。

    cmdx - task runner

    最近自作した OSS, cmdx の紹介です。 https://github.com/suzuki-shunsuke/cmdx cmdx は task runner です。 task runner の定義はググってもわからなかったので、 cmdx を task runner と呼ぶのが適切かわかりませんが、 ここではプロジェクト固有のタスク 依存するライブラリのインストール ビルド テスト コード整形 lint etc などを管理するものとします。 類似するものとしては以下のようなものがあります。 Make npm scripts Task tj/robo mumoshu/variant 使い方 詳細は README を読んでください。 $ cmdx -i で設定ファイルの雛形を生成します。 そして設定ファイルに task を定義していきます。 設定に関しては README を参照してください。 そうすると cmdx -l でタスクの一覧とその説明が見れます。 例えば次は cmdx のリポジトリでの実行結果です。 $ cmdx -l init, i - setup git hooks coverage, c - test a package (fzf is required) test, t - test fmt - format the go code vet, v - go vet lint, l - lint the go code release, r - release the new version durl - check dead links (durl is required) ci-local - run the Drone pipeline at localhost (drone-cli is required) これにより新しくプロジェクトに参画した人もどのような task があるのか直ぐわかります。 例えば test を実行したければ cmdx t を実行すればいいことがわかります。 cmdx help test とすればここのタスクのより詳細なヘルプが見れます。

    Drone Extension のリスク

    Drone v1 では Extension という仕組みが導入されました。 これは文字通り Drone を拡張する仕組みで、仕様に従って作れば自由に Drone を拡張できます。 https://docs.drone.io/extensions/overview/ 全てを本体でやるのではなく、拡張する仕組みを提供し、あとはコミュニティに委ねるというのが Drone の一つの方針とも言えると思います。 Extension は非常に面白い仕組みだと思いますが、 Drone を運用する立場からすると中々頭が痛い仕組みな気がしてて、 自分は導入に対し慎重な立場です。 単なる杞憂で済めば良いのですが、その懸念について書きたいと思います。 根本は Drone Extension 固有の問題と言うより、一般的な拡張機構全般に言えることだと思います。 ただし、 Drone Extension は全てのビルドに影響を及ぼす、 CI/CDシステムが動かなくなるとサービスのリリースに影響を及ぼしかねないということからよりリスクの高いものになっています。 本体の drone/drone と比べ、開発は活発ではなく、サードパーティの extension はいつ開発が止まってもおかしくない 本体の drone/drone と比べ、ドキュメントやサポート体制が貧弱だと思われる(drone に関しては https://discourse.drone.io でサポートされているが、サードパーティの extension では難しい) ユーザーからの extension に関する要望を受け付けるようになると、管理者の負担になる extension のクォリティはマチマチであり、例外処理が甘かったり、ちゃんとエラーを吐かないものもあるだろう トラブルシューティングが難しいと思われる extension の仕組み上、extension を必要としないビルドにも影響を及ぼしうる 一度追加し、依存しだすと消すのが難しくなる extension が落ちると全 build に影響するので、耐障害性(冗長化)、モニタリングが必要 etc 勿論、上記の懸念点は Extension によって提供される機能とトレードオフであり、 Extension の導入方針は Drone が運用される環境によって大きく依存すると思います。 例えば全員が顔見知りのような小さな組織で特定のサービス専用に Drone を使っていてかつ Drone の運用体制(人員)に十分余裕があるなら 積極的に Extension を導入しても問題ないかもしれません。

    Drone v1 で gRPC が使われなくなった

    v0.8 では server - agent 間の通信に gPRC が使われていましたが、 v1 では使われなくなりました。 理由 https://discourse.drone.io/t/curious-about-decision-to-drop-grpc/3987 gRPC関連のトラブルの問い合わせが多すぎてサポートしきれないので止めた v1 での通信方法 https://discourse.drone.io/t/drone-agents-keep-closing-connections-with-499-code/5197/2 agent がロングポーリングしている 30秒後、なんのビルドもなければコネクションを切って、再接続する(張りっぱなしにしてると、LBやファイアウォールにコネクション切られるため) 自分も v0.8 から Drone を運用していて最近 v1 に upgrade しましたが、 v0.8 では gRPC 関連のトラブルが頻発していました。 server のログでは絶えず gRPC 関連のエラーを吐いていましたし、 server - agent 間の TCP connection が切れっぱなしになって戻らくなって agent 数がどんどん減っていったり ビルドが pending のままになったり、色々ありました。 関連する issue はあり、幾つか対策を打ってみたりしましたが、結局解決しませんでした。 https://github.com/drone/drone/issues/2090 https://github.com/drone/drone/issues/2246 https://github.com/drone/drone/pull/2294 https://www.reddit.com/r/droneci/comments/8opifu/drone_stops_working_after_some_little_time/e06d1gn/ それが v1 にアップグレードして gRPC が使われなくなってから解消し、個人的にはとても助かりました。 管理者的にはアップグレードして一番嬉しい点ですね。

    Golang での時刻の扱い方を整理する

    今更ながら Golang での時刻の扱い方について改めて整理してみました。 まとめ time.Local は明示的に設定する(基本UTC) DB などには 基本UTC で永続化する 出力時に必要になったらタイムゾーンを変更する location は出力時に問題になるので出力時に location を明示的に指定する 逆に言うと出力時以外は問題にならないので無理に location を UTC にしなくても良いかもしれない サードパーティ(ex. ORM) に time.Time を渡す場合は location に注意が必要 文字列として時刻の入力を受け付ける場合は location を明示的にセットする サードパーティが time.Local に依存する場合、 time.Local を明示的に UTC にしたりする必要があるかもしれない アプリケーションで利用する location が分かっている場合、location を取得するヘルパー関数を定義する time.LoadLocation は環境依存なので予め location が分かっているなら使わないほうがよい 文字列を time.Time に変換する場合、time.ParseInLocation で Location を指定して time.Time に変換後、time.Time.UTC() で UTC に変換する time.Time を文字列に変換する場合、time.In で location を変換後、time.Time.Format で文字列に変換する グローバルな location https://golang.org/pkg/time/#Location

    Drone v1 では Jsonnet が extension なしで使える

    Drone では v1 から冗長な YAML を DRY にする一つの手として、 Jsonnet の利用が推奨されています。 これについては過去のブログでも触れています。 https://techblog.szksh.cloud/drone-jsonnet-generator/ しかし、 v1 の rc の時点では Jsonnet の活用には Jsonnet Extension が必要でした。 https://engineering.linecorp.com/ja/blog/go-oss-ci-cd-platform-drone-1-0-0-rc-1/#title7-1 しかし、 v1 の正式版では Jsonnet Extension がなくても Jsonnet が利用できるようになっています。 まず Drone の管理者側で Drone server に環境変数 DRONE_JSONNET_ENABLED=true を設定する必要があります。 そうしたら、ユーザー側は次のようにすることで jsonnet が使えます。 .drone.yml の代わりに .drone.jsonnet をコミットする (.drone.yml は不要) 各リポジトリの settings の Main > Configuration で設定ファイルのパスを変更する こうすることでビルド実行時に自動で Jsonnet が YAML に変換され処理されるようです。 いつから Jsonnet Extension は不要になったのか https://github.com/drone/drone/compare/v1.0.0-rc.6...v1.0.0 https://github.com/drone/drone/commit/5013cfa993fa455fc56f10e45b9f36cf1d6dff57 v1 の rc ではサポートされてませんでしたが、正式版をリリースするタイミングで Jsonnet Extension が不要になっていたようです。