私は普段 Windows 上でコーティングを行い、そのコードを仮想環境の Linux で動かしています。 そのためには Windows → VM(Linux) でコードを同期する必要があるのですが、過去に幾つかの方法を試行錯誤してきました。
- WinSCP で Linux 上のファイルをエディタで直接編集
- ありえん
- Linux から Windows の共有フォルダを cifs でマウント
- いまここ
- Linux の samba でエクスポートしたディレクトリを Windows でマウント
- VM を起動しておかないとコードを見ることすらできない
- VCS(Subversion)との相性が悪かった
- クライアント側(TortoiseSVN)の問題だったのかも
- WinSCP のミラーリングで Windows から Linux にアップロード
- VMware Player の共有フォルダ機能を使う
- cifs よりもファイルのI/Oが遅い気がする
- Linux 機がローカルの VM だとは限らない
- 社内にわりと自由に使える ESXi があるのです
- Eclipse FileSync で同期
- Bvckup で同期
- 同期先は samba でエクスポートした Linux 上のディレクトリ
- 微妙に遅延する
- これそういう用途のものじゃない
いろいろ試した結果、初期の頃の「2. Linux から Windows の共有フォルダを cifs(samba) でマウント」に落ち着きました。
Linux から Windows の共有フォルダを cifs でマウントする方法
ググれば色々出てくるので省略。
問題点
この方法には幾つかの問題点・・・というか気になる点がありました。
ReadOnly でマウントしているのでデータやログの書き込みが出来ない
なんとなく cifs では ro でマウントしています。
rw でマウントすれば解決ですが、できるだけそれはやりたくないのです。 WinSCP でローカルのファイルを以下略した経験が活きているのです。
これはアプリの設定ファイルとかでファイルの書き込み先を変更できれば解決です。
define('LOG_DIR', __DIR__ . '/log/');
とかやると変更できないのでやめて欲しいです。
最近のプロジェクトでは必ずアプリの設定ファイルで変更できるようにしているので問題なしですが、 そうじゃなかった頃のプロジェクトも少なからずあります。
Framework や ライブラリまで cifs 経由なので動作がもっさり
最近は PHP 界隈で Composer というものが流行っていて、Framework や ライブラリもプロジェクトローカルの vendor/ ディレクトリに配置するのが主流です。
以前はこの問題を見越してプロジェクト外のディレクトリに配置するようにしていたのですが、時代の流れには逆らえないのです。
Composer で pear からインストールすると絶対パスがファイルに書き込まれることがある
PHPUnit を pear からインストールしていた頃にこの問題に直面しました。 どうしようもありません。
PHPUnit ぐらいなら composer ではなく pear でシステムワイドに入れてしまってもいいかもしれません。
解決方法
これらの問題を一撃で解決する方法、それが mount --bind
です。
mount --bind
はマウント済のディレクトリツリーを別のツリーに再マウントする機能で、グルると色々出てきます。
- http://linuxjm.sourceforge.jp/html/util-linux/man8/mount.8.html
- http://aikotobaha.blogspot.jp/2011/10/bind-mount.html
- http://qiita.com/tukiyo/items/243da17ce398e2b0b9d6
mount --bind
はファイルシステムを超えることが出来るので、
cifs でマウントした先の一部のディレクトリを mount --bind
でローカルのディレクトリに再マウントすることができます。
$ sudo mount -t cifs //ore-pc/project /home/ore/project -o (略) $ mkdir -p /home/ore/project-l/vendor $ sudo mount --bind /home/ore/project-l/vendor /home/ore/project/vendor $ cd /home/ore/project $ php composer.phar install
これで /home/ore/project
は cifs でマウントされていますが /home/ore/project/vendor
はローカルのディレクトリになります。
ここまで出来れば /etc/fstab
で起動時に自動でマウントされるようにしたくなります。
mount --bind
を /etc/fstab
に記述するときは、ファイルシステムを none、マウントオプションに bind を指定すればいいので・・・
//ore-pc/project /home/ore/project cifs (略) /home/ore/project-l/vendor /home/ore/project/vendor none bind
また、cifs のようなネットワークファイルシステムを起動時にマウントする場合、netfs サービスを有効にしておきます。
$ chkconfig netfs on
ファイルシステムのマウントはネットワークの始動よりも先に行われますが、 当然 nfs や cifs のようなネットワークファイルシステムはネットワークの始動後でなければマウント出来ません。 netfs はネットワークの始動後に nfs や cifs をマウントしてくれるようにするためのサービスです。
これで完成・・・かと思いきや、まだこれだけではうまくいきません。cifs のマウントよりも --bind
のマウントの方が先に行われてしまうからです。
そのため・・・
- 起動時の
mount --bind
でマウントポイントが無くて失敗する - シャットダウン時に cifs がアンマウントできなくてシャットダウンが停止する
といった問題が発生します。
長らくこの問題を解決する方法がわからなかったため、起動時は手動でマウント/シャットダウン時は手動でアンマウント、したり、 別の方法を模索したりしていたのですが、netfs のスクリプトを眺めていたら簡単な解決方法がわかりました。
先に述べた netfs は nfs や cifs などのファイルシステムを、起動時はネットワークの始動後にマウントしたり、
シャットダウン時にはネットワークの停止前にアンマウントしたりするものですが、
その条件(ネットワークファイルシステムと認識される条件)は、ファイルシステムが nfs や cifs のようなネットワークファイルシステムであること以外に、
マウントオプションに _netdev
が付いている、というものもありました。
なので /etc/fstab
に次のように記述すれば大丈夫でした。
//ore-pc/project /home/ore/project cifs (略) /home/ore/project-l/vendor /home/ore/project/vendor none bind,_netdev
これで mount --bind
もネットワーク始動後(の cifs のマウントの後)に行われるようになり、問題は解決です。