FURYU Tech Blog - フリュー株式会社

フリュー株式会社の開発者が技術情報を発信するブログです。

Packer+Chef-SoloでAMI作り

こんにちは。 自称Chef導入委員長の国平です。
立て続けの投稿になってしまいますが、今回はPackerの紹介記事を書かせて頂きます。

仮想マシンイメージの作成ツールであるPackerがChef-Soloからのマシンイメージ作成に対応しました。 今回は、その機能を利用して、AWSのEC2 AMIを作成してみます。

Packerとは

仮想環境のマシンイメージを作ってくれるツールです。 一つの設定を元に複数のプラットフォームに対してマシンイメージを作成出来ます。 シェルスクリプトやChef-Soloを使ってマシンイメージを構築します。

ChefやAnsibleの様なプロビジョニングフレームワークはマシン環境の構築にとどまらず、EC2の操作などかなり幅広く利用出来ます。反面、それらのツールで実行する役割を増やすほど設定が複雑化してしまいます。しかし、Packerを利用するとマシンイメージの作成をPackerにまかせることができ、ユーザはマシン設定に集中する事が出来ます。

Packerの利点

Packerを利用する事で以下のメリットを得られます。

  • インフラ構築の高速化
  • 複数プロバイダー間の連携
  • テスタビリティの確保

インフラ構築の高速化

Packerを利用する事で、そのマシンイメージの作成コストを下げることができ、マシンイメージを起動するだけで、利用可能な環境を手に入れる事が出来ます。

複数プロバイダー間の連携

PackerはAWS, VirtualBox, VMWareなど複数のプラットフォームに対応しています。Packerの設定一つで、AWSとローカルマシンの両方に同じ設定を行ったマシンイメージを作成する事が出来ます。 それぞれのプラットフォーム間の違いは、Packerが吸収してくれるので、最終的なマシンイメージを統一して用意する事が出来ます。

テスタビリティの確保

Packerを使う事で上記のように複数のプラットフォームにマシンイメージ作成できます。 そのため、一つの環境でテストを行う事で、他の環境が期待される結果になっている事を保証されます。

気に入った機能

個人的に気に入った機能が、fixコマンドです。 Packerがバージョンアップした際に、古いバージョンのJSONを新バージョンに変換してくれます。 変換結果は、標準出力に吐き出されるので、Linuxであれば以下のコマンドで、最新のJSONを取得できます。

]# packer fix old.json > new.json

一度書いた設定が動くことが保証される、もしくは、容易に動く状態にできるというのは、運用が長期化したり、運用するサーバ設定が複数ある場合に非常に助かると思います。

インストール

UNIX/Linuxでは、~/packerもしくは/usr/local/packerにインストールすることが推奨されています。 インストールするためには、公開されているzipファイルをhttp://www.packer.io/downloads.htmlからダウンロードし、解凍しパスを通します。

Linuxマシンに対してインストールを行うには以下のコマンドを実行します。 ご利用の環境に応じて、適宜ダウンロードURLは変更してください。

]# curl -L -o packer.zip https://dl.bintray.com/mitchellh/packer/0.3.6\_linux\_386.zip 
]# mkdir /usr/local/packer 
]# unzip -d /usr/local/packer packer.zip 
]# export PATH=$PATH:/usr/local/packer

正常にインストールが完了し、パスが通っていれば、packerコマンドを実行すると以下のように、表示されます。

]# packer 

usage: packer [--version] [--help] <command> [<args>] 
Available commands are: build build image(s) from template
fix fixes templates from old versions of packer inspect see 
components of a template validate check that a template is 
valid Globally recognized options: -machine-readable 
Machine-readable output format. 

Macの場合は、Homebrewを使ったインストールも可能なようです。 詳しくは、公式サイトを参照してください。

とりあえず使ってみる

Packerを使って、NginxをインストールしたAWSのAMIを作成してみます。 まずは、以下のJSONを作成します。

ami-shell.json

{
  "builders": [{
    "type": "amazon-ebs",
    "region": "us-west-2",
    "source_ami": "ami-de0d9eb7",
    "instance_type": "t1.micro",
    "ssh_username": "ec2-user",
    "ssh_timeout": "5m",
    "ami_name": "Packer-{{timestamp}}",
    "access_key": "YOUR_ACCESS_KEY",
    "secret_key": "YOUR_SECRET_KEY"
  }],
  "provisioners": [{
    "type": "shell",
    "inline": ["sudo yum install -y nginx"]
  }]
}

builders には、どの様なマシンイメージを作成するかを設定します。 今回はAMIに設定するために typeamazon-ebsにし、resionなどの設定をしています。 access_key, secret_keyは、それぞれAWSアカウントで作成して入力します。

provisioners には、作成するマシンイメージに対して行う処理を設定します。 まずは、Packerの動作を確認するために、typeにshellを指定し、シェルスクリプトを実行してNginxをインストールしてみましょう。

JSONを作成したら以下のコマンドを実行します。

]# packer build ami-shell.json

これでAMIの作成が開始されます。 AWSのConsoleから、EC2が起動する事が確認出来ると思います。 EC2が起動すると、provisionersで指定した通りのシェルが実行されます。 yumコマンドが実行されNginxがインストールされると、AMIの作成に入ります。 最終的にAMIが作成されると起動したEC2インスタンスはterminateされます。 ami_nameに指定したように、”Packer-“後にタイムスタンプが追加された名前のAMIが作成されます。

ProvisionarsにChef-Soloを利用する

Packerのバージョン0.3.6からProvisionersにChef-Soloを指定出来るようになりました。

Packer|ChangeLog

下準備 – 実行するChef Recipeを用意する

まずはChefRepositoryを用意します。 今回のお題もまたまたNginxをソースからインストールします。 レシピの準備を手軽に実施するために、Berkshelfを利用してChefRecipeを取得します。 Berkshelfについては、以前の記事や、以前の発表資料で紹介しています。

]# mkdir packer-sample
]# cd packer-sample
]# berks init
]# mkdir site-cookbooks

Berksfile

site :opscode

cookbook "nginx"
]# berks -p ./site-cookbooks/

これで、site-cookbooks内にNginx Recipeと、Nginx Recipeが依存するRecipeが用意されます。 実行後はpacker-sampleフォルダ内は以下の状態になっていると思います。

packer-sample
├── Berksfile
├── Berksfile.lock
├── Gemfile
├── Gemfile.lock
├── Thorfile
├── Vagrantfile
├── ami-packer.json
└── site-cookbooks
    ├── apt
    │   └─ ...
    ├── build-essential
    │   └── ...
    ├── nginx
    │   └── ...
    ├── ohai
    │   └── ...
    ├── runit
    │   └── ...
    └── yum
        └── ...

Packer設定ファイルの用意

Chefリポジトリが用意出来たので、次にPackerの設定ファイルを記述します。 今回は、EC2 AMI を作成するので、以下のようなファイルを作成します。

ami-chef.json

{
  "builders": [{
    "type": "amazon-ebs",
    "region": "us-west-2",
    "source_ami": "ami-de0d9eb7",
    "instance_type": "t1.micro",
    "ssh_username": "ec2-user",
    "ssh_timeout": "5m",
    "ami_name": "Packer-{{timestamp}}",
    "access_key": "YOUR_ACCESS_KEY",
    "secret_key": "YOUR_SECRET_KEY"
  }],
  "provisioners": [{
    "type": "chef-solo",
    "cookbook_paths": ["./site-cookbooks/"],
    "run_list": ["recipe[nginx::source]"],
    "json": {
      "nginx" : {
        "path" : "/usr/local/nginx"
      }
    },
    "prevent_sudo": false,
    "skip_install": false
  }]
}
]# packer build ami-chef.json

provisioners には、Chef-Soloを利用するので、typechef-soloを指定し、cookbookのパスや、run_list、attributeを書いたJSONフィールドを設定しています。

まとめ

実は以前にPacker+Chef-Soloと同じ事をしてくれるフレームワークを自作してたりしてました。(ec2_automation)

しかし、当たり前ですがPackerの方がずっと使いやすいです。

  • 複数のプラットフォームに対応
  • Chef-Solo以外のProvisionerも利用可能

など、Packerの優位な点が非常に多くあります。 非常に素性がよく、設定も書きやすいので環境構築の自動化と高速化に取り組まれている方々にはPackerは非常にお勧め出来るツールです。

つい先日バージョン0.3.7がリリースされ、新たにPuppetをProvisionerとして利用出来るようになりました。 開発が活発でこれからどんどん便利になって行く事が期待出来ます。