我在带有VirtualBox的Windows7机器上使用流浪者和docker作为docker主机VM的提供者。我用docker
提供程序定义了一个流浪项目,以便vagrant up
启动mongo
容器。我没有在docker主机VM中配置mongo
容器,因为我有时需要mongo
,有时需要postgres
等。
对于mongo
的情况,我试图针对这个正在运行的mongo
容器运行一些mongo集合初始化脚本,以使用流浪设置索引等。mongo
映像不运行除mongod
以外的任何操作,因此has_ssh
是容器的false
,因此不能使用预设置器来运行这些操作。
我曾尝试在一个单独的容器中运行mongoshell,该容器链接到运行mongodb
的容器,但为了实现这一点,我需要能够在容器中运行命令时扩展mongo
环境变量(MONGO_PORT_27017_TCP_ADDR
和MONGO_PORT_27017_TCP_PORT
)。
我一直在尝试使用vagrant docker-run
来实现这一点,但我找不到一种方法来正确解释命令,从而正确扩展这些环境变量。每次尝试都会导致mongo
命令抱怨没有提供主机和端口(环境变量扩展为空)。
我最终想做的是:
- 启动一个链接到正在运行的mongo容器的容器(这样它就可以获得其env变量)
- 将一个javascript文件上传到新容器中,其中包括我想要进行的mongo初始化
- 在容器上运行shell命令,如下所示:
mongo "$MONGO_PORT_27017_TCP_ADDR:$MONGO_PORT_27017_TCP_PORT/db-name" initialize.js
- 取出容器
有什么建议或其他我可以尝试的方法吗?
典型失败命令示例
Powershell是这个Windows系统上的命令行解释器:
PS C:UsershoobajoobDocumentsEclipseworkspace-sts-lunaproject.environmentvagrantmongo-provisioner> vagrant docker-run default -- mongo
'$MONGO_PORT_27017_TCP_ADDR:`$MONGO_PORT_27017_TCP_PORT/test' --eval "printjson(db.getCollectionNames())"
==> default: Docker host is required. One will be created if necessary...
default: Docker host VM is already ready.
==> default: Creating the container...
default: Name: mongo-provisioner_default_1449193166_1449193166
default: Image: mongo
default: Cmd: mongo $MONGO_PORT_27017_TCP_ADDR:$MONGO_PORT_27017_TCP_PORT/test
default: Link: mongo-container:mongo
default:
default: Container is starting. Output will stream in below...
default:
default: MongoDB shell version: 3.0.7
default: 2015-12-04T01:38:20.037+0000 E QUERY Error: Missing host name in connection string ":/test"
default: at Error (<anonymous>)
default: at connect (src/mongo/shell/mongo.js:160:15)
default: at (connect):1:6 at src/mongo/shell/mongo.js:160
default: exception:
default: connect failed
default:
A Docker command executed by Vagrant didn't complete successfully!
The command run along with the output from the command is shown
below.
Command: "docker" "run" "--name" "mongo-provisioner_default_1449193166_1449193166" "--link" "mongo-container:mongo" "--rm=true" "mongo" "mongo" "$MONGO_POR
T_27017_TCP_ADDR:$MONGO_PORT_27017_TCP_PORT/test" "--eval" "printjson(db.getCollectionNames())"
Stderr: exception: connect failed
Stdout: MongoDB shell version: 3.0.7
2015-12-04T01:38:20.037+0000 E QUERY Error: Missing host name in connection string ":/test"
at Error (<anonymous>)
at connect (src/mongo/shell/mongo.js:160:15)
at (connect):1:6 at src/mongo/shell/mongo.js:160
来源
docker主机Vagrantfile
:
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.require_version ">= 1.6.0"
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.hostname = "docker-host"
config.vm.box_check_update = false
config.ssh.insert_key = false
config.vm.box = "williamyeh/ubuntu-trusty64-docker"
config.vm.network "forwarded_port", guest: 27017, host: 27017
config.vm.synced_folder ".", "/vagrant", disabled: true
end
mongod
容器Vagrantfile
:
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.require_version ">= 1.6.0"
VAGRANTFILE_API_VERSION = "2"
ENV['VAGRANT_DEFAULT_PROVIDER'] = 'docker'
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.provider "docker" do |docker|
docker.vagrant_vagrantfile = "../docker-host/Vagrantfile"
docker.image = "mongo"
docker.ports = ['27017:27017']
docker.name = 'mongo-container'
end
end
mongo shell
容器Vagrantfile
(这是我试图运行vagrant docker-run
命令的容器,以便正确扩展链接到mongod
容器的mongo环境变量):
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Specify Vagrant version and Vagrant API version
Vagrant.require_version ">= 1.6.0"
VAGRANTFILE_API_VERSION = "2"
ENV['VAGRANT_DEFAULT_PROVIDER'] = 'docker'
# Create and configure the Docker container(s)
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.provider "docker" do |docker|
docker.vagrant_vagrantfile = "../docker-host/Vagrantfile"
docker.image = "mongo"
docker.link("mongo-container:mongo")
end
end
目前,我发现Vagrant的docker提供商在我可以使用它执行的docker容器操作范围方面相当有限。
我研究了在mongo容器中运行ssh
,这将允许我在mongo
容器上运行Vagrant的provisioner,这样我就可以让这些脚本以这种方式运行。但是,这需要a)定义自定义图像并重新设计入口点,以便启动ssh
和mongod
,以及b)在docker提供程序Vagrantfile
中设置has_ssh=true
。
不幸的是,这个选项在当前版本的流浪汉中不起作用,当我在docker提供程序Vagrantfile
中将has_ssh
设置为true
时,当我运行vagrant up
时,它会挂在我的Windows系统上。
所以,对于这个流浪的新手来说,我的选择似乎是有限的。
我目前认为,更好的方法可能是完全放弃使用两个docker提供程序Vagrantfile
项目,而是在一个docker主机Vagrantfile
中定义一堆不同的提供程序。
然后,如果我想启动一个特定的容器,我可以定义并运行一个只运行该容器的provisioner(不执行任何mongo初始化)。如果我想运行这些mongo初始化脚本,那么我有一个单独的provisioner来执行这些操作,等等
拆下容器将需要使用相应的docker rm
命令运行vagrant ssh
。
这样做似乎很遗憾,但我在尝试通过vagrant docker-run
初始化mongo时运气不佳。
更新:12/4/2015
我完全放弃了使用Vagrant的docker提供者,主要是因为,至少在我的情况下,我发现docker提供者在其支持的docker词汇方面过于有限,无法满足我的需求。我不是《流浪者》或《Docker》的老手,所以我完全有可能错过了什么。
因此,例如,为了初始化mongo数据库,我更希望能够使用相同的javascript初始化文件来进行初始化,这些文件可能由目标站点的mongoDB
管理员运行,并且这些文件来自dev源代码树。必须构建一个预先提供了这些文件的自定义docker-mongo容器,这会带来太多的开销。
至少就我所知,Vagrant的方法是使用file
提供程序将该文件复制到正在运行的容器,并使用script
提供程序在容器上执行该文件。Vagrant的file
和script
提供程序需要容器上的SSH才能工作。
但是,在docker领域,不在容器中运行SSH似乎是一个常见的建议,原因有很多,所以如果不必要的话,我宁愿不这样做。
在不创建预先配备有这些文件的自定义容器的情况下实现这一点的(或一种)docker方法是使用docker cp <container>
和docker exec <container>
,以便在运行的容器上实现这一目标。Vagrant的docker provider命令都没有显示这两种情况,所以我不知道如何通过docker providers到达那里。
因此,我相信,使用Vagrant的Provisioner是完全合理的,但只有在与docker主机VM(在我的情况下是一个VirtualBox盒子)交互时,SSH访问对其没有任何争议(据我所知)。
我将所有容器生命周期操作(创建、启动、停止、重新启动、rm等)都移到了docker主机的Vagrantfile
配置上的provisioner中。为了执行这些操作,我坚持使用docker cli。
Docker主机虚拟机上的Vagrantfile
提供程序如下所示:
# provisioners
config.vm.provision "host.provision.scripts.mongo", type: "file", source: $mongoProvisionInit, destination: $hostProvisionMongoInit
config.vm.provision "mongo.run", type: "shell", inline: $dockerRun_mongo
config.vm.provision "mongo.provision.scripts", type: "shell", inline: $dockerCp_MongoInit
config.vm.provision "mongo.db.init", type: "shell", inline: $dockerExec_mongoDbInit
config.vm.provision "mongo.stop", type: "shell", inline: $dockerStop_mongo
config.vm.provision "mongo.start", type: "shell", inline: $dockerStart_mongo
config.vm.provision "mongo.restart", type: "shell", inline: $dockerRestart_mongo
config.vm.provision "mongo.rm", type: "shell", inline: $dockerRm_mongo
e
inline
脚本看起来是这样的:
$dockerRun_mongo = <<MONGO
echo '>>> docker run --name mongo-container -p 27017:27017 -d mongo'
docker run --name mongo-container -p 27017:27017 -d mongo
MONGO
$dockerCp_MongoInit = <<MONGO
echo '>>> docker exec mongo-container mkdir /home/vagrant'
docker exec mongo-container mkdir -p /home/vagrant
echo '>>> docker cp ./provision/mongo/initialize.js mongo-container:/home/vagrant/mongo.initialize.js'
docker cp ./provision/mongo/initialize.js mongo-container:/home/vagrant/mongo.initialize.js
MONGO
$dockerExec_mongoDbInit = <<MONGO
echo '>>> docker exec mongo-container mongo mongo db-name /home/vagrant/mongo.initialize.js'
docker exec mongo-container mongo db-name /home/vagrant/mongo.initialize.js
MONGO
$dockerStop_mongo = <<MONGO
echo '>>> docker stop mongo-container'
docker stop mongo-container
MONGO
然后,我使用bmuschko的流浪插件将所有这些连接到gradle
:'com.bmuschko:gradle-vagrant-plugin:2.0'
。因此,我的开发环境可以通过像initializeMongoAndRun
这样的分级任务实现自动化,这些任务会在这些不同的Provisioner上发出vagrant provision --provision-with
命令来完成工作。
这意味着所有从事该项目的开发人员都需要同意在vm中托管docker,甚至在Linux系统上也是如此。为了在机器之间获得一致的docker和容器体验,这似乎是一个可以接受的折衷方案。
我会密切关注Vagrant docker
提供商。也许它在这些类型的用途中会变得更加实用,或者我会弄清楚我缺少了什么来让它发挥作用。