- 2014-03-13 (木) 17:30
- Vagrant
Vagrant 1.5 がリリースされました。1.1 以来の big change ということで、目新しい機能が追加されています。
目玉はやはり Vagrant Share だと思うのですが、その他にも Web システムの開発に Vagrant を使っている人には嬉しい機能が追加されています。
その一つが Rsync Synced Folder です。
Rsync Synced Folder
Vagrant には、ホストマシンとゲストマシンとでファイルを共有、同期する機能があります。
これにより、開発はホストマシンで行い、実行は LA(MP)P 環境であるゲストマシンで行うという、いいとこ取りができました。
この機能を実現する方法として、shared folder(VirtualBox の機能)や NFS を利用することができたのですが、これに rsync による同期が追加されました。
ホストマシンからゲストマシンへ rsync で同期を行います。
嬉しいこと
Rsync Synced Folder は、rsyncで同期を行うだけなので、ゲストマシン側はネイティブなファイルシステムが利用できます。つまり、synced folder の仕様に影響されなくなります。
パフォーマンス
分かりやすいメリットとしては、VirtualBox の shared folder に比べると、パフォーマンスが向上します。手元にある PHP アプリケーションでは、shared folder で 90 秒程度かかっていたユニットテストが、60 秒程度に短縮しました。
また、NFS と違って、ホスト側でデーモンを起動しておく必要が無いのも大きなメリットです。
パーミッション
shared folder では、パーミッションをディレクトリやファイルごとに設定することができなかったのですが、rsync を利用すれば、ゲストマシンからは通常のファイルシステムなので何も支障がありません。
ただ、現状の Rsync Synced Folder では、同期時にファイルオーナーを強制的に書き換える仕様になっているので、この点については留意しておく必要があります。(後述)
自動更新機能
この rsync は、基本的にはvagrant up
, vagrant reload
, vagrant provision
、そして今回新設されたvagrant rsync
コマンド実行時に行われます。
これだとファイルを変更する度にコマンドを実行するのが面倒になるのですが、vagrant rsync-auto
コマンドを実行することで、自動で同期を行うことができます。設定で同期対象となったディレクトリに変更があれば、自動で同期処理を行います。
どのようなプロバイダでも同期可能
AWS や DigitalOcean のようなクラウドサービスをプロバイダとして使っている場合も、rsync-auto による自動同期が可能です。
コードを変更すると、クラウド上のサーバに自動で同期されます。
要件
この機能を利用するには、ホストとゲストの双方にrsyncコマンドが必要になります。
ホストについては、OSX であればデフォルトでインストールされています。
ゲストについては、もしインストールされていなくても、主要な OS については、Vagrant が自動でインストールしてくれます。例えば、RedHat 系であれば yum -y install rsync
が実行されます。
これは気が効いてますね。
設定
Vagrantfile の synced folder の設定で、type=rsync
を指定します。
config.vm.synced_folder "src", "/share", type: "rsync"
設定には下記のようなオプションがあります。
- rsync__args
rsync コマンドに渡す引数です。デフォルトでは["--verbose", "--archive", "--delete", "-z"]
が指定されています。 -
rsync__auto
rsync-auto による自動同期の対象にするかどうかです。デフォルトは、true
です。 -
rsync__exclude
同期の対象外にするファイルやディレクトリを指定します。デフォルトでは[".vagrant/"]
が指定されています。
例えば、.git ディレクトリは同期対象から外すなら、下記のようにrsync__exclude
を指定します。
config.vm.synced_folder "src", "/share", type: "rsync", rsync__exclude: [".git/"]
手動で同期する
vagrant up
、vagrant reload
、vagrant provision
、vagrant rsync
を実行すると、Vagrantfile の synced_folder で指定したディレクトリについて、rsync による同期を行います。
ファイルを同期したいだけなら、vagrant rsync
を実行します。
$ vagran rsync ==> default: Rsyncing folder: /path/to/src/ => /share
自動で同期する
自動で同期するには、vagrant rsync-auto
コマンドを実行します。コマンドを実行すると、synced_folder で指定した同期対象のディレクトリを監視します。
$ vagrant rsync-auto ==> default: Watching: /path/to/src/
同期対象のディレクトリに変更があると、自動でrsyncが実行され、同期されます。
$ vagrant rsync-auto ==> default: Watching: /path/to/src/ ==> default: Rsyncing folder: /path/to/src/ => /share
ホストで開発して、ゲストで実行するというスタイルなら、常に rsync-auto を実行しておくと良いでしょう。
注意点
ホストからゲストの同期のみ
現在のところ、同期はホストからゲストの一方向のみです。
ゲストからホストへファイルを転送するvagrant rsync --pull
というのが、issue で提案されているので、いずれ実装されるかもしれません。
https://github.com/mitchellh/vagrant/issues/3062
rsync 実行でファイルオーナーが変更される
rsync-auto を使っている時に気づいたのですが、rsyncの実行前にゲスト側の同期ディレクトリに対してchown -R vagrant /path
を実行して、ファイルオーナーを変更しています。
同期対象ディレクトリを丸ごとホスト側と同期するなら特に問題無いのですが、ゲストでアプリケーションが実行時に生成するファイル(ログファイル等)をrsync__exclude
オプションで同期対象外にしている時に問題が発生します。
例えば、アプリケーションがapp/storage/log/
以下にログファイルを出力する場合、このディレクトリを同期対象外とします。
config.vm.synced_folder "src", "/share", type: "rsync", rsync__exclude: [".git/", "app/storage/log/*"]
この時、アプリケーションを実行するとゲストでは、下記のようにアプリケーションの実行ユーザである apache ユーザによってログファイル(laravel.log)が生成されます。
[vagrant@localhost /share]$ ls -la app/storage/log/ drwxrwxrwx. 2 vagrant vagrant 4096 3月 13 05:51 2014 . drwxrwxrwx. 7 vagrant vagrant 4096 2月 13 07:50 2014 .. -rw-rw-rw-. 1 vagrant vagrant 13 2月 13 07:50 2014 .gitignore -rw-r--r--. 1 apache apache 5394 3月 13 05:51 2014 laravel.log
次にホスト側で vagrant rsync
で同期します。
$ vagrant rsync ==> default: Rsyncing folder: /path/to/src/ => /share
ゲスト側では laravel.log は、同期対象外となっているのでファイルはそのまま残っています。しかし、ファイルオーナーが vagrant に変更されています。
[vagrant@localhost /share]$ ls -la app/storage/log/ drwxrwxrwx. 2 vagrant vagrant 4096 3月 13 05:51 2014 . drwxrwxrwx. 7 vagrant vagrant 4096 2月 13 07:50 2014 .. -rw-rw-rw-. 1 vagrant vagrant 13 2月 13 07:50 2014 .gitignore -rw-r--r--. 1 vagrant apache 5394 3月 13 05:51 2014 laravel.log
この状態でアプリケーションを実行すると、ログファイルへの書き込み権限が無いためにエラーが発生します。
Vagrant のソースを見ると、plugins/guests/linux/cap/rsync.rb で、rsync 前に実行する処理が定義されているのですが、たしかにsudo chown -R
が実行されています。
def self.rsync_pre(machine, folder_opts) username = machine.ssh_info[:username] machine.communicate.tap do |comm| comm.sudo("mkdir -p '#{folder_opts[:guestpath]}'") comm.sudo("chown -R #{username} '#{folder_opts[:guestpath]}'") end end
おそらく、vagrant rsync
を実行する際に、Permission Denied が出ないように、一括でchown
しているのだと思うのですが、ここは注意しておく必要があります。
rsync-auto を忘れる
これはケアレスミスなのですが、VirtualBox の shared folder や NFS であれば、自動で同期するので、ホストでコードを変更したのに、ゲストに反映されずに「あれ?」となったことが何度かありました。
vagrant rsync-auto
を実行しないと、自動で同期されないので、忘れずに。
さいごに
Rsync Synced Folder を使うことで、shared folder で気になっていた点が解決しそうです。なんといっても、ユニットテストが速くなるのはありがたいですね。
- Newer: Laravel コードで見るファサードクラスの仕組み
- Older: composer install をどこで実行するか