Tech-Circle #2: Vagrant+Dockerを使って環境を簡単に作るハンズオン勉強会資料

## 第1セッション: Vagrantでローカルに仮想マシンの構築

### □ Vagrantにboxを追加

インターネット経由でダウンロードして追加する場合

```shell-session
> vagrant box add ubuntu https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box
```

USBメモリからコピーして追加する場合

```shell-session
USBメモリにあるtrusty-server-cloudimg-amd64-vagrant-disk1.boxをローカルにコピー
> vagrant box add ubuntu trusty-server-cloudimg-amd64-vagrant-disk1.box
```


### □ Vagrantfileを生成

```shell-session
> mkdir vagrant-ubuntu
> cd vagrant-ubuntu
> vagrant init ubuntu
```

上記で追加したboxを利用して起動するためのVagrantfileを初期作成

### □ Vagrantfileを編集

編集箇所

* private networkの設定
* 仮想マシンリソースの設定
* ホストOSとのディレクトリ共有設定

```rb:Vagrantfile
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "ubuntu"
  config.vm.network "private_network", ip: "10.2.2.2"
  config.vm.provider "virtualbox" do |vb|
     # vb.customize ["modifyvm", :id, "--memory", "1024"]
     vb.memory = 1024
  end
  config.vm.synced_folder "data", "/tmp/host_dir"
end
```

### □ ゲストVMにマウントさせるディレクトリを作成

```shell-session
Vagrantfileがあるディレクトリ内で以下を実行
> mkdir data
```

### □ 仮想マシンを起動

```shell-session
> vagrant up
```

### □ 仮想マシンに接続

```shell-session
> vagrant ssh
```

以下の情報でログイン
公開鍵認証がうまく通れば以下のユーザ認証は必要なし。

* ユーザ名: vagrant
* パスワード: vagrant

### □ 仮想マシンの中の設定を確認

```shell-session
$ ifconfig
```

2つのネットワークが生成されていることを確認
NATのネットワークとホストオンリーネットワーク

指定したディレクトリがマウントされていることを確認

### □ ホストとVM間のファイル共有確認

VM内のマウントディレクトリ(/tmp/host_dir)に1つファイルを書き込み、ホスト側で確認できることを試す

## 第2セッション: Vagrantで複数Dockerコンテナを一括構築

### □ Dockerをインストール

```shell-session
$ sudo apt-get update
$ sudo apt-get install docker.io
```

### □ Dockerコンテナイメージをpull

```shell-session
$ sudo docker pull ubuntu:14.04
```
Ubuntuのコンテナイメージを登録
ホストVMと合わせる形でバージョン指定して取得(全て取得すると通信量が多くなるので)

### □ 手動でコンテナを起動してみる

```shell-session
$ sudo docker run -i -t ubuntu:14.04 /bin/date
```

時刻表示がされて、コンテナが終了すればOK

```shell-session
$ sudo docker ps -a
```

### □ DockerホストVM上にvagrantユーザで操作できるよう設定

VagrantからDockerを操作する際、vagrantユーザでdockerコマンドの実行を試みる。
その際、dockerがsocketモードで稼働しているとソケットへのアクセス権限不足で弾かれるためvagrantユーザがソケットファイルを読み込めるようdockerグループに割り当て。

```shell-session
$ ls -la /var/run/docker.sock
srw-rw---- 1 root docker 0 Dec 22 02:07 /var/run/docker.sock
$ sudo usermod -G docker vagrant
```

### □ ホストOS上でVagrant + Docker構築用の準備

####□ ディレクトリ作成

vagrant-ubuntuと同じ階層にvagrant-dockerディレクトリを作成

```shell-session
> cd ../
> mkdir vagrant-docker
```

####□ コンテナを自動起動するためのDockerfileを作成

下記のDockerfileをvagrant-dockerディレクトリに配置

```shell-session:Dockerfile

FROM ubuntu:14.04
MAINTAINER Daisuke Ikeda <dai.ikd123@gmail.com>

## Install packages ##
RUN apt-get update
RUN apt-get install -y openssh-server
RUN mkdir /var/run/sshd

## Setup login user ##
RUN useradd docker
RUN echo "docker:password" | chpasswd
RUN echo "docker ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/docker

## Setup sshd config ##
RUN sed -ri 's/UsePAM yes/#UsePAM yes/g' /etc/ssh/sshd_config
RUN sed -ri 's/#UsePAM no/UsePAM no/g' /etc/ssh/sshd_config

## Start sshd ##
RUN service ssh start

## Open Port ##
EXPOSE 22

## Set entrypoint ##
CMD [ "/usr/sbin/sshd", "-D" ]
```

#### □ Vagrantfileを作成

下記のVagrantfileをvagrant-dockerディレクトリに配置

```rb:Vagrantfile

Vagrant.configure(2) do |config|
  config.vm.define "dev1" do |dev|
    dev.vm.provider "docker" do |d|
      d.vagrant_vagrantfile = "../vagrant-ubuntu/Vagrantfile"
      d.build_dir = "."
      d.name = "dev1"
    end
    dev.ssh.username = "docker"
  end
end
```

### □ ホストVM+コンテナの起動

```shell-session
> vagrant up
```

注意：vagrantのバージョンが1.7未満の場合には、以下のようにプロバイダがdockerであることをコマンドライン上から指定しないとデフォルトでvirtualboxプロバイダで起動しようとし、boxの指定がないとエラーになる。

```shell-session:error
There are errors in the configuration of this machine. Please fix
the following errors and try again:

vm:
* A box must be specified.
```

```shell-session
> vagrant up --provider=docker
```

### global-statusの確認

コンテナおよびhost vmのかどう状況の確認

```shell-session
> vagrant global-status
```

### □ コンテナにログイン

```shell-session
> vagrant ssh dev1
ホストVMのログイン→コンテナのログインを実施
```
パスワードはpassword

### □ コンテナを削除

```shell-sessino
> vagrant destroy dev1
```

### □ 複数コンテナを一括作成

複数コンテナ作成できるようVagrantfileを修正

```rb:Vagrantfile

Vagrant.configure(2) do |config|
  config.vm.define "dev1" do |dev|
    dev.vm.provider "docker" do |d|
      d.vagrant_vagrantfile = "../vagrant-ubuntu/Vagrantfile"
      d.build_dir = "."
      d.name = "dev1"
    end
    dev.ssh.username = "docker"
  end

  config.vm.define "dev2" do |dev|
    dev.vm.provider "docker" do |d|
      d.vagrant_vagrantfile = "../vagrant-ubuntu/Vagrantfile"
      d.build_dir = "."
      d.name = "dev2"
      d.link("dev1:dev1")
    end
    dev.ssh.username = "docker"
  end
end
```

### □ 複数コンテナを一括起動

```shell-session
> vagrant up --no-parallel
```

### □ コンテナ間接続の確認

dev1コンテナに接続してdev2の名前解決ができないことを確認

```shell-session
> vagrant ssh dev1
$ ping dev2
ping: unknown host dev2
```

dev2コンテナに接続してdev1の名前解決ができることを確認

```shell-session
> vagrant ssh dev2
$ ping dev1
PING dev1 (172.17.0.17) 56(84) bytes of data.
64 bytes from dev1 (172.17.0.17): icmp_seq=1 ttl=64 time=0.057 ms
```

Dockerのlink機能で/etc/hostsが書き換えられていることを確認

```shell-session
$ cat /etc/hosts
172.17.0.18     1b06f142b5ed
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.17     dev1
```

以上。


## 追加課題

### □ Shell provisionerを使ってDocker自動インストール

セッション2の冒頭で手作業でインストールしたDockerをVagrantのShell provisionerを使って自動インストールしてみます。
セッション1で作成したvagrant-ubuntu/Vagrantfileを以下の内容に変更してあらためてubuntu仮想マシンを作成。

```rb:Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

$script = <<SCRIPT
sudo apt-get update
sudo apt-get -y install docker.io
sudo docker pull ubuntu:14.04
sudo usermod -G docker vagrant
SCRIPT

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "ubuntu"
  config.vm.network "private_network", ip: "10.2.2.2"
  config.vm.provider "virtualbox" do |vb|
     #vb.customize ["modifyvm", :id, "--memory", "1024"]
     vb.memory = 1024
  end
  config.vm.synced_folder "data", "/tmp/host_dir" 
  config.vm.provision "shell", inline: $script
end
```
これにより手作業なしに全て自動化可能。

## ハンズオンで利用したVagrantfile,Dockerfile公開先

https://github.com/ike-dai/tech-circle/tree/master/vagrant%2Bdocker