Vagrantconfiguration脚本在VM完全启动之前运行?

我正在准备一个Vagrant框,以及一个shell脚本作为configuration文件。 我已经花了几天的时间,现在看起来稳定和完整。 基础盒子是Ubuntu 12.04(32位),在虚拟机上运行Postgres,Redis和Memcached。 configuration脚本设置Nginxconfiguration,创build一个空白数据库,并做一些基本的pipe家工作。

当我来打包虚拟机,并试图在家里的另一台机器上重新运行虚拟机时,我在第一次运行( vagrant up )时遇到了一个问题,因为没有任何服务正在运行 – 所以我尝试运行dropdbcreatedb失败。

深入探讨为什么发生这种情况(我是一个前Windows的家伙,所以这需要做一些)我发现自己在运行级别和/etc/rc[0-6,S].d文件。

我有三个我感兴趣的服务的相关S(开始)文件:

 vagrant@precise32:~$ ls -l /etc/rc2.d total 4 -rw-r--r-- 1 root root 677 Apr 14 2012 README lrwxrwxrwx 1 root root 20 Dec 29 10:05 S19postgresql -> ../init.d/postgresql lrwxrwxrwx 1 root root 19 Dec 29 10:05 S20memcached -> ../init.d/memcached lrwxrwxrwx 1 root root 15 Dec 29 10:05 S20nginx -> ../init.d/nginx lrwxrwxrwx 1 root root 22 Dec 29 10:05 S20redis-server -> ../init.d/redis-server ... 

和K文件运行级别0(关机),所以似乎都是按顺序:

 vagrant@precise32:~$ ls -l /etc/rc0.d total 4 lrwxrwxrwx 1 root root 19 Dec 29 10:05 K20memcached -> ../init.d/memcached lrwxrwxrwx 1 root root 15 Dec 29 10:05 K20nginx -> ../init.d/nginx lrwxrwxrwx 1 root root 22 Dec 29 10:05 K20redis-server -> ../init.d/redis-server lrwxrwxrwx 1 root root 20 Dec 29 10:05 K21postgresql -> ../init.d/postgresql .... 

这似乎表明,底层的虚拟机运行级别不是2,所以为了debugging这个问题,我创build了一个新的configuration脚本来输出。)configuration时的运行级别,以及b。)预期的进程正在运行(memcache,prostgres,redis):

 ps aux | grep memcache ps aux | grep postgres ps aux | grep redis # expected output is 'N 2' runlevel 

我跑了vagrant destroy ,然后在这上面vagrant up ,结果如下:

 [default] Running provisioner: Vagrant::Provisioners::Shell... root 791 0.0 0.2 4624 840 ? S 10:33 0:00 grep memcache root 793 0.0 0.2 4624 836 ? S 10:33 0:00 grep postgres root 795 0.0 0.2 4624 840 ? S 10:33 0:00 grep redis unknown 

即服务在configuration脚本运行的时候没有运行,而更令人困惑的是, runlevel命令甚至不被识别。

如果我反复在正在运行的虚拟机上重新运行configuration脚本,使用vagrant provision ,我在运行的前几次得到相同的结果,然后最终(2-3分钟后)我看到我第一次预期的结果回合:

 [default] Running provisioner: Vagrant::Provisioners::Shell... memcache 1103 0.2 0.2 46336 1072 ? Sl 10:56 0:00 /usr/bin/memcached -m 64 -p 11211 -u memcache -l 127.0.0.1 root 1267 0.0 0.2 4624 840 ? S 10:56 0:00 grep memcache postgres 1073 13.0 2.0 50440 7828 ? S 10:56 0:02 /usr/lib/postgresql/9.1/bin/postgres -D /var/lib/postgresql/9.1/main -c config_file=/etc/postgresql/9.1/main/postgresql.conf postgres 1077 0.3 0.3 50440 1248 ? Ss 10:56 0:00 postgres: writer process postgres 1078 0.3 0.3 50440 1244 ? Ss 10:56 0:00 postgres: wal writer process postgres 1079 0.1 0.6 50860 2296 ? Ss 10:56 0:00 postgres: autovacuum launcher process postgres 1080 0.0 0.3 20640 1284 ? Ss 10:56 0:00 postgres: stats collector process root 1269 0.0 0.2 4624 836 ? S 10:56 0:00 grep postgres redis 1123 0.6 0.2 3292 1036 ? Ss 10:56 0:00 /usr/bin/redis-server /etc/redis/redis.conf root 1271 0.0 0.2 4624 840 ? S 10:56 0:00 grep redis N 2 

看起来这只是需要一点时间才能出现,这对我来说是一个很大的问题,因为configuration脚本首次会失败。

这是一个已知的情况,如果是这样,解决scheme是什么? 理想情况下,configuration脚本将暂停,直到运行级别变为2,即该框已准备好接受shell命令。

[更新:HACK]

我已经设法通过一起攻击以下脚本来解决此问题:

 while [ "`runlevel`" = "unknown" ]; do echo "runlevel is 'unknown' - waiting for 10s" sleep 10 done echo "runlevel is now valid ('`runlevel`'), kicking off provisioning..." 

我把这个保存为“preprovision.sh”,我的Vagrantfile现在看起来像:

 # Enable provisioning with a shell script. config.vm.provision :shell, :path => "pre-provision.sh" config.vm.provision :shell, :path => "provision.sh", :args => "myapp" 

这给出了以下输出:

 [default] Running provisioner: Vagrant::Provisioners::Shell... runlevel is 'unknown' - waiting for 10s runlevel is 'unknown' - waiting for 10s runlevel is 'unknown' - waiting for 10s runlevel is 'unknown' - waiting for 10s runlevel is 'unknown' - waiting for 10s runlevel is 'unknown' - waiting for 10s runlevel is 'unknown' - waiting for 10s runlevel is 'unknown' - waiting for 10s runlevel is 'unknown' - waiting for 10s runlevel is 'unknown' - waiting for 10s runlevel is 'unknown' - waiting for 10s runlevel is now valid ('N 2'), kicking off provisioning... [default] Running provisioner: Vagrant::Provisioners::Shell... ... 

然后原来的provision.sh运行,一切正常。

我没有把这个标记为答案(虽然这是一个答案),因为我仍然想知道我该怎么做 – 这不可能是它的工作方式,当然?

原来,最简单的方法是查找相关进程的PID文件(请参阅本文以获取关于pid文件的解释 – 什么是.pid文件,它包含什么内容? )

 NGINX_PID=/var/run/nginx.pid ... ## set up nginx configuration using .config from shared directory if [ ! -f $NGINX_PID ]; then echo "---> Waiting for for Nginx process to spin up" while [ ! -f $NGINX_PID ]; do echo . sleep 1 done fi