Docker on Vagrant on Ubuntu on VirtualBoxのLAMP(LAPP)開発環境を構築する
動機
普段はWindows7+VirtualBox+VagrantでLAMP(LAPP)開発環境を構築しているのですが、VMが増えてディスクを圧迫してきたので、Docker on Vagrant on Ubuntu on VirtualBoxで開発環境を軽量化してみたいと思います。ここでは、Vagrantを使用する感覚でDockerを使えることを目標とします。
なお、開発環境の構築を目的としているため、本番環境でDockerを利用することは想定してません。
前提
- VirtualBoxでVMを1台構築してそれ上にUbuntu+Vagrant+Dockerを構築します
- VMにはネットワークアダプターを2個つけます
- アダプター1: NAT
- アダプター2: ホストオンリーアダプター
- Dockerのコンテナにはホストオンリーアダプター経由でアクセスするものとします
- そのためホスト以外のマシンからはアクセスできません
- ホストオンリーアダプターのネットワークは192.168.77.0/24とし、IPアドレスに192.168.77.200を割り当てます
- DockerのコンテナにはホストオンリーアダプターのIPエイリアスを割り当てていきます
- なお未確認ですが、ホストオンリーアダプターの替わりにブリッジアダプターにするとホスト以外のマシンからもアクセス可能にすることもできると思います
- VMにはUbuntu 14.04をインストールします
- CentOS 7.1でもチャレンジしましたがdevice mapperの性能が悪かったのでaufsのUbuntuを選びました
- Ubuntu上に「dockeruser」という作業用ユーザを作成してそのユーザでVagrantとDockerを利用します
- LAMP(LAPP)環境構築にはプロビジョニングツールのAnsibleを利用します
- 確認した環境はWindows7+VirtualBox 4.3.28、確認した日付は2015年8月31日です
手順
1. Ubuntu 14.04 Serverのインストールイメージファイルのダウンロード
以下のサイトからインストールイメージファイル(ubuntu-14.04.3-server-amd64.iso)をダウンロードしておきます。
2. VirtualBoxでVMを作成
まず、今回の環境用にホストオンリーアダプターを新たに追加します。VirtualBoxマネージャーから環境設定を開きます。ネットワークのホストオンリーネットワークでホストオンリーネットワークを追加するボタンで、アダプターを追加します。
追加したアダプターを選択して以下のようにDHCPをオフにしたネットワーク設定を行います。(※ネットワークアドレスは各自の環境に合わせて調整してください。)
設定したら環境設定を閉じます。
次に、VMを新規作成します。ここでは「docker」という名前で作成します。OSはUbuntu 64bitを選択します。
メモリーサイズは各自の環境に合わせて調整してください。ここでは512MBで進めます。
仮想ハードドライブを作成します。
ここではVDI形式で20GBの可変で設定します。各自の環境に合わせて調整してください。
VMを作成したら、起動する前に一部設定を変更します。
まず、システムの起動順序のフロッピーのチェックをはずし、ポインティングデバイスをPS/2 マウスに変更します。
次に、ストレージのCD/DVDドライブでUbuntu 14.04のインストールイメージファイル(ubuntu-14.04.3-server-amd64.iso)を選択します。
次に、オーディオを無効化します。
次に、ネットワークでアダプター2を有効化してホストオンリーアダプターを選択します。この際、先ほど追加した方のアダプターを選択します。
最後に、USBでUSBコントローラを無効化します。
(オプション)NATの設定変更
VirtualBoxはNATにデフォルトで10.0.2.0/24のネットワークを割り当てます。このネットワークアドレスを変更する必要がある場合は、VBoxManageコマンドを使用します。Windowsではコマンドプロンプトを起動して以下のようにすると、ネットワークアドレスを192.168.156.0/24に変更できます。
"C:\Program Files\Oracle\VirtualBox\VBoxManage" modifyvm "docker" --natnet1 "192.168.156/24"
また、ノートPCなどを使用していてホストのネットワークが無線などで切り替わりやすい環境の場合は、以下の設定を行うことでゲストのDNSの設定変更が必要なくなります。
"C:\Program Files\Oracle\VirtualBox\VBoxManage" modifyvm "docker" --natdnsproxy1 on
3. Ubuntu 14.04 Serverのインストール
作成したVMを起動してインストールしていきます。
最初は言語を選択します。カーソルキーで日本語を選んでエンターキーを押して次に進みます。
Ubuntu Serverをインストールを選択して状態でエンターキーを押して次に進みます。
カーソルキーでJapaneseを選択してエンターキーを押して次に進みます。
「はい」を選択したままエンターキーを押して次に進みます。
「日本」を選択したままエンターキーを押して次に進みます。
「いいえ」を選択したままエンターキーを押して次に進みます。
「日本語」を選択したままエンターキーを押して次に進みます。
「日本語」を選択したままエンターキーを押して次に進みます。
「eth0」を選択したままエンターキーを押して次に進みます。
ホスト名はここでは「docker」に変更してエンターキーを押して次に進みます。
ここでは「dockeruser」と入力してエンターキーを押して次に進みます。
「dockeruser」と入力されているのでそのままエンターキーを押して次に進みます。
dockeruserのパスワードを適切に設定してください。エンターキーを押して次に進みます。
「いいえ」を選択したままエンターキーを押して次に進みます。
「はい」を選択したままエンターキーを押して次に進みます。
「ディスク全体を使いLVMをセットアップする」を選択したままエンターキーを押して次に進みます。
そのままエンターキーを押して次に進みます。
「はい」を選択してエンターキーを押して次に進みます。
そのままエンターキーを押して次に進みます。
「はい」を選択してエンターキーを押して次に進みます。
インストールが開始されるのでしばらく待つと、プロキシ設定の画面になります。よくわからない場合はそのままエンターキーを押して次に進みます。
「自動的にアップデートしない」を選択したままエンターキーを押して次に進みます。
スペースキーで「OpenSSH Server」を選択してエンターキーを押して次に進みます。
しばらく待つと以下の画面になります。「はい」を選択したままエンターキーを押して次に進みます。
最後に「続ける」を選択したままエンターキーを押して次に進みます。
これでインストールは完了です。
4. OSインストール後の初期設定
dockeruserユーザでログインして作業します。
まずホストオンリーアダプターに固定IPを設定します。ここでは192.168.77.200を設定します。「sudo vi」などして「/etc/network/interfaces」に以下の内容を追記します。
auto eth1
iface eth1 inet static
address 192.168.77.200
network 192.168.77.0
netmask 255.255.255.0
broadcast 192.168.77.255
追記したら、以下のコマンドで有効化します。
$ sudo ifup eth1
ここまでの設定でホストからsshで192.168.77.200にアクセスできるようになります。
次に、sudoの設定を行います。今回はdockeruserユーザでパスワード入力なしで使えるようにしておきます。
$ echo 'dockeruser ALL=(ALL) NOPASSWD:ALL' | sudo tee -a /etc/sudoers.d/dockeruser
次に、grubのタイムアウトの設定を変更します。
$ sudo sed -ri 's/^GRUB_TIMEOUT=.*$/GRUB_TIMEOUT=0/' /etc/default/grub
$ sudo update-grub
次に、パッケージを更新して再起動します。
$ sudo apt-get update
$ sudo apt-get -y upgrade
$ sudo reboot
次に、sshdの設定を変更します。今回はsshdのインタフェースをeth1に限定するようにします。これはUbuntuのsshdとDockerコンテナのsshdの競合を避けるためです。
$ sudo sed -ri 's/^X11Forwarding\s.*$/X11Forwarding no/g' /etc/ssh/sshd_config
$ cat << 'EOT' | sudo tee -a /etc/ssh/sshd_config
AddressFamily inet
ListenAddress 127.0.0.1
ListenAddress 192.168.77.200
UseDNS no
GSSAPIAuthentication no
EOT
$ sudo service ssh restart
次に、VirtualBoxのGuest Additionsをインストールして再起動します。VirtualBoxのメニューから「Guest AdditionsのCDイメージを挿入」を選んで、以下のコマンドを実行します。
$ sudo apt-get -y install build-essential module-assistant dkms
$ sudo m-a prepare
$ sudo mount /dev/cdrom /mnt
$ sudo sh /mnt/VBoxLinuxAdditions.run --nox11
$ sudo umount /mnt
$ sudo eject
$ sudo reboot
5. ntpのインストール
時刻同期のためにntpをインストールします。
$ sudo sed -ri 's/^NTPSERVERS=.*$/NTPSERVERS="ntp.jst.mfeed.ad.jp"/' /etc/default/ntpdate
$ sudo apt-get -y install ntp
$ cat <<'EOT' | sudo tee /etc/ntp.conf
driftfile /var/lib/ntp/ntp.drift
statistics loopstats peerstats clockstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable
filegen clockstats file clockstats type day enable
server ntp1.jst.mfeed.ad.jp
server ntp2.jst.mfeed.ad.jp
server ntp3.jst.mfeed.ad.jp
restrict -4 default kod notrap nomodify nopeer noquery
restrict -6 default kod notrap nomodify nopeer noquery
restrict 127.0.0.1
restrict ::1
EOT
$ sudo service ntp restart
6. Sambaのインストール
WindowsからファイルにアクセスするためにSambaをインストールします。ここではdockeruserユーザに対してパスワードがdockeruserでホームディレクトリにアクセス可能なように設定しています。パスワードは適宜変更してください。
$ sudo apt-get -y install samba
$ cat <<'EOT' | sudo tee /etc/samba/smb.conf
[global]
workgroup = MYGROUP
server string = %h server (Samba, Ubuntu)
wins support = no
dns proxy = no
interfaces = 192.168.77.0/24 eth1
bind interfaces only = yes
log file = /var/log/samba/log.%m
max log size = 1000
syslog = 0
panic action = /usr/share/samba/panic-action %d
server role = standalone server
passdb backend = tdbsam
obey pam restrictions = yes
unix password sync = no
map to guest = bad user
usershare allow guests = no
local master = no
os level = 1
preferred master = no
wins proxy = no
load printers = no
cups options = raw
printcap name = /dev/null
printing = bsd
disable spoolss = yes
max protocol = SMB2
smb ports = 445
disable netbios = yes
nmbd bind explicit broadcast = no
dos filetimes = yes
[homes]
comment = Home Directories
browseable = no
valid users = %S
writable = yes
create mask = 0664
directory mask = 0775
EOT
$ sudo service smbd restart
$ sudo service nmbd restart
$ echo -e "dockeruser\ndockeruser" | sudo pdbedit -a -t -u dockeruser
設定が完了したらホストから「\192.168.77.200\dockeruser」でアクセスできます。
7. Dockerのインストール
まずはじめにsysctlの設定変更を行います。
$ sudo sed -ri 's/^#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
$ sudo sysctl net.ipv4.conf.all.forwarding=1
次に、Dockerをインストールします。
$ curl -sSL https://get.docker.com/ | sh
$ sudo usermod -aG docker dockeruser
$ newgrp docker
$ newgrp dockeruser
8. Vagrantのインストール
次に、Vagrantをインストールします。
$ curl -L https://dl.bintray.com/mitchellh/vagrant/vagrant_1.7.4_x86_64.deb -o vagrant_1.7.4_x86_64.deb
$ echo -n 'dcd2c2b5d7ae2183d82b8b363979901474ba8d2006410576ada89d7fa7668336 vagrant_1.7.4_x86_64.deb' | sha256sum -c -
$ sudo dpkg -i vagrant_1.7.4_x86_64.deb
あとで使用するプラグインをインストールしておきます。
$ vagrant plugin install vagrant-triggers
9. Ansibleのインストール
今回はプロビジョニングツールとしてAnsibleをインストールしてみます。
$ sudo apt-get -y install software-properties-common
$ sudo apt-add-repository -y ppa:ansible/ansible
$ sudo apt-get update
$ sudo apt-get -y install ansible
Vagrant経由でDockerのコンテナを立ち上げる
CentOS6のコンテナを立ち上げてみます。dockeruserユーザのホームディレクトリで、以下のようなディレクトリを準備します。
└── vm1
├── build
└── data
「vm1/Vagrantfile」を以下の内容で作成します。Vagrantfile中のip_alias_index、ip_alias_address、d.nameを調整することで別のコンテナも同様に構築できます。
ip_alias_dev = "eth1"
ip_alias_index = "1"
ip_alias_address = "192.168.77.201"
ip_alias_netmask = "24"
Vagrant.configure("2") do |config|
config.vm.synced_folder "./data", "/vagrant"
config.vm.provider "docker" do |d|
d.name = "vm1"
d.build_dir = "./build"
d.cmd = [ "/usr/sbin/sshd", "-D" ]
d.has_ssh = true
d.ports = []
for p in [ 22, 80, 443, 3306, 5432 ] do
d.ports.push(ip_alias_address + ":" + p.to_s + ":" + p.to_s)
end
end
config.trigger.before [:up] do
info 'Setting up ip alias ' + ip_alias_dev + ':' + ip_alias_index + ' ' + ip_alias_address + '/' + ip_alias_netmask
cmd = '/sbin/ip addr show ' + ip_alias_dev + ' >/dev/null 2>&1 && ((/sbin/ip addr show ' + ip_alias_dev + ' | grep -F \'inet ' + ip_alias_address + '/' + ip_alias_netmask + '\' >/dev/null 2>&1) || /usr/bin/sudo /sbin/ip addr add ' + ip_alias_address + '/' + ip_alias_netmask + ' dev ' + ip_alias_dev + ' label ' + ip_alias_dev + ':' + ip_alias_index + ')'
`#{cmd}`
end
end
「vm1/build/Dockerfile」を以下の内容で作成します。
FROM centos:centos6
MAINTAINER sadapon2008 <sadapon2008@gmail.com>
RUN echo 'include_only=.jp' >>/etc/yum/pluginconf.d/fastestmirror.conf
RUN yum -y update
RUN echo -n 'root:vagrant' | chpasswd
RUN groupadd vagrant
RUN useradd -g vagrant vagrant
RUN echo -n 'vagrant:vagrant' | chpasswd
RUN mkdir -p /home/vagrant/.ssh
RUN echo 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key' > /home/vagrant/.ssh/authorized_keys
RUN chown -R vagrant:vagrant /home/vagrant/.ssh
RUN chmod 700 /home/vagrant/.ssh
RUN chmod 600 /home/vagrant/.ssh/authorized_keys
RUN yum -y install sudo
RUN echo 'vagrant ALL=(ALL) NOPASSWD:ALL' >>/etc/sudoers.d/vagrant
RUN yum -y install openssh-server openssh-clients
RUN sed -ri 's/^#AddressFamily any/AddressFamily inet/' /etc/ssh/sshd_config
RUN sed -ri 's/^#UseDNS yes/UseDNS no/' /etc/ssh/sshd_config
RUN sed -ri 's/^GSSAPIAuthentication yes/GSSAPIAuthentication no/' /etc/ssh/sshd_config
RUN service sshd start
RUN service sshd stop
RUN yum -y clean all
EXPOSE 22
CMD ['/usr/sbin/sshd', '-D']
「vm1」ディレクトリに移動して、コンテナを起動します。
$ cd ~/vm1
$ vagrant up --provider=docker
$ vagrant status
コンテナを停止する場合は以下のようにします。
$ cd ~/vm1
$ vagrant halt
$ vagrant status
AnsibleでLAPP環境をプロビジョニングする
CentOS6+Apache+PHP+PostgreSQLのLAPP環境をAnsibleでプロビジョニングしてみます。
ここでは、fooユーザ(パスワードもfoo)を作成し、コンテナ内の「/vagrant」以下にApacheとPostgreSQLのデータを保存するようにしてみます。コンテナ内の「/vagrant」は「vm1/data」とリンクしているため、ホストからSamba経由でここにアクセスすることでソースの編集などが可能です。(PostgreSQLのユーザとパスワードはpostgresとpostgresになります。)
$ sudo apt-get -y install git
$ cd ~/vm1
$ git clone https://github.com/sadapon2008/ansible-roles roles
以下の内容の「vm1/playbook.yml」を作成します。
---
- name: for
hosts: all
sudo: yes
roles:
- { role: centos6-docker-common, main_username: "{{ main_username }}", main_password: "{{ main_password }}" }
- { role: centos6-apache, main_username: "{{ main_username }}", docroot: "{{ docroot }}", cake_env_mode: "{{ cake_env_mode }}" }
- { role: centos6-remi-php56 }
- { role: centos6-pgdg-postgresql94, dbroot: "{{ dbroot }}", permit_network: "{{ permit_network }}" }
「vm1/Vagrantfile」を以下のように変更します。
ip_alias_dev = "eth1"
ip_alias_index = "1"
ip_alias_address = "192.168.77.201"
ip_alias_netmask = "24"
Vagrant.configure("2") do |config|
config.vm.synced_folder "./data", "/vagrant"
config.vm.provider "docker" do |d|
d.name = "vm1"
d.build_dir = "./build"
d.cmd = [ "/usr/sbin/sshd", "-D" ]
d.has_ssh = true
d.ports = []
for p in [ 22, 80, 443, 3306, 5432 ] do
d.ports.push(ip_alias_address + ":" + p.to_s + ":" + p.to_s)
end
end
config.trigger.before [:up] do
info 'Setting up ip alias ' + ip_alias_dev + ':' + ip_alias_index + ' ' + ip_alias_address + '/' + ip_alias_netmask
cmd = '/sbin/ip addr show ' + ip_alias_dev + ' >/dev/null 2>&1 && ((/sbin/ip addr show ' + ip_alias_dev + ' | grep -F \'inet ' + ip_alias_address + '/' + ip_alias_netmask + '\' >/dev/null 2>&1) || /usr/bin/sudo /sbin/ip addr add ' + ip_alias_address + '/' + ip_alias_netmask + ' dev ' + ip_alias_dev + ' label ' + ip_alias_dev + ':' + ip_alias_index + ')'
`#{cmd}`
end
config.vm.provision "ansible" do |ansible|
ansible.playbook = "playbook.yml"
ansible.extra_vars = {
main_username: 'foo',
main_password: `openssl passwd -salt salty -1 foo`,
docroot: '/vagrant/www/html/htdocs',
cake_env_mode: 'development',
dbroot: '/vagrant/lib/pgsql/9.4',
permit_network: '192.168.77.0/24'
}
end
end
コンテナが起動している状態で以下のコマンドでプロビジョニングします。
$ cd ~/vm1
$ vagrant provision
プロビジョニングが成功すると、ホストのブラウザなどから「http://192.168.77.201/」にアクセスしたり、pgAdmin IIIなどで192.168.77.201:5432にアクセスしたりできます。
未解決の問題
- ポートのマップを変更するにはDockerでイメージを作成して別途コンテナを作成し直さないといけないようです(iptablesコマンドを駆使すればできないこともないようですが・・・)