如何用Docker实现“一二进制”原则

一个二进制原则在这里解释: http : //programmer.97things.oreilly.com/wiki/index.php/One_Binary指出,应该…

“构build一个可以在发布pipe道的所有阶段识别和升级的二进制文件,在环境中保存特定于环境的详细信息,例如,这可能意味着将它们保存在组件容器中,已知文件中或path。”

我看到许多开发人员工程师通过在每个环境中创build一个Docker镜像(即,my-app-qa,my-app-prod等)来违反这一原则。 我知道Docker支持不可变的基础架构,这意味着部署后不会更改映像,因此不会在部署后上传或下载configuration。 在不可改变的基础设施和一个二元原理之间是否存在一个权衡,还是它们可以相互补充? 当涉及到从代码分离configuration什么是在Docker世界的最佳做法? 应采取以下哪一种方法…

1)创build一个基本的二进制镜像,然后configuration一个Dockerfile,通过添加环境特定的configuration来扩充这个镜像。 (即我的应用程序 – >我的应用程序产品)

2)在部署时将一个仅二进制docker映像部署到容器中,并通过环境variables传递configuration等。

3)将Docker文件部署到容器后上传configuration

4)从configurationpipe理服务器中从容器内正在运行的泊坞窗镜像下载configuration。

5)保持主机环境中的configuration,并通过绑定挂载使其可用于正在运行的Docker实例。

有没有更好的方法没有提到上面?

如何使用不可变的基础架构来执行一个二进制原则? 它可以做到还是有一个权衡? 最佳做法是什么?

我现在有大约2年的部署Docker容器的经验,所以我将讨论我所做的和/或知道的工作。

所以,让我先说容器应该是不可变的(我甚至把它标记为只读)。

主要方法:

  • 通过设置静态入口点并通过覆盖容器启动命令来覆盖configuration文件的位置来使用configuration文件 – 这不那么灵活,因为必须提交更改并重新部署才能启用它; 不适合密码,安全令牌等
  • 通过用环境variables覆盖它们的位置来使用configuration文件 – 这又取决于是否提前准备好configuration文件; ; 不适合密码,安全令牌等
  • 使用环境variables – 这可能需要更改部署代码,从而缩短实现configuration更改的时间,因为它不需要经历应用程序构build阶段(在大多数情况下),部署这样的更改可能是挺容易。 下面是一个例子 – 如果将一个集装箱化的应用程序部署到Marathon中,更改一个环境variables可能只是从最后使用的容器映像(甚至可能在同一个主机上)启动一个新的容器,这意味着这可以在几秒钟内完成; 不适合密码,安全令牌等,特别是在Docker中
  • 将configuration存储在像Consul这样的ak / v存储中,让应用程序意识到这一点,甚至可以dynamic重新configuration。 伟大的方法同时启动function – 甚至可能跨多个服务; 如果使用诸如HashiCorp Vault之类的解决scheme来实现敏感信息的安全存储,则甚至可能具有短暂的秘密(一个示例将是用于保险柜的PostgreSQL秘密后端 – https://www.vaultproject.io/docs/secrets/postgresql/ index.html )
  • 有一个应用程序或脚本在启动主应用程序之前创buildconfiguration文件 – 将configuration存储在像Consul这样的k / v存储中,使用诸如consul-template之类的东西来填充应用程序configuration; 更安全一点 – 因为你并没有把所有的东西都作为代码来处理
  • 有一个应用程序或脚本在启动主应用程序之前填充环境variables – 一个例子是envconsul; 不适合敏感信息 – 有权访问Docker API的人(通过TCP或UNIX套接字)将能够读取这些信息
  • 我甚至有一种情况,我们将variables填充到AWS的实例user_data中,并在启动时将它们注入到容器中(使用一个在启动时修改容器的jsonconfiguration的脚本)

主要的事情,我会考虑到:

  • 什么是我暴露的variables,什么时候以及从何处获取它们的值(可能是CD软件或其他) – 例如,您可以将AWS RDS端点和凭证发布到实例的user_data,甚至可能发布EC2标记与一些IAM实例configuration文件魔术
  • 我们需要pipe理多less个variables,以及我们经常改变其中的一些variables – 如果我们有一些variables,我们可能只需要使用环境variables,或者使用环境variables来存储文件中最常见的variables和variables那些我们变化较less的人
  • 我们希望看到它们变化的速度有多快 – 如果是文件,通常需要更多时间才能将其部署到生产环境; 如果我们使用环境variabless,我们通常可以更快地部署这些变化
  • 我们如何保护其中的一些 – 我们在哪里注入它们以及如何 – 例如Ansible Vault,HashiCorp Vault,将它们保存在单独的回购库等中
  • 我们如何部署 – 可以是发送到部署框架端点,Ansible等的JSONconfiguration文件
  • 我们所处的环境是什么?像Consul这样的configuration数据存储(Consul有两种不同types的代理 – 客户端和服务器)是现实的吗?

我倾向于更喜欢将它们存储在中心位置(k / v store,数据库)中的最复杂的情​​况,并且dynamic更改它们,因为我遇到了以下情况:

  • 缓慢的部署stream水线 – 这使得改变configuration文件并部署它的速度非常慢
  • 有太多的环境variables – 这真的可能会失控
  • 不得不一次在整个机队(由数十个服务组成)中打开一个特征旗帜
  • 真正的环境通过更好地处理敏感的configuration数据来努力提高安全性

我可能错过了一些东西,但是我认为这应该足以成为一种触发器,去考虑什么对你的环境是最好的

过去的做法是在执行构build之后将标记化合并到打包过程中。 这些令牌可以在位于顶层的编排层进行pipe理,以pipe理您的平台工具。 所以对于给定的标记,有一个匹配的正则expression式或xpathexpression式。 该令牌链接到一个或多个configuration文件,具体取决于所select的关系。 然后,当这个构build部署到一个容器时,一个平台服务(即configurationpipe理)将戳这些令牌与其环境的正确值。 这些捅价值很可能会从保险库中提取。