Docker 1.13引入了一系列功能,使我们能够集中管理机密并将其仅传递给需要它们的服务。 它们提供了急需的机制来提供应向除指定服务之外的任何人隐藏的信息。

一个秘密(至少从Docker的角度来看)是一个数据博客。 典型的用例是证书,SSH私钥,密码等等。 机密应保持机密,这意味着它们不应未经加密存储或通过网络传输。

综上所述,让我们看看它们的作用,并通过实际示例继续我们的讨论。

创造秘密

由于单个节点足以证明Docker机密,因此我们将基于Docker Machines创建一个单节点Swarm集群。

Windows用户注意事项

建议从Git Bash (通过Docker Toolbox以及Git安装)运行所有示例。 这样,您在本文中将看到的命令将与应在OS X或任何Linux发行版上执行的命令相同。

docker-machine create \
    -d virtualbox \
    swarm

eval $(docker-machine env swarm)

docker swarm init \
  --advertise-addr $(docker-machine ip swarm)

我们创建了一个名为swarm的Docker Machine节点,并使用它来初始化集群。

现在我们可以创建一个秘密。

Windows用户注意事项

为了使下一条命令中使用的挂载(秘密也是挂载)起作用,您必须停止Git Bash更改文件系统路径。 设置此环境变量。

export MSYS_NO_PATHCONV=1

创建机密的命令的格式如下(请不要运行它)。

docker secret create [OPTIONS] SECRET file|-

secret create命令需要包含机密的文件。 但是,创建具有未加密机密的文件首先达不到机密的目的。 每个人都可以读取该文件。 我们可以在将文件推送到Docker之后删除该文件,但这只会创建不必要的步骤。 相反,我们将使用-这将使我们能够传递标准输出。

echo "I like candy" \
    | docker secret create my_secret -

我们刚刚执行的命令创建了一个名为my_secret的秘密。 该信息已使用TLS连接发送到远程Docker Engine。 如果我们有一个由多个管理人员组成的更大的集群,那么秘密将在所有人之间复制。

我们可以检查新创建的秘密。

docker secret inspect my_secret

输出如下。

[
    {
        "ID": "9iqwc8zb7xum7krgm183t4mym",
        "Version": {
            "Index": 11
        },
        "CreatedAt": "2017-02-20T23:00:48.983267019Z",
        "UpdatedAt": "2017-02-20T23:00:48.983267019Z",
        "Spec": {
            "Name": "my_secret"
        }
    }
]

秘密的价值是隐藏的。 即使恶意人员获得了对Docker Engine的访问权限,该机密仍然不可用。 说实在的,在这种情况下,我们的担心会比保护Docker机密大得多,但我将把讨论留给其他时间。

现在我们已经加密了机密并将其存储在Swarm管理器中,我们应该探索在我们的服务中利用它的方法。

消费秘密

新参数--secret已添加到--secret docker service create命令中。 如果附加了机密,则可以在形成服务的所有容器内的/run/secrets目录中将其作为文件使用。

让我们来看看它的作用。

docker service create --name test \
    --secret my_secret \
    --restart-condition none \
    alpine cat /run/secrets/my_secret

我们创建了一个名为test的服务,并附加了一个名为my_secret的秘密。 该服务基于alpine ,将输出机密内容。 由于这是一个会快速终止的命令,因此我们将--restart-condition设置为none 。 否则,服务将在创建之后终止,而Swarm会重新安排它的时间,只是看到它再次终止,依此类推。 我们将进入一个永无止境的循环。

让我们看一下日志。

docker logs $(docker container ps -qa)

输出如下。

I like candy

该密码可作为容器内的/run/secrets/my_secret文件使用。

在开始讨论更真实的示例之前,让我们删除服务和我们创建的秘密。

docker service rm test

docker secret rm my_secret

使用秘密的真实示例

Docker Flow Proxy项目公开了仅应保留供内部使用的统计信息。 因此,需要使用用户名和密码进行保护。 在Docker v1.13之前,允许用户通过环境变量指定用户名和密码来处理这种情况。 Docker Flow Proxy也不例外,并且确实具有环境变量 STATS_USERSTATS_PASS

使用自定义用户名和密码创建服务的命令如下。

docker network create --driver overlay proxy

docker service create --name proxy \
    -p 80:80 \
    -p 443:443 \
    -p 8080:8080 \
    -e STATS_USER=my-user \
    -e STATS_PASS=my-pass \
    --network proxy \
    -e MODE=swarm \
    vfarcic/docker-flow-proxy

尽管这样做可以保护统计信息页面免受普通用户的侵害,但仍然可以让能够检查该服务的任何人看到它。 一个简单的例子如下。

docker service inspect proxy --pretty

输出的相关部分如下。

...
ContainerSpec:
 Image:     vfarcic/docker-flow-proxy:latest@sha256:b1014afa9706413818903671086e484d98db669576b83727801637d1a3323910
 Env:       STATS_USER=my-user STATS_PASS=my-pass MODE=swarm
...

不泄露机密信息的相同结果可以通过以下命令来实现。

echo "secret-user" \
    | docker secret create dfp_stats_user -

echo "secret-pass" \
    | docker secret create dfp_stats_pass -

docker service update \
    --secret-add dfp_stats_user \
    --secret-add dfp_stats_pass \
    proxy

我们创建了两个秘密( dfp_stats_userdfp_stats_pass )并更新了我们的服务。 从现在开始,这些秘密将在服务容器中以文件/run/secrets/dfp_stats_user/run/secrets/dfp_stats_pass 。 如果密钥的名称与环境变量的名称相同,且使用小写字母且具有dpf_前缀,则将使用该dpf_

如果再检查一次容器,您会发现没有任何秘密信息。

我们可以在这里停下来。 毕竟,关于Docker机密的说法不多。 但是,我们已经习惯了Docker堆栈,如果机密信息可以在新的YAML Compose格式中工作,那就太好了。

在继续之前,让我们删除proxy服务。

docker service rm proxy

在Docker Compose中使用机密

为了实现在所有受支持的版本中具有相同功能的使命,Docker引入了Compose YAML格式3.1版的机密。

我们将继续使用Docker Flow Proxy来演示秘密在Compose文件中如何工作。

curl -o dfp.yml \
    https://raw.githubusercontent.com/vfarcic/
docker-flow-stacks/master/proxy/docker-flow-proxy-secrets.yml

我们从vfarcic / docker-flow-stacks存储库下载了docker-flow-proxy- secrets.yml堆栈

堆栈定义的相关部分如下。

version: "3.1"

...

services:

  proxy:
    image: vfarcic/docker-flow-proxy:${TAG:-latest}
    ports:
      - 80:80
      - 443:443
    networks:
      - proxy
    environment:
      - LISTENER_ADDRESS=swarm-listener
      - MODE=swarm
    secrets:
      - dfp_stats_user
      - dfp_stats_pass
    deploy:
      replicas: 3

...

secrets:
  dfp_stats_user:
    external: true
  dfp_stats_pass:
    external: true

该格式的版本是3.1。 proxy服务附有两个秘密。 最后,还有一个单独的secrets部分,将机密定义为外部实体。 另一种方法是在内部指定机密。 一个例子如下。

secrets:
    dfp_stats_user:
        external: true
    dfp_stats_pass:
        external: true
secrets:
  dfp_stats_user:
    file: ./dfp_stats_user.txt
  dfp_stats_pass:
    file: ./dfp_stats_pass.txt

我更喜欢第一个从外部指定机密的选项,因为它不会留下任何痕迹。 在其他一些情况下,机密可能会用于非机密信息(我们将在后面讨论),使用指定为文件的内部机密可能是一个更好的选择。

让我们运行堆栈并检查它是否有效。

docker stack deploy -c dfp.yml proxy

如果没有数据,统计信息本身就没有用,因此我们将部署另一个将在代理中重新配置的服务,并开始生成一些统计信息。

curl -o go-demo.yml \
    https://raw.githubusercontent.com/vfarcic/
go-demo/master/docker-compose-stack.yml

docker stack deploy -c go-demo.yml go-demo

请稍等片刻,直到go-demo堆栈中的服务运行为止。 您可以通过执行docker stack ps go-demo来检查其状态。 您可能会看到go-demo_main副本处于失败状态。 不要恐慌。 它们只会继续失败,直到go-demo_db开始运行。

现在,我们终于可以确认代理已配置为使用机密进行身份验证。

curl -u secret-user:secret-pass \
    "http://$(docker-machine ip swarm)/admin?stats;csv;norefresh"

有用! 仅需执行一个额外的步骤( docker service create ),我们就使我们的系统更加安全。

秘密使用的常用方法

在引入机密之前,将信息传递到容器的一种常见方法是通过环境变量。 尽管这将继续成为非机密信息的首选方式,但部分设置也应包含秘密。 两者应合并。 问题是选择哪种方法以及何时选择。

Docker机密的明显用例就是机密。 很明显,不是吗。 如果有一条信息对于除特定容器之外的任何人均不可见,则应通过Docker机密提供。 常用的模式是允许将相同的信息指定为环境变量和机密。 如果两者都设置,则机密应该优先。 您已经通过Docker Flow Proxy看到了这种模式。 可以通过环境变量指定的每条信息也可以指定为秘密。

在某些情况下,您可能无法修改服务代码并使之适应秘密。 也许这不是能力问题,而是缺乏修改代码的欲望。 如果您遇到后一种情况,那么我现在将限制自己解释为什么要连续重构代码,并想象您有很好的理由。 无论哪种情况,解决方案通常是创建一个包装器脚本,该脚本将机密信息转换为您的服务所需的内容,然后调用该服务。 将脚本作为CMD指令放入Dockerfile中 ,您就完成了。 秘密就是秘密,您不会因重构代码而被解雇。 对于某些人来说,这最后一句话听起来很愚蠢,但是公司考虑重构浪费时间并不少见。

什么是秘密? 没有人可以为您真正回答这个问题,因为每个组织的问题都不同。 其中的一些示例包括用户名和密码,SSH密钥,SSL证书等。 如果您不希望其他人知道它,请将其保密。

我们应该努力实现不变性,并尽力运行完全相同的容器,无论它们在何处运行。 真正的不变性意味着,即使在所有环境中,配置也始终相同。 但是,这并不总是那么容易,有时甚至是不可能实现的。 这种情况可能是Docker机密的一个很好的候选者。 它们不一定必须仅用作指定机密信息的手段。 我们可以使用机密作为提供不同群集信息的一种方式。 在这种情况下,应将一个环境与另一个环境(例如,登台和生产集群)不同的配置项存储为机密。

我敢肯定,还有很多我甚至都没有想到的用例。 毕竟,秘密是一个新功能(从撰写本文之日起几周之久)。

我想得到您的反馈。 您认为机密会有所帮助吗?如果这样做,您的用例将是什么? 请加入slack.devops20toolkit.com/ Slack频道,让我知道。

现在怎么办?

删除Docker Machine VM并开始将机密应用于您自己的Swarm集群。 (目前为止)没有太多要说的了。

docker-machine rm -f swarm

DevOps 2.1工具包:Docker Swarm

如果您喜欢本文,则可能对DevOps 2.1 Toolkit:Docker Swarm一书感兴趣。 与本系列的前一篇文章( DevOps 2.0工具包:使用容器化微服务自动化持续部署管道 )提供了对一些最新DevOps实践和工具的总体了解不同,本书完全致力于Docker Swarm及其过程和工具。我们可能需要构建,测试,部署和监视集群中运行的服务

docker spring boot 健康检查 docker swarm 健康检查_python

您可以从Amazon.com (和其他全球站点)或LeanPub获得副本。 它也可以作为DevOps Toolkit系列软件包使用。