西田雄也と申します. 長女(5)に嫌われているのか3歳の中頃からお風呂に誘うと「お父さんやだ.一人で入る.」と言われます.

本稿の想定読者: Vagrantを使っている方

開発環境を作成するのに便利なVagrantですが,2014-05にリリースされた1.6からはDocker Providerが標準で使えるようになっています.これはVirtualBoxの代わりにDockerを使って同様の環境を用意するもので,VirtualBoxよりもDockerの方が隔離レベルが低い分,仮想環境の構築・起動を短時間で行える利点があります.

筆者は作成したItamaeレシピを動かしたり,レシピの処理結果をServerspecで試験する環境として使っています.

本稿ではそんなVagrantのDocker Providerの使い方を紹介します.

必要なもの

  • Vagrant 本稿では1.8.6を使いました.
  • Docker 本稿では1.12.1を使いました.

Vagrantfileの作成

次のようなVagrantfileを作成します.

# -*- mode: ruby -*-
# vi: set ft=ruby :

ENV["VAGRANT_DEFAULT_PROVIDER"] ||= "docker"
Vagrant.configure(2) do |config|
  config.vm.provider(:docker) do |d|
    d.image = "nishidayuya/docker-vagrant-debian:jessie"
    d.has_ssh = true
  end
end

これは次の設定を行っています.

  • ENV["VAGRANT_DEFAULT_PROVIDER"] ||= "docker": 通常,VirtualBox Provider以外はvagrant up --provider=dockerのように起動します. しかし,このVagrantfileはDocker Providerしか使わないため, vagrant upだけでDocker Providerを使えるようにしています. また,起動時に環境変数VAGRANT_DEFAULT_PROVIDERが 設定されていればそれを尊重するように配慮しています.
  • d.image = "nishidayuya/docker-vagrant-debian:jessie": 使うDockerイメージを設定しています. ここでは公式のDebian JessieのDockerイメージを元にしてDocker Providerのための最小の変更を行ったDockerイメージを指定しています.
  • d.has_ssh = true: sshdが立ち上がるDockerイメージ用の設定です. この指定がないとvagrant provisionが動かせません.

なお,Docker Providerの場合config.vm.boxの指定はしません.

コンテナの起動

いつものようにvagrant upで起動します.

Vagrantにプラグインが設定されていれば同様に動作します. vagrant-cachierプラグインとかおすすめです.

$ vagrant up
Bringing machine 'default' up with 'docker' provider...
==> default: Creating the container...
    default:   Name: try_default_1475227192
    default:  Image: nishidayuya/docker-vagrant-debian:jessie
    default: Volume: /home/yuya/try:/vagrant
    default: Volume: /home/yuya/.vagrant.d/cache/nishidayuya/docker-vagrant-debian-jessie:/tmp/vagrant-cache
    default:   Port: 127.0.0.1:2222:22
    default:
    default: Container created: 394e83cb795eaa03
==> default: Starting container...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 172.17.0.4:22
    default: SSH username: vagrant
    default: SSH auth method: private key
    default:
    default: Vagrant insecure key detected. Vagrant will automatically replace
    default: this with a newly generated keypair for better security.
    default:
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
==> default: Configuring cache buckets...

ログイン

いつものようにvagrant sshでログインできます. /vagrantがマウントされているのも同様です.

$ vagrant ssh

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
vagrant@394e83cb795e:~$

vagrant ssh-configも使えます.

$ vagrant ssh-config > ./ssh-config
$ ssh -F ./ssh-config default

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Sep 30 09:20:24 2016 from 172.17.0.1
vagrant@394e83cb795e:~$

LinuxカーネルCapabilitiesの設定方法

セキュリティ上の理由からDockerコンテナにはデフォルトで様々な制約があります. 詳細はDocker securityにありますが,起動した環境内で実行する内容によっては適切に設定する必要があります.

ウェブアプリケーションの動作環境のような目的では不要かもしれませんが,例えば筆者はiptablesの設定を行うItamaeレシピを書いていたときにDockerコンテナが課す制約のためにiptablesがそのままでは動作しない現象に遭遇しました.

$ vagrant ssh
...
vagrant@394e83cb795e:~$ sudo apt-get install -y iptables
...
vagrant@394e83cb795e:~$ sudo iptables --list
iptables v1.4.21: can't initialize iptables table `filter': Permission denied (you must be root)
Perhaps iptables or your kernel needs to be upgraded.

本節ではiptablesを動かす方法を通して,コンテナの起動パラメータの変更方法を紹介します.

iptablesのようにnetfilterファイアウォールを操作する際はNET_ADMINというLinuxカーネルCapabilitiesが必要になります. そのため,Vagrantfileでコンテナ起動時に--cap-add=NET_ADMINを追加するようにします.

# -*- mode: ruby -*-
# vi: set ft=ruby :

ENV["VAGRANT_DEFAULT_PROVIDER"] ||= "docker"
Vagrant.configure(2) do |config|
  config.vm.provider(:docker) do |d|
    d.image = "nishidayuya/docker-vagrant-debian:jessie"
    d.has_ssh = true
    d.create_args = %w(--cap-add=NET_ADMIN) # ここを追加
  end
end

vagrant destroyしてからvagrant upして反映します. なお,vagrant haltからのvagrant upでは反映されないため,vagrant reloadでも反映されません.

$ vagrant destroy -f && vagrant up && vagrant ssh
...
vagrant@cfa444e40cc9:~$ sudo apt-get install -y iptables
...
vagrant@cfa444e40cc9:~$ sudo iptables --list
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

まとめ

いかがだったでしょうか.

本稿ではDebianのDockerイメージを使いましたが,他にもDocker Hubでdocker vagrant providerあたりの語句で検索すれば様々なイメージが見つかります.