Vagrantの重要ファイル「Vagrantfile」の読み込みとその周りの挙動をちょっと細かく追ってみた
だんだん秋めいてきて、毎日の服装に迷っている@at_grandpaです。
長袖だと日中暑いですし、半袖だと夕方寒いです。
体調を崩しやすい季節ですので、みなさんお気をつけください。
前回までで、Vagrantを用いた仮想環境の立ちあげ〜ログインまでを行いました。
今回は、Vagrantをいじくりまわす上で重要なファイルである Vagrantfile について書こうと思います。
参考にしているサイトは、以下です。
※Vagrantのコードを全て追ったわけではありません。(検証はしていますが)
※その点に注意して読んでいただければと思います。
Vagrantfile
どんな役割のファイルなのか
Vagrantfile は VMを立ち上げる際のconfigやprovision(立ち上げ時自動実行)を記述するファイル です。
前回の操作の際は、vagrant init
を行った時点で、カレントディレクトリに作成されていました。
Vagrantfileは、ひとつのプロジェクトに最低ひとつ必要です。
また、gitなどでバージョン管理をすることができるので他の人との開発にも便利です。
Vagrantfileを編集してできることは、以下のようなものがあります。
- VMを立ち上げる際のboxの指定
- IP、ポートの設定
- VM立ち上げ時に、自分で書いたシェルスクリプトを走らせる
- VM立ち上げ時に、Chef-Soloを実行し開発環境を整える
- 複数のVMを立ち上げられるようにする
- etc...
まだまだ機能がありますが、これだけでも相当なことができると思います。
Vagrantfile は Ruby で書かれていますが、簡単な変数代入で書かれているため、
公式にも「Rubyの知識は必要ない」と書いてあります。
この部分も、導入の敷居を下げるのに貢献しているのかもしれませんね。
Vagrantfileの読み込み
読み込みの流れ
Vagrantfile は、以下の4ステップで読み込まれます。
あるステップでVagrantfileが存在しなかった場合は、そのステップを飛ばして次のVagrantfileが読み込まれます。
それぞれのステップにVagrantfileがあった場合、一体どのファイルの内容が実行されるのかが気になるところです。
いろいろ検証してみました。
Rubyをちょっと勉強する
Vagrantfileの内容を見てみると、以下のような形式になっています。
Vagrant::Config.run do |config| ... end
今回のこのブログで初めてRubyを触っているわけですが、いろいろ調べてみました。
するとこの部分は、Vagrantオブジェクト、Configメソッド、runメソッドがあり、
その返り値をforeach風に回しているんだと思います。
このことから、
・何らかのメイン処理があり、そこでVagrantオブジェクトが生成される
・VagrantfileはVagrant::Config.run
メソッドの返り値をループ処理するためにrequireされている
と仮説が立てられます。
Vagrantfileが複数ある場合は、その個数分だけrequireされ、Vagrant::Config.run
メソッドが走ります。
インスタンス変数は、Vagrant::Config.run
メソッドの返り値がループ処理されるたびに上書きされていきます。
(ex:VM立ち上げ時にはOSを1つだけ指定するので、box-nameは一番最後に読み込まれたVagrantfileのものになる)
また、配列に値がどんどん追加されていく、という形も考えられます。
(ex:provision(自動実行処理)などは、処理内容をどんどん追加して最後に全て実行する形)
だんだんとVagrantfileの読み込み、実行、変数の内容の決定方法がわかってきました。
実際の処理はいつ走るのか
ここで疑問になったのが、実際の処理はいつ走るのかです。
まぁ、大体の構成として「オブジェクトの内容を全て決定してから最後に実行」なのだろうと予想がつきます。
でも確かめてみたくなるのが人情。やってみましょう。
簡単です。Vagrantfile内でtextを出力させ、どのような順で出力されるかを検証します。
テスト用のVagrantfileは以下です。それぞれ保存先が違います。
#~/.vagrant.d/Vagrantfile print "11111111" + "¥n" Vagrant::Config.run do |config| # ここにいろいろな設定 print "22222222" + "¥n" end print "33333333" + "¥n"
#./Vagrantfile print "hogehoge" + "¥n" Vagrant::Config.run do |config| # ここにいろいろな設定 print "fugafuga" + "¥n" end print "piyopiyo" + "¥n"
vagrant up
した際の出力結果はこうなりました。
$ vagrant up 11111111 33333333 hogehoge piyopiyo 22222222 fugafuga [default] VM already created. Booting if it's not already running... [default] Clearing any previously set forwarded ports... [default] Forwarding ports... [default] -- 22 => 2222 ...
結果を見てみると、
- 実際の処理の前にprintされていることから、全てのVagrantfileがVM立ち上げ処理の前に読み込まれている
- 読み込まれる順は、
~/.vagrant.d/Vagrantfile
→./Vagrantfile
- この順番で、まずは全てのVagrantfileの
Vagrant::Config.run do |config| 〜 end
の外側部分が実行される- 次に、この順番で、全てのVagrantfileの
Vagrant::Config.run do |config| 〜 end
の内側部分が実行される
となっています。
Rubyというものはこういうものなんですかね。その辺、勉強不足です。
このような流れで、インスタンス変数の上書きや、配列への値の追加がなされています。
これで、Vagrantfileの読み込みから実行までを追うことができました。
【補足】探索する順序
ステップ4でカレントディレクトリ内のVagrantfileが存在するかを確認していますが、
もし無い場合は、以下のようにディレクトリツリーを上に遡って検索していきます。
/hoge/fuga/piyo/Vagrantfile /hoge/fuga/Vagrantfile /hoge/Vagrantfile /Vagrantfile
これにより、プロジェクトのどこからでもvagrant
コマンドを実行できます。
まとめ
今回はVagrantの中核をなすファイル、Vagrantfileとその周りの挙動について追ってみました。
- Vagrantのメイン処理が走ると、Vagrantオブジェクトが生成される
- そのメイン処理の中で、Vagrantfileがrequireされる
- Vagrantfileは複数存在することもあり、読み込まれる順番が決っている
- Vagrantfileには、「
Vagrant::Config.run
メソッドの返り値をループ処理する」際の挙動が書かれている- 複数のループ処理が走る(Vagrantfileが読み込まれる)と、それに応じて変数が上書きされたり、配列に値が追加されたりする
- こうして、様々な設定がなされたVagrantオブジェクトが作り上げられていく
- 全てのVagrantfileを読み込み、Vagrantオブジェクトが完成した時点で、VM立ち上げ処理を実行する
Rubyistの方は「そんなの当たり前の処理じゃん」と思われるかもしれませんが、
Ruby初心者の自分にとっては、処理が追えたのはテンション上がりました。
細かく処理が追えたことで、今後のVagrantfileの編集の手助けになりそうです。
次回は、Vagrantfileを編集し、複数VMの立ち上げ を行いたいと思います。
お茶でも飲みながら読んでくださればと思います。
温かいお茶が美味しくなってくる季節ですしねぇ〜。