简体   繁体   English

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

[英]Grails watch files doesn't work inside Docker container running inside a Vagrant virtual machine

I have a fairly nested structure:我有一个相当嵌套的结构:

  1. MacOSX workstation running a... MacOSX 工作站运行...
  2. Vagrant VirtualBox virtual machine with ubuntu/trusty64 running a...带有ubuntu/trusty64 Vagrant VirtualBox 虚拟机运行...
  3. Docker container running... Docker 容器正在运行...
  4. my application written in Grails我用 Grails 编写的应用程序

Every layer is configured in such a way as to share a portion of the file system from the layer above.每一层都以这样一种方式配置,即共享来自上层的文件系统的一部分。 This way:这边走:

  • Vagrant, with config.vm.synced_folder directive in Vagrantfile Vagrant,在Vagrantfile使用config.vm.synced_folder指令
  • Docker, with the -v command like switch and VOLUME directive in the Dockerfile Docker,在Dockerfile使用-v命令,如 switch 和VOLUME指令

This way I can do development on my workstation and the Grails application at the bottom should (ideally) detect changes and recompile/reload on the fly.这样我就可以在我的工作站上进行开发,底部的 Grails 应用程序应该(理想情况下)检测更改并即时重新编译/重新加载。 This is a feature that used to work when I was running the same application straight on the MacOSX, but now grails seems totally unaware of file changes.当我在 MacOSX 上直接运行相同的应用程序时,这是一个曾经可以工作的功能,但现在 grails 似乎完全不知道文件更改。 Of course, if I open the files with an editor (inside the Docker container) they are indeed changed and in fact if I stop/restart the grails app the new code is used.当然,如果我使用编辑器(在 Docker 容器内)打开文件,它们确实会发生变化,事实上,如果我停止/重新启动 grails 应用程序,就会使用新代码。

I don't know how grails implements the watch strategy, but if it depends on some operating system level feature I suspect that file change notifications get lost somewhere in the chain.我不知道 grails 如何实现监视策略,但是如果它依赖于某些操作系统级别的功能,我怀疑文件更改通知会在链中的某个地方丢失。

Anyone has an idea of what could be the cause and/or how I could go about debugging this?任何人都知道可能是什么原因和/或我如何进行调试?

There are two ways to detect file changes (that I'm aware of):有两种方法可以检测文件更改(我知道):

Polling , which means checking timestamps of all files in a folder at a certain interval.轮询,这意味着以一定的时间间隔检查文件夹中所有文件的时间戳。 Getting to "near instant" change detection requires very short intervals.达到“近乎即时”的变化检测需要非常短的时间间隔。 This is CPU and disk intensive.这是 CPU 和磁盘密集型的。

OS Events (inotify on Linux, FSEvents on OS X), where changes are detectable because file operations pass through the OS subsystems.操作系统事件(Linux 上的 inotify,OS X 上的 FSEvents),其中的更改是可检测的,因为文件操作通过操作系统子系统。 This is easy on the CPU and disk.这在 CPU 和磁盘上很容易。

Network File Systems (NFS) and the like don't generate events.网络文件系统 (NFS) 等不生成事件。 Since file changes do not pass through the guest OS subsystem, the OS is not aware of changes;由于文件更改不通过客户操作系统子系统,因此操作系统不知道更改; only the OS making the changes (OS X) knows about them.只有进行更改的操作系统 (OS X) 知道它们。

Grails and many other File Watcher tools depend on FSEvents or inotify (or similar) events. Grails 和许多其他文件观察器工具依赖于 FSEvents 或 inotify(或类似的)事件。

So what to do?那么该怎么办? It's not practical to 'broadcast' NFS changes from host to all guests under normal circumstances, considering the traffic that would potentially generate.考虑到可能产生的流量,在正常情况下将 NFS 更改从主机“广播”到所有来宾是不切实际的。 However, I am of the opinion that VirtualBox shares should count as a special exception...但是,我认为 VirtualBox 的股票应该算作一个特殊的例外......

A mechanism to bridge this gap could involve a process that watches the host for changes and triggers a synchronization on the guest.弥合这一差距的机制可能涉及一个过程,该过程观察主机的变化并触发来宾上的同步。

Check these articles for some interesting ideas and solutions, involving some type of rsync operation:查看这些文章以获取一些有趣的想法和解决方案,涉及某种类型的 rsync 操作:

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

Rsync-ing to a non-NFS folder on your guest (Docker) instance has the additional advantage that I/O performance increases dramatically. Rsync-ing 到您的来宾 (Docker) 实例上的非 NFS 文件夹具有额外的优势,即 I/O 性能显着提高。 VirtualBox shares are just painfully slow. VirtualBox 的共享速度非常缓慢。

Update!更新!

Here's what I did.这就是我所做的。 First install lsyncd (OS X example, more info at http://kesar.es/tag/lsyncd/ ):首先安装lsyncd (OS X 示例,更多信息请访问http://kesar.es/tag/lsyncd/ ):

brew install lsyncd

Inside my Vagrant folder on my Mac, I created the file lsyncd.lua :在 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"
    },
}

What this does, is sync the folder demo inside my Vagrant folder to the guest OS in /home/vagrant/demo .这样做是将我的 Vagrant 文件夹中的文件夹demo同步到/home/vagrant/demo的来宾操作系统。 Note that you need to set up login with SSH keys to make this process frictionless.请注意,您需要使用 SSH 密钥设置登录,以使此过程顺畅无阻。

Then, with the vagrant VM running, I kicked off the lsyncd process.然后,随着 vagrant VM 的运行,我启动了 lsyncd 进程。 The -log Exec is optional; -log Exec是可选的; it logs its activity to the stdout:它将其活动记录到标准输出:

sudo lsyncd lsyncd.lua -log Exec 

On the vagrant VM I started Grails (2.4.4) in my synced folder:在 vagrant VM 上,我在同步文件夹中启动了 Grails (2.4.4):

cd /home/vagrant/demo
grails -reloading run-app

Back on my Mac in IntelliJ I edited a Controller class.回到我在 IntelliJ 中的 Mac 上,我编辑了一个 Controller 类。 It nearly immediately triggered lsyncd (2 sec delay) and quickly after that I confirmed Grails recompiled the class!它几乎立即触发了 lsyncd(延迟 2 秒),之后我确认 Grails 重新编译了该类!

To summarize:总结一下:

  • Edit your project files on your Mac, execute on your VM在 Mac 上编辑项目文件,在 VM 上执行
  • Use lsyncd to rsync your changes to a folder inside your VM使用 lsyncd 将更改同步到 VM 内的文件夹
  • Grails notices the changes and triggers a reload Grails 注意到更改并触发重新加载
  • Much faster disk performance by not using VirtualBox share通过不使用 VirtualBox 共享来提高磁盘性能

Issues: Textmate triggers a type of FSEvent that lsyncd does not (yet) recognize, so changes are not detected.问题: Textmate 会触发一种 lsyncd(尚未)识别的 FSEvent,因此未检测到更改。 Vim and IntelliJ were fine, though.不过,Vim 和 IntelliJ 都很好。

Hope this helps someone!希望这可以帮助某人! Took me a day to figure this stuff out.我花了一天时间才弄清楚这些东西。

The best way I have found to have filesystem notifications visible within the container was as follows:我发现在容器内显示文件系统通知的最佳方法如下:

  1. Create two folders, one to map the project and a "mirror"创建两个文件夹,一个用于映射项目,一个用于“镜像”
  2. Map the project in the first folder映射第一个文件夹中的项目
  3. Keep a background script running in the container, rsyncing the project folder to "mirror"在容器中保持后台脚本运行,将项目文件夹同步到“镜像”
  4. Run the project from "mirror"从“镜像”运行项目

It may not be the most efficient or most elegant way, but this way was transparent to users of the container.它可能不是最有效或最优雅的方式,但这种方式对容器的用户来说是透明的。 No additional script needs to be run.不需要运行额外的脚本。

Not tested in a larger project, but in my case I did not realize performance issues.没有在更大的项目中测试,但就我而言,我没有意识到性能问题。

https://github.com/altieres/docker-jekyll-s3 https://github.com/altieres/docker-jekyll-s3

Vagrant already includes some options for rsync, so it's not necessary to install a special program on the host machine. Vagrant 已经包含了 rsync 的一些选项,因此不需要在主机上安装特殊程序。

In Vagrantfile, I configured rsync:在 Vagrantfile 中,我配置了 rsync:

config.vm.synced_folder ".", "/vagrant", type: "rsync",  rsync__exclude: [ "./build", ".git/" ]

Then on command line (in host), I run:然后在命令行(在主机中),我运行:

vagrant rsync

Which performs a single synchronization from host to guest.它执行从主机到来宾的单一同步。

or或者

vagrant rsync-auto

Which runs automatically when changes on host are detected.当检测到主机上的更改时,它会自动运行。

See more at Vagrant rsync Documentation and rsync-autoVagrant rsync 文档rsync-auto 中查看更多信息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM