Grails 监视文件在 Vagrant 虚拟机内运行的 Docker 容器内不起作用

Ste*_*ini 5 filesystems grails vagrant docker

我有一个相当嵌套的结构:

  1. MacOSX 工作站运行...
  2. Vagrant VirtualBox 虚拟机ubuntu/trusty64运行...
  3. Docker 容器正在运行...
  4. 我用 Grails 编写的应用程序

每一层都以这样一种方式配置,以共享来自上层的文件系统的一部分。这边走:

  • Vagrant,在config.vm.synced_folder指令中Vagrantfile
  • Docker 中的-v命令如 switch 和VOLUME指令Dockerfile

这样我就可以在我的工作站上进行开发,底部的 Grails 应用程序应该(理想情况下)检测更改并即时重新编译/重新加载。当我在 MacOSX 上直接运行相同的应用程序时,这是一个曾经可以工作的功能,但现在 grails 似乎完全不知道文件更改。当然,如果我使用编辑器(在 Docker 容器内)打开文件,它们确实会发生变化,事实上,如果我停止/重新启动 grails 应用程序,就会使用新代码。

我不知道 grails 如何实现监视策略,但是如果它依赖于某些操作系统级别的功能,我怀疑文件更改通知会在链中的某个地方丢失。

任何人都知道可能是什么原因和/或我如何进行调试?

Roy*_*mse 1

有两种方法可以检测文件更改(据我所知):

轮询,即以一定的时间间隔检查文件夹中所有文件的时间戳。达到“近乎即时”的变化检测需要非常短的时间间隔。这是 CPU 和磁盘密集型的。

操作系统事件(Linux 上的 inotify,OS X 上的 FSEvents),其中的更改是可检测的,因为文件操作会通过操作系统子系统。这对 CPU 和磁盘来说很容易。

网络文件系统 (NFS) 等不会生成事件。由于文件更改不会通过来宾操作系统子系统,因此操作系统不知道更改;只有进行更改的操作系统(OS X) 知道它们。

Grails 和许多其他文件观察器工具依赖于 FSEvents 或 inotify(或类似)事件。

那么该怎么办?考虑到可能产生的流量,在正常情况下将 NFS 更改从主机“广播”到所有来宾是不切实际的。然而,我认为 VirtualBox 股票应该算作一个特殊的例外......

弥补这一差距的机制可能涉及一个监视主机变化并触发客户机同步的进程。

查看这些文章,了解一些有趣的想法和解决方案,涉及某种类型的 rsync 操作:

http://drunomics.com/en/blog/syncd-sync-changes-vagrant-box (Linux) https://github.com/ggreer/fsevents-tools (OS X)

Rsync 到来宾 (Docker) 实例上的非 NFS 文件夹具有 I/O 性能显着提高的额外优势。VirtualBox 的分享速度慢得令人痛苦。

更新!

这就是我所做的。首先安装lsyncd(OS X 示例,更多信息请访问http://kesar.es/tag/lsyncd/):

brew install lsyncd
Run Code Online (Sandbox Code Playgroud)

在 Mac 上的 Vagrant 文件夹中,我创建了文件lsyncd.lua

settings {
    logfile = "./lsyncd.log",
    statusFile = "./lsyncd.status",
    nodaemon = true,
    pidfile = "./lsyncd.pid",
    inotifyMode = "CloseWrite or Modify",
}

sync {
    default.rsync,
    delay = 2,
    source = "./demo",
    target = "vagrant@localhost:~/demo",
    rsync = {
        binary   = "/usr/bin/rsync",
        protect_args = false,
        archive = true,
        compress = false,
        whole_file = false,
        rsh = "/usr/bin/ssh -p 2222 -o StrictHostKeyChecking=no"
    },
}
Run Code Online (Sandbox Code Playgroud)

其作用是将demo我的 Vagrant 文件夹内的文件夹同步到/home/vagrant/demo. 请注意,您需要使用 SSH 密钥设置登录,以使此过程顺利进行。

然后,随着 vagrant VM 的运行,我启动了 lsyncd 进程。是-log Exec可选的;它将其活动记录到标准输出:

sudo lsyncd lsyncd.lua -log Exec 
Run Code Online (Sandbox Code Playgroud)

在 vagrant VM 上,我在同步文件夹中启动了 Grails (2.4.4):

cd /home/vagrant/demo
grails -reloading run-app
Run Code Online (Sandbox Code Playgroud)

回到 Mac 上的 IntelliJ,我编辑了一个 Controller 类。它几乎立即触发了 lsyncd(2 秒延迟),之后我很快就确认 Grails 重新编译了该类!

总结一下:

  • 在 Mac 上编辑项目文件,在 VM 上执行
  • 使用 lsyncd 将更改同步到虚拟机内的文件夹
  • Grails 注意到更改并触发重新加载
  • 不使用 VirtualBox 共享,磁盘性能更快

问题: Textmate 触发 lsyncd(尚)无法识别的 FSEvent 类型,因此无法检测到更改。不过,Vim 和 IntelliJ 都很好。

希望这对某人有帮助!我花了一天时间才弄清楚这些东西。