如何使用流浪docker与容器环境变量扩展一起运行



我在带有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_ADDRMONGO_PORT_27017_TCP_PORT)。

我一直在尝试使用vagrant docker-run来实现这一点,但我找不到一种方法来正确解释命令,从而正确扩展这些环境变量。每次尝试都会导致mongo命令抱怨没有提供主机和端口(环境变量扩展为空)。

我最终想做的是:

  1. 启动一个链接到正在运行的mongo容器的容器(这样它就可以获得其env变量)
  2. 将一个javascript文件上传到新容器中,其中包括我想要进行的mongo初始化
  3. 在容器上运行shell命令,如下所示:

mongo "$MONGO_PORT_27017_TCP_ADDR:$MONGO_PORT_27017_TCP_PORT/db-name" initialize.js

  1. 取出容器

有什么建议或其他我可以尝试的方法吗?

典型失败命令示例

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)定义自定义图像并重新设计入口点,以便启动sshmongod,以及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的filescript提供程序需要容器上的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提供商。也许它在这些类型的用途中会变得更加实用,或者我会弄清楚我缺少了什么来让它发挥作用。

最新更新