VagrantとDockerを使って環境に依存せずにChefのお勉強がしたい

# 環境依存ってめんどくさい
昨日とあるchefの勉強会に参加しました。
そこではみんな直ちにchefりたいという気持ちとは裏腹に、環境まわり（特にWindowsユーザー）で詰まってなかなか進まないという問題がありました。rubyのバージョン、パス、sshなど等。。。
なのでまずはお勉強環境を統一するためにvagrantでホストの上にホストとなるゲストを作りましょう。

# ホストでの作業
## 仮想環境の準備
まずはvagrantが動く環境を作ります。windowsの人もMacの人も、[VirtualBox](https://www.virtualbox.org/)と[Vagrant](http://www.vagrantup.com/)をインスコしましょう。これらは各OS毎にインストーラーが提供されているので、問題なく準備できるはずです。

## vagrantでさっくりと

まずはvagrantの作業用ディレクトリを作ります。
`mkdir vagrant
cd vagrant
mkdir share`
んでもってVagrantfileを作ります。vagrantはこのファイルの中身に従って自動で仮想環境を作ってくれます。shareディレクトリは仮想マシンを起動した後で使用するので、追って説明します。

```ruby:Vagrantfile
ip_address = "192.168.10.10"

Vagrant.configure("2") do |config|
  config.vm.box = "CentOS-6.5"
  config.vm.box_url = "http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.5-x86_64-v20140110.box" 

  config.vm.network :private_network, ip: ip_address
  config.vm.synced_folder "share", "/home/vagrant/share"

  config.vm.provision :shell, :path => "provision.sh"
end
```

ipアドレスなどは適当に編集してください。この設定では最低限の設定などを行っているだけで、実際のサーバー設定（プロビジョニング）はprovision.sh内で行っています。

```shell-session:provision.sh
#!/bin/sh

# dockerをインスコする
yum -y install http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
yum -y install docker-io git jq
service docker start
chkconfig docker on
usermod -G docker vagrant

# chefをインスコする
curl -L https://www.opscode.com/chef/install.sh | sudo bash
# knife-soloをインスコする
/opt/chef/embedded/bin/gem install knife-solo -no-ri -no-rdoc

# dockerコンテナにSSHするための準備
cp /vagrant/share/id_rsa.docker /home/vagrant/.ssh/id_rsa
cp /vagrant/share/id_rsa.docker.pub /home/vagrant/.ssh/id_rsa.pub
chown -R vagrant:vagrant /home/vagrant/.ssh
chmod -R g-rwx,o-rwx /home/vagrant/.ssh
```

これは普通のシェルスクリプトです。vagrantを使わずに仮想マシンをセットアップした場合でいうところの、OSのインストール後rootでログインしてこのスクリプトを流すような感じです。vagrantはこれを自動でやってくれます。
provision.shの内容ですが、大きくわけて3つのことをやっています。

* dockerのインストール
* chefのインストール
* dockerへのアクセス準備

です。dockerはこれからchefる対象のゲスト環境を作るのに必要なです。
次にchefのインストールです。インストールにはchefが用意してくれてるomnibusインストーラを使います。
最後にchefが動く対象となるdockerコンテナへのアクセス用設定です。あらかじめshare以下で`ssh-keygen -t rsa`して鍵をつくっておきましょう。
これでvagrantの準備は完了したので、コマンドラインから

`vagrant up`

を実行してください。各種ソフトのインスコに時間がかかりますが、数分後には仮想マシンが立ち上がります。
また、初回に限りOSのイメージをDLするのでそれなりの時間はかかってしまいます。２回め以降はイメージを削除しない限り再利用するので、時間はかなり短縮されます。

## vagrantへssh
お勉強の舞台である仮想環境は起動したので、さっそくsshでログインします。
Vagrantfileで指定したIPアドレスにvagrantユーザーでログインできます（パスワードもvagrant）。
ログインすると、ホームディレクトリにshareというディレクトリがあります（正確にはシンボリックリンク）。この中身が手順の最初で作ったホストのvagrant/shareディレクトリになっています。
実際は/vagrant/shareへのリンクになっていて、vagrantが勝手にホストのvagrantディレクトリを/vagrant以下にマウントしてくれています。そのディレクトリにリンクを張ったものです。
実際にshare以下に適当にファイルを作ると（`date > share/hoge`）ホストにもhogeが作成されていることが確認できます。
ここで作業をすることで、仮想マシンを作り直しても成果物をホストに残すことができます。
あとついでにchef-soloやknifeコマンドが動くことも確認しておいてください。

# docker
次にchefがcookする対象のサーバーを用意します。
share以下にDockerfileを作ります。

```text:share/Dockerfile
FROM ubuntu:14.04

RUN apt-get update && apt-get -y upgrade
RUN apt-get install -y openssh-server chef

RUN mkdir -p /var/run/sshd

RUN useradd -d /home/docker -m -s /bin/bash docker
RUN echo docker:docker | chpasswd
RUN echo 'docker ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers


RUN sed -ri 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config
RUN mkdir -p /var/run/sshd && chmod 755 /var/run/sshd
ADD id_rsa.docker.pub /home/docker/.ssh/authorized_keys
RUN chown -R docker /home/docker/.ssh
RUN chmod -R g-rwx,o-rwx /home/docker/.ssh

CMD /usr/sbin/sshd -D
```

内容はubunt:14.04をベースにapt-getでsshdをインストールし、鍵の設定をしているだけです。頭にRUNやCMDがついてますが、大体は普通のシェルスクリプトですが、apt-getでchefをインストールしておくのと、ADDコマンドでローカル（vagrant）の鍵をdockerコンテナに追加しているのがポイントです。

Dockerfileが準備できたらいよいよコンテナを起動させます。
と、その前に起動するコンテナのイメージを作ります。Dockerfileがあるディレクトリで`docker build test:01 .`を実行します。するとubuntu:14.04をベースにDockerfileで設定した内容にしたがって新たなコンテナイメージ`test:01`を作ってくれます。作ったコンテナは`docker images`で確認ができます。
![1.png](https://qiita-image-store.s3.amazonaws.com/0/35642/8154268c-090a-b57d-ac1c-6bbbee197be0.png)
test:01ができていたらこれを起動します`docker run -d test:01`。
buildに比べてrunはあっさり終わりましたが、これでコンテナが起動しました。
`docker ps
`でtest:01が起動中であることを確認できます。
![2.png](https://qiita-image-store.s3.amazonaws.com/0/35642/c5a6bf9f-fd22-cfca-bccf-0ecc4e23e5bc.png)

## コンテナへのssh
次に起動したtest:01へsshします。まずは対象のIPアドレスを調べます。
`docker ps`でコンテナのIDがわかる（今回の例では`bd1c21e8ecc0`）ので、それに対して`docker inspect bd1c21e8ecc0`を実行します。するとコンテナの情報がjsonでずらずら出てくるので、この中からIPアドレスを調べます。
vagrantにはjqを入れてあるので、`docker inspect bd1c21e8ecc0 | jq ".[0].NetworkSettings.IPAddress"`でipを調べ、.ssh/configにssh設定を行います。

```text:.ssh/config
host docker
        hostname [コンテナのIP]
        user docker
        port 22
        identityfile ~/.ssh/id_rsa
```

パミッションの設定も忘れずに`chmod 700 ~/.ssh/config`しておきます。この状態で`ssh docker`でログインできることを確認します。

# やっとchef
ここまでの作業でホスト環境に依存しないknifeの実行環境（vagrant)と、いつでも作り直せる調理対象(docker)が出来上がりました。
適当な作業ディレクトリを作りdockerに対してknifeを実行してみます。
`mkdir knife
cd knife
knife solo init .
knife solo bootstrap docker
`
knifeが無事に実行されましたか。

## やりなおしたい
chefのテストなどで、一度まっさらな環境からやり直したい場合ときは、コンテナを作り直します。
まずは起動中のコンテナを破棄します。
`docker rm -f bd1c21e8ecc0`
すると`docker ps`がまっさらになるので、`docker run -d test:01`からやり直せます。一度イメージを作った後なので、一瞬でやり直せます。なんどでもお手軽にやり直せるのがdockerのいいところです。

# 最後に
当方がまだchefの勉強お始めたばかりなので、chefの内容については空っぽです。しかし、chefを勉強するための環境は整えれたので、これから勉強を続けていくことができるようになりました。
また、ほかの人の環境でも`vagrant up`するだけで同じ環境を構築できるので、ホストマシンに依存する問題がなくなり勉強だけに集中できるようになりました。

##成果物
ここで作ったものは[github](https://github.com/pepepe/vagrant.git)に上げてあるので、よかったらお使いください。