サーバ構築自動化
 (on AWS)
Sqaleの場合

           Automation Tech Casual Talks #1
           Ryo Kuroda @lamanotrama
           パペボ所属
Agenda
●   サービス紹介
●   puppetのnode管理がだるい
●   名前解決がだるい
●   インスタンス作成がだるい
●   それでもインスタンス作成がだるい
●   puppetの適用がだるい
だるい作業をやっつけるぞー
サービス紹介
Sqale (Closed Beta)
●   http://sqale.jp
●   AWS
●   30インスタンスいかないくらい (EC2+RDS)
●   Amazon Linux 64bit
    ○ 一部のインスタンスはカーネルをいじっている
● Nagiosの運用
    ○ Monitoring Casual Talk #1
    ○ http://d.hatena.ne.
      jp/lamanotrama/20120618/1339988584
puppetのnode管
理がだるい
× node.pp
インスタンスの増減の度に手編集とかやってられ
ない。
 node 'hoge001.sqale.jp' {
   include base
   include xxxx
   include yyyyy
 }

 node 'baa001.sqale.jp' {
   include base
   include zzzz
 }
External Nodes
agentのホスト名を引数で受け取って色々動的に
決定できる。
   [master]
   node_terminus = exec
   externa_nodes = /path/to/script
● http://docs.puppetlabs.com/guides/external_nodes.html
● yamlで出力
   ○ includeするclass
   ○ enviroment (こいつはあんまりあてにならない)
   ○ parameters (トップレベルスコープの変数)
● 言語は問わない
Sqaleの場合はperlで実装
 use Net::Amazon::EC2;
 use JSON;
 use YAML;

puppetクライアントホストのroleタグを取ってきて、
それをincludeするclass名として使う。
補足
運用ルールでサーバの役割をroleタグにJSONの
配列で定義することになっています。

Net::Amazon::EC2::PaperboyAttriburtes は使っ
てない?
$instance->roles() で簡単にroleをArrayRef取れ
るものがあるんですが、このときはまだ作ってな
かっただけです。
名前解決がだるい
特に内部名前解決は必須
ec2インスタンスは停止、起動するとIPが変わるの
で、インスタンス間のやり取りやsshのログインにIP
を使うのは現実的ではない。

しかし、新規作成時や起動の度に手作業でhosts
ファイルやDNSのレコードを更新するなんてのは
やってられない。
/etc/hosts の自動更新
/etc/hosts の自動更新で解決している。

1. 5分毎に各インスタンス上でAWSのAPIを叩くスクリプト
   (hosts-gen.pl)を実行
2. 全インスタンスのName(タグ)とpublic IP、private IPを取得
3. /etc/hosts を生成
   a. スタティックに管理したい情報が /etc/hosts.base にあ
       れば、内容をマージ

  <IP>         <Name>.sqale.jp
  <Private IP> <Name>.sqale.lan
どうしてもDNSサーバが欲しい場合
一部ミドルウェアがhostsを見てくれないので、その
場合だけlocalhostにdnsmasqを立てて、そいつを
使うようにしています
● /etc/hosts は自動更新
● inotifyで監視
  ○ 監視スクリプトはsupervisorでdaemonize
● 更新があればdnsmasqにHUPシグナルを送り最
  新の情報を読み直させる
インスタンス作成が
だるい
サービス投入までの流れ
ざっくりとこれだけある
1.   新規でまっさらなインスタンスを作成
2.   起動したらec2-user(デフォルトユーザ)でログイン
3.   hostnameを設定
4.   最低限必要な内容で/etc/hostsを手編集
5.   puppetのインストール
6.   puppetのconfig設定
7.   puppet agent実行

まーだるい
cloud-init
インスタンス作成時にuser-dataにスクリプトを埋め
込んで、初回boot時に任意の処理を実行できると
いう便利な仕組みを使う。
https://help.ubuntu.com/community/CloudInit

独自のシンタックス(cloud config)でも設定できるけど、sqaleでは
シュルスクリプトで行なっています。
スクリプトでやっていること
1.   AWSのapiを叩いて、自身のNameを取得
2.   hostnameを設定 <Name>.sqale.jp
3.   puppetサーバのIP(apiから取得)とFQDNをhostsに書き込み
4.   puppetのインストール
5.   puppet.confを設定
6.   puppet agent --tags base を実行して基礎構築
7.   hosts-gen.plでhosts生成
これで前述のだるい作業は全て自動化されまし
た。

あとはldap認証でログインして残りの部分(roleに
紐付くpuppet class)を適用すれば出来上がりで
す。

ほぼ特権ユーザであるec2-userでのログインは
余程のことが無い限り行いません。
補足
スクリプトの中でAPIへアクセスするためにセキュリティー証明
書が必要なので、予め証明書を埋め込んだ(だけの)AMIを作っ
ておいて、それを使ってインスタンスをlaunchしています。

ただし、今はそんなことをしなくても IAM roles for EC2
instances を使ってよりシンプルで安全にアクセスができるよう
です(未検証)。
http://aws.typepad.com/aws_japan/2012/06/iam-roles-for-
ec2-instances-simplified-secure-access-to-aws-service-
apis-from-ec2.html
それでもインスタン
ス作成がだるい
ローンチ自体がだるい
以上でインスタンスローンチ後の構築は自動化で
きましたが、そのローンチ自体がわりとだるい。
● インスタンスをローンチするには
  ○ マネジメントコンソールでポチポチポチ…
  ○ ec2-run-instances [オプション沢山沢山…] --user-
    data /path/to/cloud-init-sctipt
● AMIの指定や、Nameやroleタグ、security-group、インスタン
  スタイプ等々設定すべき項目が山ほどある
  ○ 項目が多い -> 間違いを起こしやすい
  ○ 怠惰さがまだ足りないですね
ec2-instance-launcher 作った
これだけ !
  sudo ec2-instaance-launcher <Name>
仕様で決まっていることは全てデフォルトで設定
●   AMI
●   instance type
●   availabability-zone
●   detailed-monitoring on
●   Name tag
●   role tag、secutiry-group は Name =~ /^(w+)d+/
●   user-data (cloud-initスクリプト)
それぞれオプションで上書き可能
更に
● 既存のインスタンスと同Nameのインスタンスは作ら
 せない
 ○ ec2側では制限がないので作れてしまうがそれは避けた
   い
● 実行時にpuppetサーバで同名のホストが認証済み
 な場合は認証情報をリセット
 ○ puppet cert --clean xxx
 ○ インスタンスの作り変え等を行った場合、クライアント証
   明書が違うということで(cloud-init内の)puppet実行が失
   敗してしまうのを回避する為
puppet agent実行
がだるい
運用の話
以上で構築周りは自動化ができました。
次は運用。

manifest等を変更した際のpuppetの適用ってみな
さんどうしてます ?
× agentをデーモン起動
更新の自動適用って怖くていやだ。

却下。
× puppet kick
agentをno-clientモードで起動し、puppetサーバ側
からremoteでagentを実行できる(push型)。
が、いまいち機能が足りない。
● role毎にまとめて実行が出来ない
  ○ --class で指定するにはLDAPでのnode管理が必須
● noop実行(dry-run)ができない
● ログがしょぼい
  ○ puppet agent --test で出力されるようなリッチなログが
    得られない
parappet (parallel puppet)
ガッとまてめて実行で楽をする。
●   perlで実装
●   引数で対象インスタンスのName(タグ)を並べて指定
●   --para Num で並列実行
●   --role XXX で特定roleのインスタンスをまとめて指定も
●   --timeout Num でタイムアウトを指定
●   --noop
●   ログがリッチ、且つファイルにもホスト毎に分けて出力

report-ikachanプラグインを使って、ircにgreenのログが一気に
流れる。テンション上がる!
http://mizzy.org/blog/2012/03/31/1/
parappetの仕組み
1. perlでオプションをパース
2. AWSのapi使ってroleオプション引数から対象インスタンスの
   リストを作成
3. リモートでpuppet --agentを実行するpsshコマンドを組み立
   てる
4. psshをexecしてパラレルでssh接続し、リモートでpuppetを実
   行

perlでオプションパースして、pythonなpsshを実行し、リモートで
rubyなpuppetを実行するという夢のLLコラボレーション!
python力、ruby力が無かったがための苦肉の策!!
Passenger
puppetmsterdのバックエンドがデフォでWEBrick。つまりシング
ルスレッド。
多数のクライアントが同時に接続してくると、猛烈にコケます。
というわけでPassengerに変えました。

http://projects.puppetlabs.
com/projects/1/wiki/Using_Passenger

Unicornでもいけるみたいよ。
まとめ
AWS(EC2)は楽しやすい
AWSを使うと楽できる(自動化しやすい)のは確か
です。

ですが、AWS側は楽できる仕組みを用意してくれて
いるだけなので、使い方次第ですね。

開発力は必須かと思います。
今後のこと
使っているスクリプト等は公開できる形にしたいと
思ったり思わなかったりしてます。

その他、各種バックアップなども自動化しています
ので、そのあたりはまた機会があればお話したい
と思います!
ありがとうございました

サーバ構築自動化 On aws sqaleの場合