Upload
hiboma
View
4.409
Download
4
Embed Size (px)
DESCRIPTION
Citation preview
@hiboma
Sqale のPuppet と Chef
2013年5月10日金曜日
• 伊藤洋也 (いとう ひろや)
• 株式会社 paperboy&co. 6年目氏
• 弟 30年目氏
• 技術基盤エンジニア
• ホスティングの開発業務に関わってる時間が多め
@hiboma
2013年5月10日金曜日
どっちも買って下さい
2013年5月10日金曜日
前置きの話
• レンタルサーバー / ホスティング
• 分譲マンションモデル
• リソースの切り売り
2013年5月10日金曜日
ユーザーで共有されるリソース
システム管理者用リソース
PHP Perl Ruby Python Apache postfix sshd
user A user B user C user D
ユーザーごとのリソース (任意のタイミングで追加/削除)
レンサバ モデルレイヤ
nagios munin fluentd ldap
ftpd
resque
2013年5月10日金曜日
Sqale
2013年5月10日金曜日
2013年5月10日金曜日
2013年5月10日金曜日
http://www.slideshare.net/mizzy/inside-sqales-backend-at-sapporo-ruby-kaigi-2012
Sqaleのバックエンド諸々
2013年5月10日金曜日
* PaaS *
2013年5月10日金曜日
今日の話
• アプリがうごく環境
• 「コンテナ」と呼んでいます
2013年5月10日金曜日
Sqaleのコンテナ
• Rubyコンテナ
• Nginx + Rackアプリ
• PHPコンテナ
• Apache2.4 + PHP-FPM
2013年5月10日金曜日
コンテナの実体
• LXC ( Linux Container )
• chroot + namespace + cgroup
• 仮想化 = 隔離、分離、制限
• プロセスレベルでの仮想化
• chroot な環境を作らないといけない !
• 構成管理だ!
2013年5月10日金曜日
構成管理
• ということで構成管理の話
2013年5月10日金曜日
構成管理
• Sqale は 基本的に Puppet 管理
• appサーバー(Rails)とか
• gitリポジトリ管理サーバーとか
• アプリをビルドする build サーバーとか
• queueサーバー(resque) とか ... etc
• ユーザのアプリを動かすサーバーが特殊
• Puppet と Chef
2013年5月10日金曜日
EC2 Instance
PHP Apache phpenv ruby unicorn nginx
chef-solo で chroot環境chef-solo で chroot環境
ldap munin nagios rbenv kernel cgroup
Puppet の土台
/var/rootfs/ruby/var/rootfs/php
lxc-start lxc-start lxc-start lxc-start
2013年5月10日金曜日
Puppetのレイヤ
• LDAP とか munin とか nagios とか 何かいろいろ
• ログインしてオペできる土台
• カーネルも
• LXC を動かせる土台
2013年5月10日金曜日
Puppet + AWS 自動化
http://www.slideshare.net/lamanotrama/on-aws-sqale2013年5月10日金曜日
Chefのレイヤ
• Puppet の土台の上に
• chroot 環境を chef-solo で作る
• ユーザーごとの環境も chef-solo で作る
• ユーザー追加のタイミングで作る
2013年5月10日金曜日
Chefでchroot環境
• chroot 環境を Chef 管理
• /var/rootfs/php # PHP用
• /var/rootfs/ruby # Ruby用
• chroot してから chef-solo 流す
• レシピは mount --bind してホストOSを参照
• レシピの作り方は慣例通り
• Ruby や PHPに必要なものをガッと入れる
2013年5月10日金曜日
Why Chef ?
• chroot するので ホスト名ベースでレシピを当てられない• なので chef-solo にした• puppet apply でもできるかも
2013年5月10日金曜日
#レンサバあるある
2013年5月10日金曜日
#レンサバあるある
• ユーザを追加する度に環境作成
• アカウントの追加
• ストレージ ($HOME) の作成
• mkdir したり
• uid:gid 変えたり
• パーミッション変えたり
• ミドルウェアの設定追加
• 例) httpd.conf
2013年5月10日金曜日
#ホスティングあるある
• たんぽぽ作業
• chef-solo で作ろう
2013年5月10日金曜日
ユーザー作成
user node.username do action :createend directory "/var/www/#{node.username}" do owner node.username group node.username action :create mode "0755"end template "/etc/httpd/conf.d/#{node.username}.conf" do notifies :restart, "service[httpd]" source "httpd.conf.erb" owner "apache" group "apache" mode "0644"end service "httpd" do action :restartend
{ "username": "sushi",}
attribute/sushi.json
2013年5月10日金曜日
ユーザー作成
• attributeで変数を注入 *1
• ユーザー名を変えて環境複製
• べき等性 = 上書き、やり直しも簡単
(注) 任意の値を入れると死ぬので要バリデート
2013年5月10日金曜日
ユーザー削除
• 消す時にも便利
• べき等性が効いてくる
user node.username do action :removeend directory "/var/www/#{node.username}" do action :deleteend file "/etc/httpd/conf.d/#{node.username}.conf" do notifies :restart, "service[httpd]" action :deleteend service "httpd" do action :restartend
2013年5月10日金曜日
chef-solo -j <URL>• でも attribute ファイル作るの面倒じゃないですか ...
• chef-solo -j <URL> 便利 そう
$ sudo chef-solo -j http://chef-api.example.com/user/fuga
chef-api.example.com
ユーザ収容のサーバーs
① kick
② chef-solo
2013年5月10日金曜日
Sqale
• sqale でも ユーザごとに attribute を作って管理
2013年5月10日金曜日
コンテナ作成のchef-solo
{ "run_list": [ "role[create_container_ruby]" ], "sqale": { "consecutive_number": "1", "container_id": "1", "port_offset": "0", "project_name": "ruby", "role": "ruby", "username": "namahage" }}
$ sudo chef-solo -j namahage_sqale_1.json
• Resqueワーカーが chef-solo
attribute/namahage-ruby-1.json
2013年5月10日金曜日
仕様変更
• 仕様変更したい場合も chef-solo
• 1. レシピ更新
• 2. chef-solo 再度実行
• 3. コンテナのプロセスを再起動
• 4. 仕様 update !
• ユーザ名に依存しちゃうような仕様を変える際に便利
2013年5月10日金曜日
DSL
• #{node.key.value} と埋め込むのはイマイチ
• ふつうのRubyのコードっぽくなるし ...
• 内部DSLを逸脱するので若干 BK な匂い
2013年5月10日金曜日
DSL
• ラップするクラスを入れてキレイに
• "define" でラップするのも良いですかね
directory lxc.userfs_root "/home/sqale/current" do owner "sqale" group "sqale" mode "0755" recursive true action :createend
directory "/var/sqale/namahage/ruby/1/home/sqale/current"
after
2013年5月10日金曜日
• puppet apply でもできそう ?
• antipopさん お願いします
2013年5月10日金曜日
混ぜるな危険 !!!!1
• Puppet と Chef が混在 していましたが ...
• 管理しているスコープが違うのでOK
• 特殊事例
2013年5月10日金曜日
#テスト
2013年5月10日金曜日
#テスト
• 「Puppet, Chef」でプロビジョニング しました!!」
• 期待通り動くのかな ?
• 手作業で確認するの ?
• 変更する度に ?
2013年5月10日金曜日
Infrastructure as Code
• コード書いたらテストですよねー
2013年5月10日金曜日
#あるある
• パッケージの追加が怖い
• パッケージのアップデートが怖い
• パッケージの削除が怖い
• 設定追加が怖い
• 設定変更が怖い
• 設定削除が怖い
• 意図しないところで不具合
2013年5月10日金曜日
#あるある
• 振る舞いが把握できてないとこわい
2013年5月10日金曜日
#テスト
• 振る舞いをテスト = 動く仕様
• 「あれ、この設定なんだったかな...」
• テストで思い出す
• require "serverspec"
• Puppet, Chef のリファクタリング
• 振る舞いを保証して マニフェスト/レシピをいじる
2013年5月10日金曜日
EC2 Instance
PHP Apache phpenv ruby unicorn nginx
Chef の chroot環境Chef の chroot環境
ldap munin nagios rbenv kernel cgroup
Puppet の土台
/var/rootfs/ruby/var/rootfs/php
lxc-start lxc-start lxc-start lxc-start
2013年5月10日金曜日
Sqaleのテスト
• 1. chef-solo で LXCの作成/起動
• 2. LXCの外からプロセスが起動しているかテスト
• nginx, unicorn, supervisord, sshd, syslogd ...
• 3. SSHでログイン、コンテナでRSpecを実行
• 4. chef-soloで LXCの停止/削除
2013年5月10日金曜日
RSpecの中味
• ユーザーさんの行動を模擬テスト
• SSHログインできる?
• /etc/init.d/nginx で操作できる?
• Rails動く? Sinatra動く?
• bundle install できる?
• シェルコマンド使える?
• ログ見れる?
• cron 動いてる ?
• セキュリティ制限効いてる?
• cgroupのリソース制限効いてる?
2013年5月10日金曜日
RSpec / Railsの例
describe "rubyコンテナでRailsをUnicornで動かす" do
before(:all) do system("/etc/init.d/rails stop") end it "アプリケーション /home/sqale/current に配置することができること" do
system("tar xfz /home/sqale/rspec/misc/rails_app.tar.gz").should be_true system("rm -rf /home/sqale/current").should be_true system("mv rails_app /home/sqale/current").should be_true
end it "Railsを /etc/init.d/rails で 起動することができる" do
system("/etc/init.d/rails start").should be_true end it "HTTPリクエストを出して200が返ってくること" do
response = http_get response.code.should == "200" response.body.should == "hello,world" end end
2013年5月10日金曜日
RSpec / rbenvの例
%w{ 2.0.0-p0 2.0.0-preview1 1.9.3-p327 1.9.3-p286 1.9.3-p194 }.each do |version| context "rbenv で #{version} に切り替える場合に" do
it "バージョン切り替えできていること" do
rbenv_global(version) end it "rubyのパスが通っていること" do
system("which ruby >/dev/null").should be_true end it "irbのパスが通っていること" do
system("which irb >/dev/null").should be_true end it "gemsのパスが通っていること" do
system("which gem >/dev/null").should be_true end it "bundlerのバージョンが #{@bundler_version} であること" do
`bundle -v`.split[2].should == @bundler_version end end
2013年5月10日金曜日
RSpec / PHP Pearの例
describe "phpコンテナのpear" do
it "pearでライブラリをインストールできること" do
system("pear install Numbers_Roman").should be_true end it "pearでインストールしたライブラリを読み込めること" do
File.write("numbers_roman.php", <<'....')<?php require_once 'Numbers/Roman.php'; $roman = new Numbers_Roman();echo $roman->toNumeral(1);.... `php numbers_roman.php`.chomp.should == "I" end end
2013年5月10日金曜日
#お問い合わせあるある
• 「○○コマンドは使えますか?」
• 「○○ライブラリは使えますか?」
• 確認作業 => テストで残しておく
• サポートした仕様がデグレードしないようにする
2013年5月10日金曜日
#テスト
• 「○○できない」こともテスト
• su, sudo できないとか
• LXC を reboot できないとか
• forkbomb 対策できてるかとか
• されると困るアクションをテスト
2013年5月10日金曜日
Rspec / ○○できない it "/var/log/messagesを読み込めないこと" do expect { File.read("/var/log/messages") }.to raise_error(Errno::EACCES) end it "/var/log/secureを読み込めないこと" do expect { File.read("/var/log/messages") }.to raise_error(Errno::EACCES) end
it "cgroup の fork.remaing で fork bomb対策が施されている" do
# forkbomb するワンライナー system "perl -e 'for(0..255){$i = fork;exit 255 unless defined $i;$i == 0 && sleep 1 && exit 0; }'" $?.success?.should be_false end
context "カーネルの制限で sqaleユーザーはポートをbindできない" do
it "httpdの予約ポート 8000 ~ 10000 をbindできない" do (8000..10000).each do |port| expect { TCPServer.open(port) }.to raise_error(Errno::EACCES) end end
2013年5月10日金曜日
#テスト
• 手続きをRSpec化
• 一般ユーザ権限で実行 = ユーザーの取れる行動
• パッケージの有無とかは見てない
• ホスティングだと価値高いテスト
2013年5月10日金曜日
SqaleのJenkins
• Jenkins で毎日 LXC のテスト
• yum も毎回 update
• RSpecが通る = 振る舞い保証
2013年5月10日金曜日
終わり
2013年5月10日金曜日