はじめに
自宅で遊び用にVirtualboxで運用しているFedoraが、ちょっとミスをして起動しなくなってしまいました。そのため、再インストールの必要が出たのですが、いちいち「OSイメージダウンロード」「GUIやCUIでインストーラーで設定」「インストール後にネットワーク設定を色々」「必要なツールをyumでインストール」などが、かなり面倒なので、Vagrantを使ってしまおうと思い立ったのが始まりです。
さらに、「せっかくVagrantを入れるんだから、OSを入れたからyumやら何やらであれこれ入れるんじゃなく、コマンド一発でanyenvやPHPやRubyを入れたい」と思って検索してみると、どうも断片的な記事がほとんどで、最初から最後まで網羅的に説明してる記事が見つからず、少し苦労しました。そのため、同じ目的を持ってる他の人にも役に立つ(かも)と思い、自分のメモ書きも兼ねて公開してみました。
記事の概要および前提
- ホストはWindows 10、ゲストはUbuntu 18.04となります。
- OSにこだわりは無いので、使い慣れてるRedhat系を考えていましたが、途中で上手く行かないところや、気に入らないところがあったので、最終的にUbuntuを選択しました。
- 上手く行かなかった点は、最後で簡単に説明します。
-
VirtualboxとVagrantは、既にインストール済みであり、簡単にVagrantを使用した事がある人が前提とします。そのため、インストール方法や、細かいVagrantのコマンドの内容などは、この記事では説明しません。
- 自分は「Vagrant + VirtualBoxでWindows上に開発環境をサクッと構築する」を参考とさせていただきました。
- 共有フォルダを使う時は、vagrant-vbguest もインストールします。
- 目的は、PHPとRubyが動く環境をコマンド一発で構築するところまで持っていく事です。
環境設定
環境変数
boxのダウンロード場所をDドライブに変更します。この辺は好みなので、不要な人は飛ばしてください。
個人の好みですが、あまりCドライブに(厳密に言うと、C:\Users\ユーザー名\.vagrant.d\boxes
のようなユーザーディレクトリ内に)大きなファイルを起きたくないというのがあるので、Dドライブにboxがダウンロードされるようにするため、環境変数VAGRANT_HOME
を以下のように設定。
VirtualBox側も、デフォルトの仮想マシンフォルダー
を以下のようにDドライブに設定してます。これで、「boxをダウンロード」するドライブも、「仮想マシンを作る」ドライブも、すべてDドライブとなります。
Vagrant構築
box
boxには、「ubuntu/bionic64」を選択しました。
最初は「bento/ubuntu-18.04」を使おうかと思ったのですが、これはなぜかapt-get upgrade
実行時、Setting up keyboard-configuration (1.178ubuntu2.7) ...
というログで止まってしまう現象が起こり、解決しなかったのでboxをubuntu/bionic64
変更しました。
Vagrantfile
任意のフォルダに移動して、コマンドプロンプトで以下を実行すると、Vagrantfile
ができます。
vagrant init ubuntu/bionic64
こいつを、以下のように編集します。不要なコメントは除外してます。
synced_folder
は、自分がプログラムのソースを置く基本フォルダです。必要に応じて変えてください。
この中で、config.vm.provision
で設定しているシェルスクリプト群がありますが、これが今回の肝となります。
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/bionic64"
config.vm.network "private_network", ip: "192.168.33.12"
config.vm.synced_folder "C:\\dev", "/vagrant_dev"
config.vm.provider "virtualbox" do |vb|
vb.name = "ubuntu-18.04"
vb.memory = "2048"
end
config.vm.provision "shell", path: "setup_root.sh"
config.vm.provision "shell", privileged: false, path: "setup_vagrant.sh"
config.vm.provision "shell", privileged: false, path: "setup_anyenv.sh"
config.vm.provision "shell", privileged: false, path: "setup_anyenv_etc.sh"
config.vm.provision "shell", privileged: false, path: "setup_anyenv_sh.sh"
end
シェルスクリプト
config.vm.provision
で指定されてる部分は、vagrant up
をしても、最初の一回だけ実行され、2回目以降は実行されません。ただ、vagrant provision
やvagrant reload --provision
と指定すれば、その中も実行されます。なので、anyenvのインストール箇所などは、フォルダの存在チェックをして、存在すればインストール処理をスキップする処理を入れてます。
setup_root.sh
config.vm.provision "shell", path: "setup_root.sh"
で実行されるスクリプトです。privileged: false
を設定してないので、これはrootで実行されます。
anyenv、PHP、Rubyのインストールに必要なものを主にapt-get
でインストールしてます。ただ、tree、zip、unzipは、個人的に必要なので入れてるだけで、anyenvを入れるだけなら不要(らしい)です。
何度も実行しては、エラーを元に付け足し差し替えを繰り返していたので、不要な物がありそうですし、重複してる物もありますが、とりあえず自分はこれで成功してますので、このまま載せてます。
#!/bin/bash
apt-get update -y
apt-get upgrade -y
apt-get install -y autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev
apt-get install -y libreadline-dev zlib1g-dev
apt-get install -y libsqlite3-dev
apt-get install -y git build-essential libssl-dev
apt-get install -y curl g++ gcc build-essential libcurl4-gnutls-dev libcurl4-nss-dev libcurl4-gnutls-dev libjpeg-dev re2c libxml2-dev libtidy-dev libxslt-dev libmcrypt-dev libreadline-dev libssl-dev zlib1g-dev libyaml-dev libffi-dev bison
apt-get install -y libxml2 libxml2-dev libssl-dev pkg-config zlib1g-dev libbz2-dev libjpeg-dev libpng-dev libreadline-dev libtidy-dev libcurl4-openssl-dev libxslt1.1 libxslt-dev
apt-get install tree
apt-get install zip unzip
apt-get update -y
apt-get upgrade -y
setup_vagrant.sh
ここ以降の4つのシェルスクリプトは、privileged: false
と設定しているので、rootではなく、vagrantユーザーで実行されます。
なお、このスクリプトの部分は、anyenvのインストールとは関係ありません。ここでは、色設定を指定してます。
今回のboxでインストールしたUbuntuは、ホームディレクトリに.dircolorsが存在しません。
そのため、ls -la
などのコマンド時にも、色分けがされず、かなり見づらいです。
なので、ファイルの存在チェックをして、.dircolorsが存在しなければ、ファイルを作成します(存在チェックをしないと、provision時に、常に上書きされてしまうので)。
さらに、.bash_profile
にも、初期状態ではsource .bashrc
の記述が無く(というか、どうも初期では.bash_profile
自体が存在しないらしく)、いちいちsource .bashrc
を実行しないと.dircolors
が反映されないので、source .bashrc
の記述を.bash_profile
に吐き出す処理も追加しました。
こちらも、そのまま吐き出す処理を実行すると、いくつもsource .bashrc
の記述が連続して書き込まれてしまうので、記述の存在チェックをしています。
シェルスクリプトあまり書いたことがなかったので、とりあえず以下の記事を参考にさせていただき、grep
してsource .bashrc
の記述を検索して、1が帰るかどうかで判定してます。
unixコマンドの戻り値は (https://qiita.com/yamao2253/items/05adf89f39c1a6862147)
#!/bin/bash
if [ ! -e '/home/vagrant/.dircolors' ]; then
dircolors -p > /home/vagrant/.dircolors
fi
if [ ! -e '/home/vagrant/.bash_profile' ]; then
touch /home/vagrant/.bash_profile
fi
grep 'source .bashrc' /home/vagrant/.bash_profile
if [ $? -eq 1 ]; then
echo 'source .bashrc' >> /home/vagrant/.bash_profile
fi
setup_anyenv.sh
ここで、いよいよanyenvをインストールします。provision時に、不要なインストールをする羽目にならないように、ディレクトリの存在チェックをしています。
#!/bin/bash
if [ ! -e '/home/vagrant/.anyenv' ]; then
git clone https://github.com/riywo/anyenv ~/.anyenv
echo 'export PATH="$HOME/.anyenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(anyenv init -)"' >> ~/.bash_profile
source ~/.bash_profile
exec $SHELL -l
fi
setup_anyenv_etc.sh
次に、anyenv経由でrbenvとphpenvをインストールします。なお、なぜ「setup_anyenv.sh」で一緒にインストールしてしまわないのかと疑問に思われるかもしれませんが、どうもVagrantのprovision処理では、シェルスクリプトにexec $SHELL -l
が含まれてると、そこで処理を終了してしまうようなのです。
Vagrantfile の Shell プロビジョンで anyenv のインストールなど
exec $SHELL -l
するような処理を書くとき (https://qiita.com/ndxbn/items/5365e5eabd9e54c3f0a6)
なので、ファイルを分けることで対応しています。
exec $SHELL -l
をせず、source ~/.bash_profile
だけでも問題ない気もしますが、「anyenv公式」に沿う形にしています。
ここでも、例によってディレクトリの存在確認をすることで、rbenvとphpenvを何度もインストールする事態になることを防いでいます。
#!/bin/bash
if [ ! -e '/home/vagrant/.anyenv/envs/rbenv' ]; then
anyenv install rbenv
fi
if [ ! -e '/home/vagrant/.anyenv/envs/phpenv' ]; then
anyenv install phpenv
fi
source ~/.bash_profile
exec $SHELL -l
setup_anyenv_sh.sh
最後の処理です。setup_anyenv_etc.sh
のときと同様の理由で、exec $SHELL -l
での終了を回避するため、別ファイルにしています。
PHPとRubyのバージョンは、とりあえずこの記事が公開された時点での安定版の最新となります。
バージョン番号は、好みで変えて良いかと思います。別バージョンを入れたいなら、installコマンドを繰り返せば良いです。
#!/bin/bash
ruby -v 1>/dev/null 2>/dev/null
if [ $? -ne 0 ] ; then
rbenv install 2.5.1
rbenv global 2.5.1
fi
php -v &> /dev/null
if [ $? -ne 0 ] ; then
phpenv install 7.2.10
phpenv rehash
phpenv global 7.2.10
fi
vagrant up
シェルスクリプトの設置も終わったら、あとはvagrantfileのある場所で、vagrant up
を実行すれば良いだけです。
vagrant up
あとは、以下のようなログが流れていくので、しばらく待てば完了するかと思います。
==> default: Attempting graceful shutdown of VM...
==> default: Destroying VM and associated drives...
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'ubuntu/bionic64'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'ubuntu/bionic64' is up to date...
==> default: Setting the name of the VM: ubuntu-18.04
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
# ずらずらとログが流れていきます。
default: [xdebug]: Installing xdebug configuration in /home/vagrant/.anyenv/envs/phpenv/versions/7.2.10/etc/conf.d/xdebug.ini
default: [xdebug]: Cleaning up.
default: [Info]: Enabling Opcache...
default: [Info]: Done
default: [Info]: The Log File is not empty, but the Build did not fail. Maybe just warnings got logged. You can review the log in /tmp/php-build.7.2.10.20181014003512.log
default: [Success]: Built 7.2.10 successfully.
default: 7.2.10
途中でエラーなど起こらなければ、以上で完了です。vagrant ssh
や、Rloginなどでログインし、PHPやRubyが動くことを確認し、OKなら開発環境の構築は完了です。
vagrant@ubuntu-bionic:~$ ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]
vagrant@ubuntu-bionic:~$ php -v
PHP 7.2.10 (cli) (built: Oct 14 2018 00:49:15) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.10, Copyright (c) 1999-2018, by Zend Technologies
with Xdebug v2.6.1, Copyright (c) 2002-2018, by Derick Rethans
vagrant@ubuntu-bionic:~$ ls -la
ミスした箇所
注意点と言うか、アホなものも含めて、色々とミスしていたので、以下にまとめておきます。
synced_folder
で、ゲスト側に/dev
という設定をしていた
どういう事かと言うと、config.vm.synced_folder "C:\\dev", "/dev"
と設定していました(なぜなのかは、良く覚えてません)。
当然ですが、/dev
はLinuxにデフォルトで存在するディレクトリなので、vagrant up
しても上手く動きません。
ただ、問題はログにはエラーが出てこず、コマンドプロンプトに流れるログを見る限りでは、普通に動いてるように見えるというのが、曲者でした。
当初はvagrant ssh
を叩いても、アクセスする事ができなかったので、「ネットワーク関係が原因?」と、しばらく悩んでしまいました。
シェルスクリプトでは、先頭を#!/bin/sh
としない。
Ubuntuには不慣れだったので知らなかったのですが、最初、私は各シェルスクリプトの1行目に、普段の慣れから「#!/bin/sh
」って書いてしまってました。
ところが、CentOS時には成功していたシェルスクリプトが、なぜか上手く動いてくれず、少し悩みました。
どうやら調べてみると、Ubuntu(というかDebian系)では、/bin/sh
は独自実装の「dash」のシンボリックリンクらしく、php -v &> /dev/null
の部分などが、きちんと機能しなくなってました。「#!/bin/bash
」とすると、bashとして実行されます。
ちなみに、CentOSなどRedhat系なら、「#!/bin/sh」で動きます。
CentOSの/bin/shとUbuntuの/bin/shの違い (http://blog.aqutras.com/entry/2016/03/11/104801)
private_networkで指定したIPを使っても、Rloginなどでログインできない。
単純なミスと言うか、ホスト名に「192.168.33.12」と指定して、ポートに「2222」としていたので、ログインできませんでした。
SSHクライアントから、vagrantにアクセスする場合の記事を探し、まずは「127.0.0.1」にしてポートに「2222」としている記事を見て、それを実行して成功しました。
次に、ホスト名を「private_networkで設定したIP、192.168.33.12」に書き換えたのですが、ポート番号の変更をするという事に気づかず、接続できなかったのです。あれこれ色々とググって調べて、最終的には、色々と良く考えると「ポート番号を変えればよいのでは?」という事に気づき、自己解決しました。
ホスト名に「192.168.33.12」と指定して、ポートに「22」とし、さらに秘密鍵を指定すれば、普通にログインできます。
各シェルスクリプトの改行コードはLFで。
当然ですが、シェルスクリプトはUbuntu上で動くので、改行コードはLFにする必要があります。
CRLFだと、シェルスクリプトがバグる事があります(Windows上でスクリプト書いていたら、LF指定したつもりでしたが、いつの間にかCRLFになってて、スクリプトが変な動きをしました)。
最後に
この箇所は自分用のメモ書きや感想が主なので、飛ばしても問題ありません。
Ubuntuにした理由
最初で少し説明しましたが、はじめはCentOSやFedoraを使う予定でした。
特に、自宅ではyumでPHPの最新バージョンが手軽に入るという理由で、好んでFedoraを使ったいたので、今回もFedoraにするつもりでした(anyenvを使う今回のパターンだと、yumで最新PHPが入るのは、あまりメリットではありませんが、慣れていたので)。
しかし、Fedora(bento/fedora-28)はいざ進めてみると、「yum update」でカーネルなどの更新が起こると、VagrantとVirtualboxで、GuestAdditionsのバージョンが合わなくなります。さらに本来なら、自動で「vagrant-vbguest」が実行されてバージョンが合うようになるはずですが、これも上手く動かない事態になりました。
あれこれ調べてみましたが、どうやっても解消しないので、Fedoraは諦めてCentOS(bento/centos-7.4)にしました。
こちらは割とスムーズに進んだのですが、yumはpythonのバージョン2で動いているので、将来的にpythonのバージョン3を入れるとyum関係でトラブルを起こすことから断念。
この問題自体は、割と簡単に解決できるっぽいですが、設定ファイルを書き換える必要があるようなので、「コマンド1つで実行環境を整える」という今回の目的には、少し合わなくなります。.bash_profile
の「追記」程度ならともかく、シェルスクリプトの「書換」は少し怖いので、考えた末に別のOSを使うこととしました。
ということで、前々から興味のあったUbuntuを選択。
正直、コマンドなどで微妙にRedhat系と違いがあって、慣れない部分も多いですが、会社では今後、Ubuntuサーバが増えていくかもという話が出ているので、ちまちま慣れていこうかと思います。
感想
Vagrantを入れる前、自宅で遊ぶための開発環境は、Virtualboxに直接Fedoraやらをインストールして、yumで地道に必要ツール群をインストールするという原始的な方法で構築していたのですが、サーバで遊んでいると、壊れるということは稀にあります。これまでも壊れたたびに、面倒くさい再インストール再構築をやっていたのですが、今回はこれを機に自宅でもVagrantを使って環境構築をしてみようかなと思い立って、実行に移してみました。
業務でもVagrantは使ったことがありますが、基本はインフラチームや、Vagrantfileが書けるエンジニアが作り上げた環境を渡され、こちらはコマンドを実行するだけということが多かったので、勉強がてら試してみることにしました。
インフラ系はやってみると面白いのですが、どうも上手くいかない時はとことん上手くいかないので、少し苦労します。最終的には、とりあえず個人で使う環境としては、納得行くものができたかなと思います。
Vagrantを最初から試行錯誤して使ってみた感想としては、単純にOSをインストールするだけでも、かなり楽になるということですね。今回は、さらにシェルスクリプトで、あれこれインストールさせる所まで自動化できたので、一度設定してしまえば、壊れることも恐れる必要がなくなります。
Vagrantはスナップショットを取るのも楽ですし、さ今後は、躊躇なくガンガンと新しいことを試す事ができそうなので、楽しみです。