【问题标题】:Passing environmental variables when deploying docker to remote host将 docker 部署到远程主机时传递环境变量
【发布时间】:2017-03-29 12:56:38
【问题描述】:

我的 docker 容器和环境变量有问题。

目前我有一个 docker-compose.yml,定义如下:

version: '2.1'
services:
  some-service:
    build:
      context: .
    image: image/replacedvalues
    ports:
      - 8080
    environment:
      - PROFILE=acc
      - ENVA
      - ENVB
      - TZ=Europe/Berlin

  some-service-acc:
    extends:
      service: some-service
    environment:
      - SERVICE_NAME=some-service-acc

现在,当我在服务器 A 上手动部署(直接通过 SSH 命令行)时,它会从服务器 A 获取环境变量并将它们放入我的容器中。所以我有来自容器中主机的ENVAENVB 的值。使用以下命令(在构建图像之后):docker-compose up some-service-acc.

我们目前正在开发更好的基础架构,并希望通过 Jenkins 部署服务。 Jenkins 在服务器 B 上的 docker 容器中启动并运行。

我可以通过 Jenkins 部署服务(Job-DSL,设置 DOCKER_HOST="tcp://serverA:2375"temporary)。因此,它将从服务器 B 上的 Jenkins 容器在服务器 A 上运行所有 docker(撰写)命令。该服务已启动并正在运行,只是它没有 ENVAENVB 的值。

Jenkins 使用 Job-DSL groovy 脚本运行以下命令:

withEnv(["DOCKER_HOST=tcp://serverA:2375"]) {
    sh "docker-compose pull some-service-acc"
    sh "docker-compose -p some-service-acc up -d some-service-acc"
}

我尝试将它们设置在我的 Jenkins 容器和服务器 B 本身上,但都没有成功。只有当我直接在服务器 A 上手动部署时它才能工作。

当我使用 docker inspect 检查正在运行的容器时,我得到env 块的以下输出:

"Env": [
    "PROFILE=acc",
    "affinity:container==JADFG09gtq340iggIN0jg53ij0gokngfs",
    "TZ=Europe/Berlin",
    "SERVICE_NAME=some-service-acc",
    "ENVA",
    "ENVB",
    "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
    "LANG=C.UTF-8",
    "JAVA_VERSION=8",
    "JAVA_UPDATE=121",
    "JAVA_BUILD=13",
    "JAVA_PATH=e9e7ea248e2c4826b92b3f075a80e441",
    "JAVA_HOME=/usr/lib/jvm/default-jvm",
    "JAVA_OPTS="
]

我需要在哪里设置环境变量以便将它们传递给容器?我更喜欢将变量存储在服务器 A 上。但如果这不可能,有人可以解释一下如何做到吗? 不是硬编码组合文件中的值或源中任何其他位置的值的选项,因为它们包含敏感数据。

如果我在错误的地方问这个问题,请将我重定向到我应该去的地方。

谢谢!

【问题讨论】:

    标签: docker jenkins yaml docker-compose


    【解决方案1】:

    您需要在运行 docker-compose 命令行的 shell 中设置环境变量。在 Jenkins 中,最好在您的 groovy 脚本中完成(Jenkins 不使用构建从站中的主机环境):

    withEnv(["DOCKER_HOST=tcp://serverA:2375", "ENVA=hello", "ENVB=world"]) {
        sh "docker-compose pull some-service-acc"
        sh "docker-compose -p some-service-acc up -d some-service-acc"
    }
    

    编辑:来自 cmets,您还想传递秘密。

    为此,有像Mask Password 这样的插件可以让您传递变量,而不会出现在日志或作业配置中。 (我相当肯定一个坚定的入侵者仍然可以获得这些值,因为 Jenkins 自己知道它并以明文形式将它传递给您的脚本。)

    IMO 更好的选择是使用 docker 内部的秘密管理工具。 Hashicorp has their Vault product 实现了一个加密的 K/V 存储,其中使用时间限制令牌访问值,并提供了为每个请求生成新密码并集成到目标系统的能力。完全配置后,我认为这是最高级别的安全性,但您可以配置无数种方式以满足您自己的需求。您需要编写一些东西来提取秘密并将其注入到容器的环境中(这是一个可以添加到入口点的休息协议)。

    Docker 本身的最新选项是需要新的 Swarm 模式的秘密管理。您将您的秘密保存在 swarm 中,并使用 entry in the docker-compose.yml version 3 format 将其作为文件添加到您想要的容器中。如果您已经使用 Swarm 模式并且可以使用 docker stack deploy 而不是 docker-compose 启动容器,那么这是一个相当容易实施的解决方案。

    【讨论】:

    • 硬编码对我来说不是一个选项,因为它包含敏感数据,而且我不需要每次部署时都需要那些环境变量,只需要部署到 ServerA 的服务。但如果我做对了,除了DOCKER-HOST 之外,在docker-compose 命令的那一刻没有其他环境变量?
    • DOCKER_HOST,一个最小的 PATH,以及 Jenkins 定义的各种变量。还有其他秘密选项,我会更新我的答案。
    • 感谢您的广泛回答。我会接受它作为正确答案。有很多东西需要研究。感谢您提供所有信息。
    猜你喜欢
    • 2018-01-08
    • 1970-01-01
    • 2020-10-23
    • 2018-12-02
    • 2018-09-18
    • 1970-01-01
    • 2020-11-07
    • 1970-01-01
    • 2019-06-02
    相关资源
    最近更新 更多