Terraformベストプラクティス解釈

最近、自分のチームでTerraformを使ってAWSオーケストレーションをやろうという話になった。

サーバー台数も10~20台程度、今まではAWSコンソールをポチポチしてインスタンスを用意していたが
サービス規模の拡大に伴って、手動オペレーションによるミスを防いだり、インフラ説明コストなどを省くこと、インフラ整理の意味合いで導入している最中。

Terraformに触るのは初めてだったので、ドキュメントを読みつつ基本的な機能について勉強しつつ
どのようなファイル構成で管理をするのがいいのか、経験者の同僚にアドバイスをもらいにいったところ
Hashcorpが公開しているベストプラクティスのリポジトリを教えてくれた。

github.com

ところがこの構成、けっこう複雑で初心者がいきなり読み始めるのは辛かったので
復習も兼ねてベストプラクティスを読み解いていく。

理解するために必要な要素

  • AWSの基本的な知識
  • 基本的なTerraformの操作
  • tfvarsファイルを使った変数管理
  • module機能

おおむねこの4つを理解すれば、その知識を使って読み解くことができるはず。
最初の2つは今回は解説を省きます。

tfvarsファイルを使った変数管理

Terraformではtfファイル内に変数を記述することができますが、変数に値を入力するには

  • tfファイル内に記述
  • 実行時にオプションで指定
  • 環境変数に埋めておく
  • tfvarsファイルに記述

の4種類の方法があります。

Input Variables - Terraform by HashiCorp

ベストプラクティスではtfvarsの手法が採用されており
以下のようなファイルが存在します。

best-practices/terraform.tfvars at master · hashicorp/best-practices

ここで定義した変数はtfファイル内で参照することができます。
ベストプラクティスでは環境ごとに利用する変数を全て1つのtfvarsファイルで管理しています。

module機能

Terraformにおけるmoduleは各resourceを抽象化するためのものです。

例えばベストプラクティスの中では

AWSのコンピューティングリソース(要するにEC2)群を管理する compute module
HAProxyが動くであろうインスタンスのresourceを抽象化した haproxy moduleが存在します。

ベストプラクティスでは、上に示したように

  • 各resource自体の抽象化 (haproxy module)
  • AWSのリソース群を示す抽象化 (compute module)

の2段階の抽象化が行われています。

さらにmoduleには、自分自身の変数をmodule外から出力するための outputという構文も用意されており
これを使うことで、例えばTerraformで作成したVPCのidをmoduleの外からも参照することが可能です。
https://github.com/hashicorp/best-practices/blob/master/terraform/modules/aws/network/vpc/vpc.tf#L17

ベストプラクティスでは、このmodule機能を使って
各resourceを抽象化、そして作成したresourceのidなど動的な情報をoutputすることで
module間の値の受け渡しを実現しています。

具体的にはEC2インスタンスを立ち上げる際に
先にネットワークを構築し、VPC, subnetなどのidをoutputしてEC2の設定に利用するなどの使い方をしています。

ベストプラクティスの構成

ここまでで、必要な知識は揃ったので
改めてベストプラクティスの構成を見ていきます。

module/aws
├── compute
│   ├── compute.tf
│   └── haproxy
│          ├── haproxy.sh.tpl
│          └── haproxy.tf
└── network
    ├── bastion
    │   └── bastion.tf
    └── vpc
     └── vpc.tf

providers/aws
├── README.md
├── global
│   ├── global.tf
│   └── terraform.tfvars
├── us_east_1_prod
│   ├── terraform.tfvars
│   └── us_east_1_prod.tf
└── us_east_1_staging
    ├── terraform.tfvars
    └── us_east_1_staging.tf

まず、1番上の階層には moduleとprovidersの2つのディレクトリが存在します。

前者はそのままmoduleを、後者は環境ごとのtfvarsやリソース群のmoduleを管理するtfファイルを含みます。

どんなリソースを作成しているか追うためにproduction配下のtfファイルを見ていきます。

production.tfでは、利用するリソース群のmoduleを定義しています。 以下はEC2リソース群を管理するcompute moduleです。

# production.tf
module "compute" {
  source = "../../../modules/aws/compute"

  name               = "${var.name}"
  region             = "${var.region}"
  vpc_id             = "${module.network.vpc_id}"
  vpc_cidr           = "${var.vpc_cidr}"
  key_name           = "${aws_key_pair.site_key.key_name}"
  azs                = "${var.azs}"
  private_subnet_ids = "${module.network.private_subnet_ids}"
  public_subnet_ids  = "${module.network.public_subnet_ids}"
  ~以下略~
}

compute moduleで読み込んでいるcompute.tf内には
各resourceを抽象化したmoduleが定義されています。
このmoduleで渡した変数が最終的にresourceとして使用されます。

# compute.tf
module "haproxy" {
  source = "./haproxy"

  name               = "${var.name}-haproxy"
  vpc_id             = "${var.vpc_id}"
  vpc_cidr           = "${var.vpc_cidr}"
  key_name           = "${var.key_name}"
  subnet_ids         = "${var.public_subnet_ids}"
  atlas_username     = "${var.atlas_username}"
  atlas_environment  = "${var.atlas_environment}"
  atlas_token        = "${var.atlas_token}"
  amis               = "${var.haproxy_amis}"
  nodes              = "${var.haproxy_node_count}"
  instance_type      = "${var.haproxy_instance_type}"
  sub_domain         = "${var.sub_domain}"
  route_zone_id      = "${var.route_zone_id}"
}

順番に見ていったように

ファイル 記述内容
production.tf どういったリソース群を利用しているのか
compute.tf どういうresourceを利用しようとしているのか
haproxy.tf どういう設定でリソースを利用しようとしているのか

が、それぞれわかるようになっており
大きく3階層の構造で ファイル構成が成り立っています。

ここにEC2のインスタンスを追加したければ最下層のmoduleを
新しいリソース群を追加したければ、中段以降のmoduleを追加していくような形です。

所感

ひと通り触ってみましたが

  • 階層の深さ
  • 変数定義の非DRYな感じ

は最後まで辛かったです。

階層に関しては、初見時にコードを追いかけていくのが大変だったので
中段のリソース群をまとめているcompute.tfなどのファイルを減らせないかと考えたのですが
そうするとproduction.tfなどの大元のファイルに各moduleを定義することになり、行数が肥大化してしまい
その環境にどういった種類のリソースが存在するのか、見通しが悪くなってしまうので、今の構成を受け入れるしかないという結論に落ち着きました。

2つ目の変数定義なのですが、各tfファイルに何度も variable hoge { } と書かされるのが本当にしんどいです。

今回は tfvars -> environment.tf -> resource_group.tf -> resource.tf といった具合に計3階層に渡って変数の値を受け渡す必要があったため
同じ変数の定義を3回書いています。

めちゃくちゃ面倒です。
この辺はTerraform側の対応を待つしかないようです。

しかし、それら不便な点を差し引いても Terraformは非常に便利な点が多いため、これからも積極的に利用していこうと思います。

ISUCON6 3万点台で予選敗退

会社の同僚と一緒に「尿酸値E」としてISUCON6出ました。
Ruby実装を選んで、最終的に「32660」というスコアで予選敗退。今年こそは本戦出るぞと意気込んでいたのでとても悔しい。

事前準備

前回出場時に、序盤の解析系作業で手こずったため
今回はかなり念入りに解析ツールの準備を行っていました。

事前に立てていた作戦

  • 午前
    • アプリケーションをサーバー上で動かしてベンチマーク流す
    • 同様にローカルで動かす
    • コマンド一発でデプロイできるスクリプトを置く
    • kataribe, pt-query-digest, stack-profなどで各種解析データを揃える
    • 解析データを元に作戦を立てて、各自作業していく
  • 午後
    • まずはベタにまずいクエリをつぶす (index効いてない, n+1)
    • 同様にミドルウェアもチューニングする (普段の業務で使っているnginx, unicorn, MySQL, sysctl.confを用意)
    • ↑やりきってからキャッシュ戦略考えよう

今回は午後の作戦を事前に話してしまったことで、キャッシュ戦略への切り替えが遅くなったのが敗因ぽい。
htmlifyボトルネックだということに午前の段階で気づけていたものの、ロジック改善を頑張ってしまい
結果スコアが伸びずキャッシュに切り替える時間をロスした。

当日タイムライン

9:30

無事に集合。前回に引き続き、会社のオフィスで作業させてもらうことに。
普段なれてる環境で作業するのが1番でした。

10:00

Azureにデプロイ。
最初なぜかインスタンス起動でエラーが出て、30分ほどリソースグループごと作り直したりしてた。

  • とりあえず1度ベンチマークを流す
  • 「isudaってなんだ? 増田か!!」
  • 「メモリ7GB近くあって結構いろいろのせられそうだね」
  • nginx.conf見て「isudaとisutarがマイクロサービスっぽくなってる」
  • githubにコードを上げておく
  • dumpを取る
  • ローカルで動かす

最初のインスタンス起動トラブルで焦ったものの、アプリケーションが動き出してからは比較的スムーズにいった。
この時点では作戦通り、まだアプリケーションを読み始めていない。

11:00

事前に準備をしていた解析ツールを入れて導入検証を進める

この辺の作業は

ISUCON予選突破を支えたオペレーション技術 - ゆううきブログ

ゆううきさんのブログを参考に用意していた。
特にデプロイスクリプトミドルウェアごと再起動するあたりは、忘れがちなので用意しておいてよかったと思う。

作戦会議の結果、特に事前に話していた作戦とは差分なく

みたいな配分で作業していくことになった。
ここまでは予定通り。

12:00 - 15:00

各自の改善を入れて少しずつスコアが上がる。しかしこの時間帯はスコアが1万にものらない。 以下のようなことを試した。

  • nginx -> unicornunixドメインソケット化
  • staticなファイルをnginxで返す
  • unicornのworkerを増やす 5 -> 10程度
  • istarをisudaに統合
  • MySQLにインデックス追加
  • keyword_pattern, htmlifyのロジック改善
  • ispamは解析始めると時間がかかりそうなのでいったん放置

ロジック改善以外はそこそこ効果があった。 正規表現部分だけどうしようもなくて、徐々にキャッシュの方に話がいきはじめる。

15:00 - 18:00

15:00すぎから、少し作業を止めて話し合い、キャッシュ導入を検討しはじめる。

最初は htmlifyまるごとredisにキャッシュ。たしかこれでスコアが1万を超えた。

そこからまた少しスコアが伸び悩み、再度ロジック改善に走る。
その間に htmlifyの処理を細分化し、さらに細かくキャッシュしていく。これでスコアが2万を超える。

また17:00の時点で一度インスタンスごと再起動してベンチマークが走りきるか確認。

キャッシュを進めていくと今度はまたstaticなファイルを返すのに詰まりはじめたり
ファイルディスクリプタを使い切ったりしたのでカーネルチューニング。

最終的に終了直前に keyword_patternの結果をredisにキャッシュしたあたりで3万オーバーのスコアが出て終了。

終了後

近所のすしざんまいに行って反省会

個人的には

  • キャッシュ戦略の引き出しが足りなかった
  • 正規表現周辺のロジック改善にこだわりすぎた
  • /initializeの5秒を使えず

あたりに後悔が残ってます。

今年けっこう気合い入ってただけに悔しい。本戦出場の壁高い。

しかしISUCON楽しい。出題チームの方々もおつかれさまでした。

表参道.rb #14 でLTしてきた

シャドウプロキシのkageを使って安心してFuelPHP -> Railsに移行した話をしました。

表参道.rb #14 ビアガーデン風編 - connpass http://omotesandorb.connpass.com/event/36622/

今回の会場はSansanさんのオフィスでした。
13Fにオフィスがあって、LT中におそらく神宮球場のであろう花火が見えたりしてよかったです。

今年は仕事で使った技術について色々話せるといいなと思います。 よろしくお願いします。

nginx実践入門を読んだ

nginx実践入門 (WEB+DB PRESS plus)

nginx実践入門 (WEB+DB PRESS plus)

発売を知って即予約した cubicdaiya さんの本。
タイトルの通り、実践のための内容でした。

特に良いと思ったのが

の4つの章で

3・4章では、普段webサービスを運営する上で使っている基本的な設定項目について丁寧に解説されていて
自分の中で歯抜けになっている知識の整理ができたり

基本的な設定やモジュールに関する解説中心ではあるものの、非常に丁寧で
たとえばngx_http_limit_req_moduleについてはleaky bucketアルゴリズムの図を交えて解説があり
モジュールに対する僕の理解が間違えていたことに気付くきっかけになりました。
感謝。

6・7章ではより実践的な内容を扱っていて

6章では自分も経験のあるphp-fpmやunicornなどの
アプリケーションサーバと連携して稼働するリバースプロキシの細かい解説

7章ではより大規模なトラフィックを扱う場合のキャッシュ戦略や負荷分散についてnginxででき得る対処が解説されていました。

特に7章ではwebアプリケーションサーバにおけるボトルネックとなりそうなハードウェアリソースとその対策の指針が解説されており
nginx実践入門というよりは、webサービス運用実践入門みたいな内容になっています。

普段本を読むのが遅く、読書自体に苦手意識が生まれてしまっているのですが
この本は全体構成としてwebアプリケーションを運用していく上で必ず遭遇するような問題と
それに対処するための方法として、nginxの設定やモジュール、構成が解説されているため
今までの自分の経験と照らしあわせながら読むことができ、ストレスなく読み終えることができました。

デスクに置いてリファレンスとしても活用できる非常にありがたい本です。おすすめ。

#CookpadTechConf 2016に行ってきた

クックパッドさん主催のCookpadTechConfに行ってきました。

techconf.cookpad.com

いくつか自分のチームで試したいことがあったのでメモ

技術力を事業の強みするために必要なこと

  • とにかくシンプルにする
  • 営業力でなんとかしない、技術で価値をつくる
  • 「とにかくがんばるぞ」という局面において技術は全く役に立たない
    • どの数字にフォーカスするか定義する必要がある
  • 議論や調整じゃなくて決定とテスト

開発した新技術から、新しい価値を作るためのクックパッド検索チームのプロダクト開発手法

  • 技術、解決策のことはいったん忘れる
    • 技術から発想してプロダクトをつくると失敗しがち
  • ユーザーの悩みや、欲求にフォーカス
    • 「あったらいいね」みたいなものは作らない。「ないと死ぬ」みたいな機能をつくる
  • 欲求から解決策を考え、そこに技術を使う
  • 技術→製品→価値ではなくて、価値→製品→技術の順で考える
  • 週に1~2h程度の時間を取って、技術を抜きにした価値に関する議論をする

「今日なに作ろう?」を支えるデザイン

  • 機能ではなくストーリーで考える
  • ユーザーのどんな問題を解決できるのか
  • プロトタイプで仮説検証
    • イデアの共有
    • エンジニア工数を取らない
  • こういうの作りたい→OK!→最高かよ!
  • デザインもIssue上で議論

確かめながらつくるユーザー体験

いったんサービスの作り方にフォーカスしてメモ。
Rails高速化の話や、DWHの話がくそおもしろかったので
次回あればもっと技術寄りの話も聞いてみたい。

2015年お買い物ランキング

2015年に買ってよかったもの12個書きます

takanamito.hateblo.jp

12位 星野源のアルバム YELLOW DANCER

いま売れ売れの星野源
アルバムとライブDVDの抱き合わせよかった。

Instrumentalの曲とかちゃんと入ってて渋い。
SAKEROCKでまた曲出して欲しい。
ライブの映像あるとニセ明さんの「君は薔薇より美しい」聞けるのでうれしい。

11位 ハイキュー 18/19巻

ハイキュー!! 18 (ジャンプコミックス)

ハイキュー!! 18 (ジャンプコミックス)

ハイキュー!! 19 (ジャンプコミックス)

ハイキュー!! 19 (ジャンプコミックス)

ツッキーが覚醒してる。めっちゃいい。
ウシワカのスパイクをドシャットするとこめっちゃいい。

10位 Wii U + スプラトゥーン

中学の時の初代バトルフロント以来のハマりっぷり。
会社でもやっててめっちゃ楽しい。ボイチャとかないから楽しい。

9位 ビーダマンの電子書籍

発行部数が少ない15巻とか全く見つからなかったので今賀俊先生本当にありがとうございます。
後半で好きなのはフラッシュワイバーンの登場回。タマゴがガンマの背中押すところと、ビー玉半分に割るところが好き。
当時コロコロで読んでてくそテンション上がった。
takanamito.hateblo.jp

8位 イミテーションゲーム

エンジニアはテンション上がるシーンが多い。 劇場でガッツポーズ出そうになった。

7位 仮面ライダークウガ

仮面ライダークウガ(1) (ヒーローズコミックス)

仮面ライダークウガ(1) (ヒーローズコミックス)

なかなか変身せん。超変身せん。アギト出てくる。めっちゃいい。

6位 aiko プラマイ

プラマイ(初回限定仕様)

プラマイ(初回限定仕様)

カップリングの「合図」がいい。
いろいろあったっぽい感じが裏に見え隠れしててめっちゃよかった。
ライブでも「明日もいつも通りに」「なんて一日」歌ってたらしいのでめっちゃ行きたかった。

4位 キングスマン 爆音上映

キングスマン(字幕版)

キングスマン(字幕版)

これ見て高いスーツ買った。
スーツ以外のカジュアルな衣装もかっこいいの多くてすごくいい。
ベタだけど教会の乱闘シーンかっこいい。

4位 キツネとリーボックのコラボスニーカー

クラシック ナイロン アフィリエイト Reebok CLASSIC(リーボック クラシック) [V69742]|Reebok ONLINE SHOP -リーボック オンラインショップ f:id:takanamito:20151231020533j:plain

初めて朝から原宿で並んでスニーカー買っただけあってすごい気に入ってる。
歩きやすいし品もあって好き。

3位 ベッドとマットレス

ヘッドボードに収納満載 引出し付きフレーム(ベガC) | ニトリ公式通販 家具・インテリア通販のニトリネット

すごいQoLが向上した。腰痛かったけど固めのマットレス選んだことで緩和。
セミダブルのベッドにして正解。

2位 スターウォーズ 4DX

見たいやつだいたい見られた。
ミレニアム・ファルコンの登場シーンとか、黒いX-WINGとか最高。

1位 LoopWheelerのスウェット

LW01吊り編み丸胴クルースウェット2015FW f:id:takanamito:20151231015007j:plain

会社の同僚から聞いてまず最初に定番のパーカーを買って
あまりの着心地の良さに感動してスウェットも買ってみたけどこっちも超よかった。
オートミール色なのでやわらかい印象になるし、着心地もパーカーと変わらずふわっとしていて最高。
吊り編み機についていろいろ調べていくうちにがっつりファンになってしまっていた。

お金使うの気持ちいいですね。
来年もたくさん散財したい。

一人暮らしを始めて5年間悩んだ末に見つけた排水口の詰まり対策ソリューション

ついに来た!!!

台所、お風呂場、洗面台と
掃除が嫌いな僕は、長期間掃除をサボって
排水口が詰まってしまうことが多かった。

最近になってお風呂の排水口は
髪の毛キャッチのネットを使い始めて改善。
↓こんなやつ


ただ、台所はどうしても油を使ったあとのフライパンとか
鍋の出汁を捨てたりするときに油が詰まって、どうしようもなくなることが多かった。

そして一度詰まると手が付けられなくてすんごい大変。
パイプユニッシュとか、タブレットタイプのやつとか市販の洗剤けっこう試したけどダメなことが多かった。

んで、こないだたまたま時間あったので
排水口の詰まり対策をネットで調べてたら、だいたいこの商品を使ってる記事にたどりついた。

ピーピースルーF 600g 業務用排水管洗浄剤

ピーピースルーF 600g 業務用排水管洗浄剤

とりあえず一般市民が手に入れることのできる洗剤の中では最強らしい。
その割に値段もべらぼうに高いわけではない。でもさすがに市販のものに比べるとちょっと高い。

というわけで、最近台所が詰まり出してたので
土曜にamazonで買ったら、通常配送なのに日曜に届いたので早速使ってみた。

ボトルの1/4ほどの粉末を台所の排水口付近に撒く。
そこに40~50度のお湯を注ぐ。

すげーしゅわしゅわしてきて、同時に刺激臭。やばい。
この辺、写真撮りたかったけど、流しがリアルに汚いので自重。

1時間ほど待ってから、水流しまくって
薬剤を全部流す。







きれいに詰まりがなくなりました!!!!!!!!!!!

最強ゆえに、取り扱いには少し注意が必要で
マスクと手袋、メガネは必須な感じ。

体感値でも、防具ないとヤバい感じはしてて
肌に直接つくと間違いなくえらいことになるし
マスクしてても鼻にツンとくる感じした。あれはメガネなしで薬剤目に入ったりしたら死にそう。

しばらくはこれで排水口は安心して使えそうです。