AWS OpsWorks (DevOps アプリケーション管理・自動化) | アマゾン ウェブ サービス (AWS 日本語)を利用してサーバの構成管理をしようとしたけど、問題になったのがOpsWorksで使われるChefのバージョン。現時点で9.x系なんだけど(2013/07/25にChef 11のサポートがリリースされてる)、opscodeが公開しているcookbookには結構10.x系以上じゃないと動作しないものが多い。
一々、9.x系で動作するようにcookbookを修正するのも面倒だし、opscodeが公開している沢山のcookbookを利用せずに自前で全部書くというのも避けたい。
chefのgemを最新にするcookbookを作って、それをOpsWorksで実行してChefのバージョンを無理やり切り替えられないかとも考えたけど、OpsWorks内でのchefを含めたgemの管理にBundler使ってるので、その切り替えも難しそう。
ということで、OpsWorksはひとまず置いといて、VagrantとChef使った構成管理にしてみた。
まずVagrantのインストール
Vagrant - Downloadsからプラットフォームにあったものダウンロードしてインストール。
初期化処理
任意のディレクトリで
$ vagrant init
する。するとおなじみのVagrantfileが生成される。
続いてvagrant-aws pluginをインストール
$ vagrant plugin install vagrant-aws
mitchellh/vagrant-aws · GitHubを入れると、AWSがvagrant実行時のプロバイダとして利用可能になる。
AWSを使用するのでVagrantのBoxは本来必要無いんだけど、Vagrantfileに定義しないとエラーになるのでダミーのBoxを用意する。
$ vagrant box add aws-dummy https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box
お次はvagrant-omnibus pluginをインストール
$ vagrant plugin install vagrant-omnibus
schisamo/vagrant-omnibus · GitHubは、Vagrantが使用するBoxにChefがインストールされてない場合に、Chefのインストールをしてくれる。EC2を使うので予めChefをインストール済みのAMIを使うという方法もあるけど、都度そういったAMIをワザワザ作るのも面倒なので、このPluginでChefをインストールする。
cookbookの管理のためBerkshelfをインストール
$ gem install berkshelf
Berkshelfはcookbookの依存関係を考慮して必要なcookbookをopscodeのリポジトリからダウンロードしてきてくれる。(一々手動でcookbookをダウンロードするのは面倒なのでこういうツールは便利)利用するcookbookをBerksfileに↓な感じで定義する。
site :opscode cookbook 'git' cookbook 'database' cookbook 'postgresql' cookbook 'java' cookbook 'tomcat'
あとRiotGames/vagrant-berkshelf · GitHubというpluginを入れるとvagrant up した際に、Berksfileに定義したcookbookを自動的に取得し処理してくれるんだけど、同じディレクトリ内にcookbookが落としてあるほうが内容確認するのに便利なのと、カスタマイズしたcookbookも合わせて利用したいので、今回はインストールしない。
↓のコマンド実行するとcookbooksというディレクトリ内にダウンロードしたcookbookが配置される。
$ berks install --path cookbooks
tty対応
VagrantがChefのcookbookに従ってパッケージをインストールする際、sshで対象サーバに接続しsudoしてインストール処理をするんだけど、この時サーバ側でrequirettyの設定(/etc/sudoers内の)が無効になっていないとエラーになる。Amazon Linuxだとデフォルトではこの設定は無効になっていないので、この設定を無効化した状態でAMIを作るかVagrantのコアの挙動を変更する方法 | Ryuzee.comで紹介されている方法でvagrant側のロジックを修正する必要がある。(Vagrant本家が対応しても良さそうなのにね…)
Vagrantfileの設定
↓な感じで設定。
# -*- mode: ruby -*- # vi: set ft=ruby : Vagrant.configure("2") do |config| # EC2を使うのでboxは使わないんだけど無いとエラーになるのでdummyのBoxを定義 config.vm.box = "aws-dummy" # omnibus pluginでEC2にインストールするChefのバージョンを定義 config.omnibus.chef_version = "11.4.4" config.vm.provider :aws do |aws, override| aws.access_key_id = 'AWSのアクセスキー' aws.secret_access_key = 'AWSのシークレットアクセスキー' aws.keypair_name = 'EC2のkeypair名' override.ssh.username = 'ec2-user' override.ssh.private_key_path = 'aws.keypair_nameで指定したkeypairのファイルパス' aws.instance_type = 'm1.small' aws.region = 'ap-northeast-1' # Tokykoリージョン指定 aws.ami = '使用するAMI' aws.availability_zone = 'ap-northeast-1c' # AZ aws.security_groups = ['適用するAWSのSecurityGroup'] end config.vm.provision :chef_solo do |chef| # berkshelfでDLしたopscodeのcookbooksと個別カスタマイズしたcookbookはsite-cookbooksに配置 chef.cookbooks_path = ["./cookbooks", "./site-cookbooks"] chef.add_recipe "git" chef.add_recipe "postgresql::server" chef.add_recipe "java" chef.add_recipe "tomcat" # cookbook側に渡すカスタムjsonデータ chef.json = { :postgresql => { :dir => '/var/lib/pgsql9/data' }, :java => { :jdk_version => 7, :install_flavor => 'oracle', :oracle => {:accept_oracle_download_terms => true} }, :tomcat => {:base_version => 7} } end config.ssh.max_tries = 40 config.ssh.timeout = 120 end
(JavaとTomcatはソースパッケージの解凍時のエラーとかTomcatの再起動タスクのキューが溜まって予期せぬリターンコードが返ってきてエラーになるのでオリジナルのcookbookをカスタマイズした…)
起動!
準備が整ったらproviderを指定して起動する。ちなみにvagrant-awsは現状reload,resume,suspend,haltといったコマンドにはまだ対応していない。
$ vagrant up --provider=aws
全てエラー出ずに終了するとちょっと感動するw
デバッグ
定義したcookbookが何事もなく全て正常に終了するにこしたことは無いけど、まぁそんな事は無いわけで。エラーが発生した際にちょこっとcookbookを修正してデバッグしてみたくなったりする。でもちょっとした修正を適用するために毎回EC2に起動するのもちょっと…となるので、そういう場合はレシピが実行された後のインスタンスにSSHでログインしてchef-soloで個別にcookbookの適用する方がお手軽。
vagrant upするとcookbook等が/tmp/vagrant-chef-1 に配備される。こののディレクトリ直下のsolo.rbがchef-soloのコンフィグレーションファイルで、dna.jsonにVagrantfileに定義した適用するrecipeやカスタムjsonデータが定義されてる。dna.jsonに定義されてるrun_listを適用したいrecipeだけにしてchef-soloを実行するとちょっとした動作確認がお手軽にできる。
$ sudo chef-solo -c solo.rb -j dna.json
今回はAWSで起動したけど、Vagrantを使った構成だと通常のBoxを使った環境とかでもそのまま適用可能になるのが便利ね。