サーバ構築自動化 on aws sqaleの場合
TRANSCRIPT
サーバ構築自動化
(on AWS)
Sqaleの場合
Automation Tech Casual Talks #1Ryo 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 Nodesagentのホスト名を引数で受け取って色々動的に
決定できる。[master]node_terminus = execexterna_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.jp3. 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 kickagentを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力が無かったがための苦肉の策!!
PassengerpuppetmsterdのバックエンドがデフォでWEBrick。つまりシングルスレッド。多数のクライアントが同時に接続してくると、猛烈にコケます。というわけでPassengerに変えました。
http://projects.puppetlabs.com/projects/1/wiki/Using_Passenger
Unicornでもいけるみたいよ。
まとめ
AWS(EC2)は楽しやすい
AWSを使うと楽できる(自動化しやすい)のは確かです。
ですが、AWS側は楽できる仕組みを用意してくれているだけなので、使い方次第ですね。
開発力は必須かと思います。
今後のこと
使っているスクリプト等は公開できる形にしたいと思ったり思わなかったりしてます。
その他、各種バックアップなども自動化していますので、そのあたりはまた機会があればお話したいと思います!
ありがとうございました