vagrantとは
敢えて説明する必要がないくらい有名なツールですが一応、Wikipediaではこのように説明されています。
Vagrant is free and open-source software for creating and configuring virtual development environments. It can be considered a wrapper around virtualization software such as VirtualBox and configuration management software such as Chef, Salt and Puppet.
vagrantはVirtualBoxなど、仮想環境を手軽に扱えるようにするためのrubyで書かれたラッパーソフトですが、プラグインで拡張することでAWSやDigitalOceanなどクラウドのインスタンスまで扱えるようになります。
背景
社内でいまいちクラウド活用が進まないなー、なんでかなーと悩んでいました。使い始めてしまえば便利過ぎるAWSですが、確かに慣れるまではいまいち使い方がピンとこなかったり、マネジメントコンソールのUIが悪いせいで尻込みしてしまったり...
そこで vagrant です。細かいことは気にせずに、ほしいときに瞬時にテスト用のEC2インスタンスを使える環境を整えれば、社内でみんなもっとカジュアルに使い始めるんぢゃないかなーと(安直な発想)
まー、ネタとしてはもう旬な時期は終わってますけど。。
したごしらえ
vagrantからはじめてAWSを使うために最低限、必要なことを説明します。
以降の設定は説明のためだいぶ簡略化してあるので、本格的にvagrantからAWSを使う際は所属している会社や部署の運用ポリシーやセキュリティーポリシー等に従うようにしてください。
AWSアカウントの作成
AWSを使うわけですから、まずはAWSを契約しなければはじまりません。
AWSのアカウントがまだなければこちらから作成します(クレジットカードの登録が必要です)
AWSのはじめ方に関する情報はネットに溢れているので、詳しい手順は割愛します。
アカウントを作成したらAWSマネジメントコンソールにログインします。
リージョンの選択
AWSのリージョンは特別な理由がなければTokyoリージョンを選択します。
以降は Tokyo リージョンで作業する前提で進めます。
vagrantユーザーの作成
IAMの管理画面で vagrant ユーザーを作成します。
その際、以下の情報を確実に控えておきます(特にSecretAccessKeyは後から確認できません)
- AccessKeyId
- SecretAccessKey
vagrantユーザーを作成したら vagrant という権限グループを作成して所属させます。
SelectPolicyTemplateの選択では PowerUserAccess あたりを選んでおけばいいです。
以降は vagrant ユーザーの認証情報を使う前提で進めます。
SecurityGroupの作成
EC2の管理画面からvagrantで利用する専用のSecurityGroupを作成します。
key | value |
---|---|
GroupName | vagrant |
Description | sg-vagrant |
VPC | デフォルトVPC(* が付いてるやつ) |
Inboundはこんな感じで。
Type | Protocol | PortRange | Source |
---|---|---|---|
SSH | TCP | 22 | 0.0.0.0/0 |
HTTP | TCP | 80 | 0.0.0.0/0 |
HTTPS | TCP | 443 | 0.0.0.0/0 |
以降は vagrant というSecurityGroupを使う前提で進めます。
sshキーペアの生成
最後に、EC2の管理画面からvagrantで使う専用のsshキーペアを生成します。
(もちろん、自分で生成したsshキーペアをアップロードして使ってもokです)
KeyPairNameは vagrant と指定します。
生成すると vagrant.pem という名前の秘密鍵をダウンロードできるので、
/Users/ユーザー名/.ssh/vagrant.pem
として保存します。
保存したら、以下のようにPermissionを設定します。
chmod 700 ~/.ssh ;
chmod 400 ~/.ssh/vagrant.pem ;
以降は、この vagrant.pem を使う前提で進めます。
導入
したごしらえが済んだらvagrantを使う準備をしましょう。
環境
作業環境は MacOSX 10.9.2 Mavericks を使う前提で進めます。
vagrantのインストール
公式サイトからインストーラーをダウンロードしてインストールします。
特に躓くことはないと思います。
vagrantプラグインのインストール
vagrantからAWSを操作するにはvagrant-awsというプラグインを利用します。
設定ファイルを個別に管理できるdotenvというプラグインもインストールしておきましょう。
以下のコマンドを実行します。
vagrant plugin install dotenv ;
vagrant plugin install vagrant-aws ;
vagrant plugin list ;
設定
以降は、以下のディレクトリで作業する前提で進めます。
/Users/ユーザー名/vagrant-test
Vagrantfile
vagrantからAWSを操作するための設定ファイルを作ります。
下記のコードを Vagrantfile というファイル名で保存します。
# -*- mode: ruby -*-
# vi: set ft=ruby :
Dotenv.load
# change default provider to digital_ocean
ENV['VAGRANT_DEFAULT_PROVIDER'] = "aws"
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.provider :aws do |provider, override|
override.vm.hostname = "vagrant-test"
override.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"
override.vm.box = "aws"
override.ssh.username = ENV['AWS_SSH_USERNAME']
override.ssh.private_key_path = ENV['AWS_SSH_KEY']
override.ssh.pty = false
provider.access_key_id = ENV['AWS_ACCESS_KEY_ID']
provider.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
provider.keypair_name = ENV['AWS_KEYPAIR_NAME']
provider.region = "ap-northeast-1" # Tokyo
provider.availability_zone = "ap-northeast-1c" # Tokyo
provider.ami = "ami-c9562fc8" # Tokyo Amazon Linux AMI 2014.03 (64-bit)
provider.instance_type = "t1.micro"
provider.instance_ready_timeout = 120
provider.terminate_on_shutdown = false
provider.security_groups = [
ENV['AWS_SECURITY_GROUP'], # sg-vagrant
]
provider.tags = {
"Name" => "vagrant-test",
"Description" => "Boot from vagrant-aws",
}
provider.block_device_mapping = [{
"DeviceName" => "/dev/sda1",
"VirtualName" => "VagrantDisk",
"Ebs.VolumeSize" => "8",
"Ebs.DeleteOnTermination" => true,
"Ebs.VolumeType" => "standard",
#"Ebs.VolumeType" => "io1", # only if you choose PIOPS
#"Ebs.Iops" => 1000, # only if you choose io1
}]
# enable these properties only if you plan not to use Default VPC
#provider.subnet_id = ENV['AWS_SUBNET_ID']
#provider.private_ip_address = "172.31.16.10"
#provider.elastic_ip = true
# enable sudo without tty
# NOTE: setting [ ssh.pty = true ] causes file provisioner fail
provider.user_data = <<-USER_DATA
#!/bin/sh
echo "Defaults !requiretty" > /etc/sudoers.d/vagrant-init
chmod 440 /etc/sudoers.d/vagrant-init
USER_DATA
# disable synced_folder:
override.vm.synced_folder "./", "/vagrant", disabled: true
# provision
# Do whatever you wanna do !!
end
end
.env
続いて、AWSの認証情報を .env というファイルに記述します。
.envはVagrantfileと 同じ場所 に保存します。
以下のテンプレートを編集して使います。
AWS_SSH_USERNAME="ec2-user"
AWS_SSH_KEY=${HOME}/.ssh/vagrant.pem
AWS_ACCESS_KEY_ID="置き換える"
AWS_SECRET_ACCESS_KEY="置き換える"
AWS_KEYPAIR_NAME="vagrant"
AWS_SECURITY_GROUP="vagrant"
#AWS_SUBNET_ID="置き換える"
以上で設定は終わりです。
使い方
では早速、使ってみましょう。
Vagrantfile のある場所に移動して以下のコマンドを実行します。
vagrant up --provider=aws
VagrantfileでVAGRANT_DEFAULT_PROVIDER=aws
を設定しているので--provider=aws
は実は省略可能ですが、ひとつのVagrantfile
で複数プロバイダーに対応させることもできるので、使用するプロバイダーは明示する癖をつけておきましょう。
初回はEC2インスタンスの起動に10分ほどかかるとおもいます。
起動できたか現在のステータスを確認してみましょう。
vagrant status
無事に起動できたらsshでログインしてみます。
vagrant ssh
拍子抜けするほど簡単に使えてしまいましたね?
以下のコマンドを実行しておけばvagrant経由でなくともインスタンスにsshできるようになります。
いちいちPublicIPを調べなくていいので非常に便利です。
# sshの設定をvagrant-testという名前で書き出す
vagrant ssh-config --host vagrant-test >> ~/.ssh/config
# vagrant-testと名前を付けたインスタンスにsshでログインする
ssh vagrant-test
使い終わったインスタンスは 忘れずに 停止または削除しましょう。
# シャットダウン
vagrant halt
# インスタンス削除
vagrant destroy
起動したまま放置プレイすると、インスタンスのタイプによっては死ねます(−人−)チーン
この点だけは、 MAX 注意しましょう!
プロビジョニングしてみる
vagrantからEC2のインスタンスを起動してsshできるようになりました、それも極短時間で!
便利ですね、便利ですがこれだけだと ふぅーん って感じですね。。
それだと残念なので、vagrant up
でプロビジョニングも同時に実行するようにしてみましょう。
shell provisioner
とansibleを組み合わせたサンプルコードを用意しました。
git clone
してからブランチをcheckoutします。
git clone https://github.com/msykiino/codebox.git vagrant-casual-aws ;
cd vagrant-casual-aws ;
git checkout vagrant-casual-aws ;
.env のAWSの認証情報を書き換えます。
これまでの行程をすべてやっていれば、先で作った .env をそのままコピーして使えます。
vim ./.env
認証情報を書き換えたらいざ、実行。
vagrant up --provider=aws --provision
EC2のインスタンスが作成され、nginxとJenkins、munin、GoAccessがインストールされすぐに利用できる状態になっているはずです(t1.microなのでコマンド実行から構築が終わるまで7分少々かかるかもしれません)
vagrant up
が終わったらサーバーのIPアドレスを確認しましょう。
vagrant ssh-config # HostNameの項目のIPアドレスをコピーしてブラウザでアクセス
確認したらブラウザでアクセスします。
# Jenkins
http://IPアドレス/
JenkinsはJettyで起動します。
# munin
http://IPアドレス/munin/
Jenkinsおぢさんとmuninの画面が出てきましたか?
muninが初回起動時に正常に起動しないことがあるようなので、50x
ページが表示されるようならプロビジョニングを再実行することで起動すると思います(これは1分ほどで終わります)
vagrant provision
ブラウザで表示できたらmuninにアクセスしつつGoAccessでリアルタイム解析してみましょう。
vagrant ssh
してサーバーにログインしたら以下のコマンドを実行します。
goaccess -p /etc/goaccess/ltsv.nginx -f /var/log/nginx/munin_access.log
このように、vagrantとAWS、構成管理ツールを組み合わせることで必要な時に、必要な環境を、極短時間で構築することができます。便利すぎて困りますねww
このサンプルはあくまでもサンプルです。
本番環境ではアクセス元の制限や通信の暗号化など セキュリティー対策 をしっかり実施してください。
余談ですが
2014/04/17 現在、先日のSSLのHeartbleedバグに起因して、curlやlibcurlのバージョン7.36.0-2.44
ではhttpsへのアクセスでIllegal instruction
というエラーが発生して正常に処理できません。同じ症状がgit
コマンドでも起きるため、https経由でgit clone
するとリポジトリがクローンできないため、サンプルコードでは暫定対応として意図的にcurlをダウングレードしています。
2014/04/18 現在、curlのパッケージが修正されたのでコードからダウングレード処理を削除しました。
詳しくはこちらのフォーラムを参照してみてください。
落とし穴
設定しているときに幾つか嵌ったポイントがあるので参考まで。
DefaultVPC
複数メンバーいるプロジェクトでは、AWSに各自で独立したインスタンスを作ることが一般的だと思いますが、通常インスタンス毎にグローバルIPが必要になると思います(VPNな環境での運用は除く)。当然、インスタンス毎にElasticIPを割り当てるようなことはしたくないのでPublicIP(PublicDNS)を利用することになるのですがいまの vagrant-aws プラグインでは PublicIPはDefaultVPCに対してしか割り当てができません 。
利用しているリージョンのVPCにDefaultVPCがあるかどうかは、VPC管理画面のYour VPCs
の一覧のDefault VPC
の項目で確認できます。この項目が Yes となっていればそのVPCがDefaulVPCです。
このDefaultVPCは消すこともできますが、 消してしまうともう自分で作ることはできません ので、もし消してしまった場合はこちらのページにあるように、AWSのサポートに連絡してDefaultVPCの復元依頼をするしか手がありません。
ぼくがテストしていたときは、既にTokyoリージョンのDefaultVPCが消されてしまっていたため、どうやってもPublicIPが取得できずに大嵌りしました;;
requiretty
AWSのAmazonLinux
の初期状態では、/etc/sudoers
が以下のような設定になっています。
#
# Disable "ssh hostname sudo <cmd>", because it will show the password in clear.
# You have to run "ssh -t hostname sudo <cmd>".
#
Defaults requiretty
これだとvagrantでssh越しにsudoが実行できないため、最初は以下の設定で対応していました。
override.ssh.pty = true
これは一見、問題なく動作するように見えましたし事実、ssh越しにsudoも実行できました。
しかし、設定を進めるうちにこの設定ではshell provisioner
がうまく動かないことが分かりました。
具体的には、以下のコードは期待通りの動きをしません。
override.vm.provision :file, source: "./provision/files/.gitconfig", destination: "/home/#{ENV['AWS_SSH_USERNAME']}/.gitconfig"
上記のコードは実際エラーにはなりませんが、アップロードしたファイルがlogout
というファイルにリダイレクトされてしまいます。内部の処理までは追っていないのであれですが、結論としてはuser_data
を設定することで回避できます。
provider.user_data = <<-USER_DATA
#!/bin/sh
echo "Defaults !requiretty" > /etc/sudoers.d/vagrant-init
chmod 440 /etc/sudoers.d/vagrant-init
USER_DATA
ちなみに、ネットでは /etc/sudoers
を直接修正しているケースが多いようですが、sudoersの設定は /etc/sudoers.d/
配下の設定ファイルで上書きできるので /etc/sudoers.d/vagrant-init
で !requiretty
を設定しています。
余談ですが、AWSでもec2-user
にパスワードなしのsudo権限を与える設定が /etc/sudoers.d/cloud-init
で設定されています。興味のあるヒトは覗いてみると良いと思います。
まとめ
さて、vagrantからAWSを利用するのがいかに簡単で便利か伝わったでしょうか。
初回の面倒なAWSの設定さえ終えてしまえばいつでも手軽にAWSを利用できるようになります。
プロビジョニングの設定を共通化しておけば、環境差異のない開発環境も即座に用意できます!
もう「ぼくの環境では動くんですけどー」とか言わせません!
プロジェクトの引き継ぎや、プロジェクトに新しいメンバーが加わったときなど、
以下 4つの設定を共有するだけでアプリケーションが動作する環境をすぐにでも共有できます。
- vagrant.pem
- Vagrantfile
- .env
- プロビジョニング設定
もう使わない理由が見当たりませんよね?
これでうちの会社もクラウド利用がもっと活発になってくれればいいんですけどね...