VagrantとDocker(1): Rails環境構築を目的とした場合のVagrantとDockerの関係

このエントリーをはてなブックマークに追加

かつて仮想環境が登場した時、VTやVTxで仮想環境がアクセラレートされクラウドが登場した時、非常にエキサイティングな経験をした。ランタイムではなく、マシン自体が仮想化されハードからシステムが切り離され自動的に冗長化していく、これはかつておっさんが新人だった頃(2000年前後)にIBMがオートノミックコンピューティングと呼び、オラクルがグリッドコンピューティングと呼んだ技術だ。

当時はSFだった、自律的コンピューティングなんてせいぜい2001年宇宙の旅のHALぐらいしか想像力が及ばなかった。効果な専用の管理用ラックや見たことも触れたこともない高価なハードやOSを準備しなければならなかったし、結局さほど普及したようにも見えなかった。

しかし、あれから10年、仮想環境は既に仮想であるということすら意識されずにクラウドとして利用されている。そしてクラウドは色々な技術を内包し統合するための便利なバズワードとなり、多数のサブワードを抱えている。VPS、IaaS、PaaS、BaaS、インスタンス、コンテナ、プロビジョン、ベアメタル、Stack、Lamda・・・んー困った。

とは言え自分のような凡人には全部一気に抑えて行くことは出来ないので、とりあえずようやく枯れてきた感のあるVagrantとDockerを用いてRailsの環境を構築することで学ぶことにした。

みんな大好きRuby on Railsは、賛否両論あるとは思うけどバージョンを重ねる毎に当初の目的であった一気通貫のシンプルなフルスタックではなくなり通常はGemにより肥大化している。まるでかつてJava世界において花型であったSpringとMavenのように感じる。実際、それなりに肥大化したRailsの環境構築はrubyenvやbundle、rakeの力を借りても一苦労だ。
そんな環境構築は自分の実務にとっても学習にとっても最適な事例だと思ったのである。

とは言え、全部を一度に学ぶのも、書くのもしんどいので下記の様に今回を(1)として一歩一歩進めて行くとしよう。

  • VagrantとDocker(1): Rails環境構築を目的とした場合のVagrantとDockerの関係
  • VagrantとDocker(2): VagrantによるRails環境構築
  • VagrantとDocker(3): VagrantによるDocker稼働環境の構築
  • VagrantとDocker(4): Docker on VagrantによるRails環境の構築
  • VagrantとDocker(5): Docker for Mac / Docker for Windows によるRails環境の構築 (※追記

回りくどいが「理論なくしてなんとやら」のため、今回は各要素の関係性と最終的な到達点までの説明であり、実際の構築スクリプトや実践は次回からとなるが、とりあえずVagrantfileやDockerfileなどをGithubにあげてあるので参考にしていただいても構わない。

参考

▽ Railsの環境って?

そもそも、Railsの動く環境をどう作るかを先に決めておこう。残念ながら自分はRailsについて熟知しているとは言えないため間違っている箇所もあるかもしれない、その時は(豆腐メンタルなので優しく)間違いを指摘してもらえれば嬉しい、大急ぎで修正する。まず、私の理解しているRailsの環境とは下記のような要素から成り立っている。

1層目に各OS、そしてその上の2層目にRubyの実行環境やデータベースが乗り、その上で3層目のアプリケーションフレームワークとしてのRailsが乗っかってくる。大きくは間違っていないし、図にするまでもないシンプルな構成である。ただ、注目して欲しいのが2層目である。Rubyの実行環境(Runtime)やDatabase(Middleware)である。これらはほぼ同様に振る舞うとはいえど、各OS毎に異なるバイナリーが提供されている。

つまり、セットアップの方法が異なるのだ。もっと言えばクリティカルな局面やシステムに近いレベルのAPIでは振る舞いも変わってくるかも知れない(HFS+とか、NFSとか)。もちろん、最近のお洒落な気取ったRubyistの大半が正統UNIXと称して閉鎖環境であるMacを軽やかに使いこなしているのは承知している。しかし世の中には何の苦行なのかWindowsでRails開発している人も、原理主義的にLinuxで開発している人もいる、そして通常のリリース環境の大半はLinuxだというようなことは覚えておいて損はない。むろんMacを僻んでいるわけではない、いつだってブルーボトルで成功の証として新鮮みのない黒い無骨なThinkpadを開いてドヤ顔してみせよう。

とは言え、いずれの環境でも実行環境の構築は下記のような順番になるだろう。

  1. Rubyの実行環境のインストール
  2. MySQLのインストール
  3. Rails環境のセットアップ
    • bundlerによる依存関係の解決
    • rakeによるDB等の初期設定やマイグレーション

簡単に見えるが結構面倒である。1が意外と面倒なのである。
具体的には下記の様になる。細かいことはわからなくても流し読みして環境ごとに結構違って面倒なんだねという雰囲気を感じ取れれば大丈夫である。
※ Windows10 Anniversary Updateから導入されたWSL(Windows Subsystem for Linux)は現時点では含めていない。

  • Windows系
    • RubyInstallerによりインストール
    • GemによりBundlerをインストール
    • GemによりRailsをインストール
  • Mac系
    • XCodeをインストール
    • Command Line Tools for Xcodeをインストール
    • Homebrewをインストール
    • Homebrewを用いてrbenvをインストール
    • rbenvを用いて任意のバージョンのRubyをビルド
    • Gemを用いてbundlerをインストール
    • Gemを用いて任意のRailsをインストール
  • Linux系
    • aptかyumで”Build Essential”をインストール
    • rbenvとruby-buildををgitで取得
    • rbenvを用いて任意のバージョンのRubyをビルド
    • Gemを用いてbundlerをインストール
    • Gemを用いて任意のRailsをインストール

さらっと書いてしまったが、この時点で幾つかのキーワードが出てくるのでメモ程度に説明を書いておく。

  • RubyInstaller
    Windows特有のRuby実行環境をある程度パッケージングしたもの
  • Gem
    Ruby実行環境でのパッケージ管理、取得コマンド
  • XCode
    Macの開発環境ソフトウェア
  • Homebrew
    Macでのコマンドラインによるパッケージ管理ソフト
  • apt
    Debian系Linuxでのパッケージ管理コマンド
  • yum
    RHEL系Linuxでのパッケージ管理コマンド
  • Build Essential
    Linux系での開発環境の標準セット、MacでのXCodeみたいな物
  • rbenv
    複数のRuby実行環境を構築したり切り替えたりするコマンド、残念ながらWindowsでは簡単には使えない
  • bundler
    複数のGemを取得したり更新したりするコマンド

どうだろう?ここまでの時点で、各OSでの環境構築がそれなりに手間であること、差異があることがわかるかと思う。とりあえず上記手順に従ったものを、この後の文章でも『Rails環境』と定義したい。

参考

▽ そもそもVagrantとDockerとは?

さて、そもそもVagrantやDockerとは何なのか?
VagrantとDockerはしょっちゅう同じ文脈出てくるが似て非なるものなので非常に紛らわしくわかりにくい。

Vagrantは開発環境の構築、配布ツール

複数の開発者が同じ環境で開発やデバッグ、テストを行えるようにするための作業環境構築をサポートするツールである。そのため、Mac、Windows、Linuxのいずれでも動作する。厳密には環境の対象(Provider: Virtualbox、VMware、Docker、AWS等々)を決定し、雛形(VagrantBox)を指定し、環境設定ツール(Provisioning: Bash、Chef、Ansible、Salt等々)を呼び出し環境を構築する。ただし、一般的にはProviderとしてはVirtualboxを利用し、VagrantBoxからLinuxイメージを取得、プロビジョニングを実行という流れで利用されることが殆どである。言い換えると、Linuxの雛形イメージをダウンロードしてVirtualBoxの仮想マシンを起動するまでを全自動でやってくれるということである。ただし、仮想マシンを利用する場合は、比較的に負荷が高く容量も消費する。なお、上記説明が難解だと思った人は、VirtualBoxをスクリプトで何かと便利に操れるものだと考えても差し支えはない。

Dockerはコンテナ(OSレベル仮想環境)の管理ツール

いわゆるパーティショニングと呼ばれる技術に近く、カーネルを共有しつつメモリ空間を分離するという半仮想化を行うツールである。Linuxのkernel上で動作することを前提としているためLinux以外では動作しない。chrootを発展させたものと言えばわかりやすいかも知れない。分離された半仮想化環境をコンテナと言う。コンテナは現在のシステム上にプロセスとして起動されるため負荷的にも容量的にも非常に軽量であるが、基本的にランタイム環境であるため永続化などに独特の構成が必要となる。また、プロビジョニング用として複数コンテナを一括で構成管理するためのdocker-composeというツールが提供されている。そしてクジラのイラストが愛くるしいが大量のコンテナを積載されており犬みたいな名前の海賊に怒られそうである。

上手な比喩が見つからないが、Vagrantで作られる環境は一軒家、Dockerで作られる環境はマンションの一室という感じであろうか。前者は水回りやガス周りなど専用だが、後者は共用の配管を部屋ごとに引き回すことで実現しているという感じである。前者は独立性や自由度が高いがコストも高い、一方後者は自由度が低く引き回しが面倒だがコストが安い。

いずれにせよ、VagrantもDockerも汎用性が高いためある程度の戦略と方針を持ってとりかかり、その後で改善していくというアプローチをとらないと何をどうして良いのかわからなくなるだろう。

参考

▽ Vagrantを用いたRails環境の構築

Vagrantを用いてRails環境を実現する場合は、各OSへVagrantをインストールし、仮想環境(VirtualBox)を作り、Vagrantにより仮想マシンへLinuxをセットアップし、そこへRubyやミドルウェアをインストールするという流れになる。そのため、仮想環境より上の層はWindowsであろうとMacであろうとLinuxであろうと共通化されることになりRails環境の構築が共通化、自動化出来そうだ。そして何より階層構造がシンプルでわかりやすい。

とは言え、仮想マシンをまるまる1台建てるので、複数同時や切り替え時のマシンリソースのコストはそれなりに高い。また、VagrantBoxのイメージもネットが高速化されたとは言え仮想マシンまるまる配布だったりするためそれなりに帯域を消費するだろうし時間もかかりそうだ。

まとめるとVagrantを利用する場合の長所と短所は下記になる

  • 長所
    • Rubyの実行環境をホストシステムに関わらずLinuxへ統一できる
    • LinuxへのRubyのインストール作業などはshellやその他のプロビジョニングツールにて実行できる
  • 短所
    • 環境ごとにVirtualBoxの仮想マシンを構築するためにマシンリソースを必要とする
    • 仮想マシン自体のイメージを取得し、セットアップするので構築に時間がかかる

▽ Dockerを用いたRails環境の構築

まず、大前提としてDockerというのはLinux以外では動かない。WSLで動くんじゃないかという話もあったが、残念ながら現時点では多分動かないだろう(参考参照)と言われている。また実験的ながらBSD用のDockerなどもあるようだが、現実論としてLinux以外の環境をコンテナ化する必要性は低いだろう。

ではDockerではどのようにRails環境を構築すべきだろうか?一般的にDockerではVagrant同様に配布されているコンテナイメージを取得、そのコンテナを組み合わせてサービスを構成するというアプローチをとるようだ。私の場合はRubyとMySQLの公式コンテナを組み合わせることにした。最初はDockerを直接実行してコンテナインスタンスを準備、何度かやり直して動作を確認しつつ構成が固まったらDockerComposeを利用して複数同時に構成するといった感じだ。イメージとしてはマイクロサービスを組み合わせてひとつのWEBサービスを構築するというのに近い。
学習コストはDockerにクセが有り比較的高いと言えるが、公式コンテナを利用することでRubyの環境構築に必要とされる時間が圧倒的に短縮できた(当たり前だ、既にビルドされたものを差分ダウンロードしてくるだけなのだ)。そしてコンテナの構築や起動のためのマシンリソースは低く高速だった。慣れればVagrantと比べて数分の1と行った感じだろう。そしてコンテナは基本的には使い捨てのためおかしくなっても短時間で異なる環境セットを立ち上げられるのも素晴らしいところだ。
なお、DockerによりVagrant的アプローチをとってSSHなどでつなぎながらコンテナ上で全ての開発作業をしていくというような方法はやめたほうが良いだろう。使い捨てであるコンテナの永続化の問題が立ちはだかるし、なによりコンテナ上に複雑な環境を構成するのは面倒なためそのような目的の場合は素直にVagrantを利用したほうが楽である。

まとめるとDockerを利用する場合の長所と短所は下記になる

  • 長所
    • Rubyの実行環境を公式イメージにより短時間で準備できる
    • マシンリソースをあまり消費しないため複数コンテナを同時に立ち上げられる
  • 短所
    • Linux以外では動かない
    • 飽くまでもランタイム環境である

※追記

情報が古かったようである。改めて調べたところ現在ではMac、Windowsでも動かすことができるようだ。ただし、いわゆるMacやWindowsのコンテナというわけではない。飽くまでもLinuxコンテナをMacやWindowsで稼働させることができるというものである。アプローチとしてはMacでもWindowsでも仮想マシン、あるいはハイパーバイザーを挟みこむことでLinuxのカーネルを稼働させ、その上にコンテナをデプロイするというものである。

参考

▽ Docker on Vagrantを用いたRails環境の構築

PPAP的アプローチ、これしかないだろう。
各層については既に説明したとおりだが、再利用可能なベースとなる開発環境(エディタやgit、Docker環境)をVagrantにより仮想マシンとして構築し、Rails環境をDocker上のコンテナとして稼働させてしまうということである。ようやくなぜDockerを調べるとVagrantが出てきてややこしい話になるのかが理解できたと思う。図を見ている限りは、高層マンション状態であり動くのかすら心配になってくるが、結論から言うとわりと簡単に動くので安心してもらって構わない。

この環境を最終目標として次回からのRails環境構築を行っていきたいと思う。

参考