Furyu
[フリュー公式]

Tech Blog

フリュー株式会社の技術ブログです

2013年04月19日

kunihira

この春エンジニアなった君に使って欲しいVagrant

お久しぶりです。 フリュー乙女ゲームチームの国平です。

前回は、弊社で開発したplay-velocity-pluginをご紹介させて頂きましが、今回はVagrantをご紹介したいと思います。 技術の検証・学習のために仮想マシンを使う機会は多いと思いますが、Vagrantを利用することで、仮想マシンの利用を簡略化することができます。

これは、私が学生時代に後輩に指導していた時なら間違いなく導入していたと確信できるほど便利だったので、何番煎じかわかりませんが思わず記事にしてしまいました。

本記事のゴールは、とりあえずVagrantを使ってWindowsPC上にLinuxの仮想マシンを動かすところまでです。

目次

  • 仮想マシンについて
  • Vagrantとは
  • インストール
  • vmを用意する
  • vmを使う
  • vmを止める
  • vmを削除する
  • まとめ
  • 最後に

仮想マシンについて

仮想マシンとは

文字通り仮想のマシン(PC)だと思ってもらえたら大丈夫です。 今、あなたが向かっているPCの中にもう一つPCを用意するイメージです。 いわゆるコンピュータは、入力装置、出力装置、制御装置、演算装置、記憶装置といった部品から成り立っています。 今年新卒で入社した人なら、高校の情報の授業で習ったんじゃないかと思います。 仮想マシン(VirtualMachine:vm)というのはこれらの部品のうち、演算装置や記憶装置をプログラムでシミュレートして、PCの中でもう一つPCを動かすシステムです。

なにがおいしいの

この仮想マシンを使って何がお得なのか。 それは2点あります。 1つは、PCを壊してもスグに復旧出来る事です。 そして、もう1つは、持っているPCのOSに関係なく別のOSを動かす事が出来る事です。

小さいときに親のPCを触ろうとして、「壊すからダメ」とか言われた経験はないでしょうか?私はあります。 確かに、会社から支給されたPCに適当にいろいろなものをインストールしまくって動かなくしてしまったら大問題です。 でも、仮想マシンなら突き詰めるとPCの中にあるファイルにすぎません。どんなむちゃくちゃな使い方をしても、最後には仮想マシンの情報が入ったファイルを削除して新たに作成すれば問題ありまん。用心深さを発揮してこまめにファイルの保存をしておけば完璧です。動かなくなったら、動いてたファイルを取り出してもう一度試す事が出来ます。 また、PC上に仮想のPCを作るので、WindowsPCしか持っていなくても、仮想マシン上でLinuxを動作させる事も出来ます。 Web系の開発だと、開発マシンはMacもしくはWindowsで、サーバはLinuxという環境も多いのではないかと思います。 自分の学習のために、共用しているサーバをいじり倒すのは問題がある場合があると思います。 しかし、この仮想マシンを利用することで、自分だけの学習環境を手に入れることができます。

Vagrantとは

ざっくり言ってしまうと仮想マシンの構築ツールです。 Vagrantではコマンドラインから仮想マシンを構築/起動する事が出来ます。 なんで、直接VMWareやVirtualBoxなどの仮想化ソフトウェアを操作せずVagrantを使うのかという疑問もあると思います。しかし、Vagrantには直接仮想化ソフトウェアを操作する以上のメリットがあります。 仮想マシンの設定をファイルに書き込むので設定の再利用がしやすいので、仮想マシンを破棄してもすぐに再構築できます。また、どこでも同じ環境を複製する事ができるので、ホストPCの変更にも影響されません。 サーバ周りのソフトウェアの検証や動作確認、学習環境構築などでは、仮想マシンを作って消して、また作るという事が多くなりますが、Vagrantにより手間の軽減をする事が出来ます。

インストール

VirtualBoxのインストール

Vagrantでは仮想マシンとしてVirtualBoxを利用します。

このインストール自体は簡単で、ここから自分のOSに応じたインストーラをダウンロードしてインストールしてください。

VirtualBox以外にもMacユーザの方なら、VMwareFusionでも大丈夫なようですが、ここではMac/Windowsの両方で利用できるVirtualBoxを前提とします。

Vagrantをインストールする

Vagrantのインストールも簡単です。ここから最新バージョンを選択して、自分のOSに応じたインストーラをDLするだけです。

あとは、適当にぽちぽちとやったらインストール完了です。

インストール出来た事を確認するために、コマンドプロンプトを立ち上げて、

と打ち込んでみてください。

こんな感じで、vagrantコマンドのヘルプが表示されればインストール成功です。

ここから先はコマンドプロンプトにコマンドを打ち込む作業が多いので、プロンプトは立ち上げっぱなしにしておいてください。

vmを用意する

Boxの用意

Vagrantでは仮想マシンのひな形をboxと呼びます。 このboxを用意するには、vagrant box コマンドを実行します。 今回は既に用意されているboxを利用させてもらいましょう。 試しに、CentOS 6.3のboxを用意します。以下のコマンドを実行してください。

これで、CentOS 6.3を使った仮想マシンのひな形が用意出来ました。 他のOSを使いたいときは、 http://www.vagrantbox.es から探すといいでしょう。

Vagrantfileの生成

ひな形が用意出来たら、作成するマシンの設定を用意します。いろいろと設定をいじる事は出来るのですが、今回はLinux環境を作る事が目的ですので、ネットワークの設定だけ行います。 Vagrantでvmを作成するときは、Vagrantファイルにvmの設定を書き込みます。

これで、vagrantというフォルダにVagrantfileというファイルが出来ているはずです。 このファイルを適当なエディタで開くと、いろいろとデフォルトの設定が書かれています。 Vagrantfileは#から始まる行はコメントとして扱われるので、大半がコメントになっています。

ネットワーク設定

とりあえず、ネットワークだけつながるようにしておきましょう。 Vagrantfileにいろいろ書かれている内容のうち、

と書かれている行の#を消して保存しましょう。 もう一カ所、

の行も#を消します。 ここまで、この記事の通りに実行していれば、23行目と28行目にあると思います。 これでネットワーク設定は完了です。

vmを使う

vmの起動

さて、これでvmを起動する用意は出来ました。 それでは、WindowsPCの上でLinux(CentOS)を動かしてみましょう。 vmの起動にはvagrant upコマンドを実行します。 vagrant upコマンドは今後vmの起動に何度も使うので、覚えておきましょう。 このコマンドを打って、しばらく待つとvmが起動します。 ひょっとすると途中で、どのネットワークアダプタを利用するかWhat interface should the network bridge to?と聞かれるかもしれません。 もし聞かれたら、だいたい 1 を入力してエンターで問題ないはずです。

vmに接続する

vagrant upコマンドの実行が終わっても、特にウィンドウが立ち上がるという事も無いので、本当に仮想マシンが動いているのかわからないと思います。 しかし、ちゃんと起動しています。 起動した仮想マシンにアクセスして操作するにはvagrant sshコマンドを実行します。 sshというのは、あるPCから別のPCへ接続して操作するコマンドのことです。ここでは、大本のOS(ホストOS)から仮想マシンへ接続しています。

vagrant sshコマンドを実行すると、いろいろ出力された後に、

の様なプロンプトが表示されると思います。 これが、今回作ったLinux仮想マシンのコンソールになります。 試しにunameと打ち込んでみましょう。unameというのは、システムの情報を出力するLinuxコマンドです。これを実行するとLinuxと出力されるはずです。これで、今Linuxを操作している事がわかりますね。 ここまで、出来たら好き放題LinuxOSを楽しみましょう。 必要な開発環境のインストールなどをガシガシしてみてください。

Linuxの操作を終了するときは、exitコマンドを実行すれば、Windowsのコマンドプロンプトに戻る事が出来ます。

vmを停止する

exitコマンドでWindowsのコマンドプロンプトに戻っても、仮想マシンが停止したわけではありません。 見えないだけで、しっかりと仮想マシンは動作しています。 つまり、このままだとホストOSのメモリやCPUを使い続けてしまいます。 そのため、やりたい事が一通り完了したら仮想マシンを停止する必要があります。 仮想マシンを止めるには、

  • vagrant suspend で仮想マシンを一時停止状態にする
  • vagrant halt で仮想マシンを停止する

の2通りの方法があります。 suspendはWindowsで言うところのスリープで、もう一度vagrant upを実行すると、suspendする前の状態そのままに続きから仮想マシンが動き始めます。 対して、haltは電源Offです。一度仮想マシンの電源を切るので、vagrant upを実行するとOSは完全に再起動されます。 どちらを使うのも自由ですので、お好きな方を選んで使ってください。

vmを削除する

さて、ここまででLinux環境でいろいろ実験出来るようになったのですが、いろいろいじりすぎて完全に環境をリセットしたいときも出てくるかと思います。 そんなときには、vagrant destroyを実行します。 このdestoryコマンドはその名の通り、作成した仮想マシンを破棄するコマンドです。 このコマンドを実行して、再度vagrant upすれば、キレイなLinux仮想マシンを新たに作る事が出来ます。 ただし、これまで仮想マシンにインストールしたプログラムや保存したファイルなどは全て消えるので実行には注意してください。

まとめ

Vagrantを使って、仮想マシンを用意する事でトライ&エラーをどんどん出来る環境を用意出来ました。 どんどん、仮想マシンをいじり倒して壊しまくってください。

最後に

本記事では、今からLinuxの勉強を始める人を対象に書きました。 そのため、省いている内容も多くあります。

より詳しく学ぶためのとっかかりをまとめておきます。

  • Vagrant公式サイト http://www.vagrantup.com/ vagrantをもっと便利に使うには、まずは公式サイトを読むことをお勧めします。 英語のページですが、比較的読みやすいように思います。 今回はネットワーク設定しか設定を変更しませんでしたが、もっといろいろと出来るのでぜひ調べてみて下さい。

  • ネットワーク設定 今回は、とりあえずLinuxを起動すること優先でネットワーク設定を適当に流しましたが、private_networkやpublic_networkが何をやっているのか、ipとはなんなのかは知っておくべきです。

以上、Vagrantを紹介しました。 次回は同じくLinuxビギナー向けにviの記事を書こうかと思います。


2013年04月18日

kasuya

西暦1000年は閏年かそうじゃないのか?

ソフトウェア開発部 粕谷(@daiksy)です。

あるシステムの試験をしていて、少し奇妙な状況に遭遇しました。
日付を入力しそれをデータベースに登録する、という単純な処理だったのですが、
特定の日付の値が、Scalaで実装されたバリデーションは通るのに、MySQLのテーブルにinsertする際にエラーになってしまうのです。

それは、西暦1000年2月29日、という日付が入力された際に起こる現象でした。

問題となった値は、Scala上ではjava.util.Date、MySQL上ではDATEでそれぞれ扱われていました。
試しにScalaのREPLを使って以下のコードを実行してみます。

すると結果はこのようになりました。

どうやら西暦1000年2月29日として、Date型で扱われるようです。

一方、MySQLの対象となるカラムに問題となる値を入れようとしたところ、
こちらはエラーになりました。

以上のことから、java.util.DateとMySQLのDATEとの間には、暦の解釈において差異があるようです。

このとき、わたしが認識していた閏年の計算アルゴリズムは下記のような具合でした。

  • 西暦が4で割り切れる年は閏年
  • ただし、西暦が100で割り切れる年は平年
  • ただし、西暦が400で割り切れる年は閏年

プログラムの教科書などに記載されている閏年の計算も、上記のアルゴリズムが記載されているはずです。

このアルゴリズムに当てはめて考えてみると、西暦1000年は、

  • 4で割り切れる
  • 100で割り切れる
  • しかし、400で割り切れない

となるので、二番目の条件にHITしますから閏年ではなく平年、ということになります。

これだけを見ると、java.util.Dateの実装に問題があるような気がします。
しかし、同様に2100年や1900年で試してみると、こちらは平年として判断されているようです。

なぜ、javaはわざわざ西暦1000年を閏年として扱うのでしょうか。

java.util.Dateの実装を見てみたところ、内部的にカレンダーの扱いが1582年を境に変わっていることがわかりました。
Date.java#Date.getCalendarSystem

GregorianCalendarクラスのjavadocを読むと、詳しい説明が書かれています。
GregorianCalendar

「グレゴリオ暦への切り換え日の前は、GregorianCalendar ではユリウス暦を実装しています。グレゴリオ暦とユリウス暦の唯一の違いはうるう年の規則です。ユリウス暦は 4 年ごとにうるう年を指定しますが、グレゴリオ暦では、400 で割り切れない世紀の初年をうるう年にしません。」

なるほど。わたしが当初認識していた閏年の計算は、グレゴリオ暦に基づくアルゴリズムであって、
javaでは西暦1582年以前はこのグレゴリオ暦ではなくユリウス暦で閏年を判定しているようです。

ちなみに余談ですが、wikipediaで西暦1000年を見てみると、「西暦(ユリウス暦)による、閏年」とありました。
wikipedia:西暦1000年

MySQLの暦の扱いは、ドキュメントで”proleptic Gregorian calendar”を使用していると定義されています。
これは「先発グレゴリオ暦」といって、1582年以前にもグレゴリオ暦を適用する、という考え方のようです。
PostgreSQLも同様の方式を採用しているようです。
MySQL: MySQL が使用するカレンダーは?
PostgreSQL: 単位の歴史
wikipedia:先発グレゴリオ暦

わたしはこれまで、日付の扱いはすべてのコンピュータシステムで同じであるはず、と思い込んでいました。
しかし、現代の我々が扱っている暦が、実際に適用されていなかった時代の日付の扱いについては、
システムによっていろいろな考え方でそれぞれの仕様が決められているようです。

西暦1000年は閏年かそうじゃないのか? 結論はこうなりました。

  • java.util.Dateでは閏年として扱われる。(1582年以前の暦はユリウス暦になる)
  • MySQLのDATEでは平年として扱われる。(暦は一律グレゴリオ暦になる)

ちなみに、java.util.GregorianCalendar には setGregorianChange というメソッドがあり、これに値をセットすることで暦の切替日を変更できるようです。
GregorianCalendar.setGregorianChange