使用 Docker Configs 存储配置数据

关于配置

Docker swarm 服务配置允许您在服务映像或正在运行的容器之外存储非敏感信息,例如配置文件。这使您可以使映像尽可能通用,而无需将配置文件绑定安装到容器中或使用环境变量。

配置的操作方式与 Secret类似,只不过它们在静态时不加密,并且直接挂载到容器的文件系统中,而不使用 RAM 磁盘。可以随时在服务中添加或删除配置,并且服务可以共享配置。您甚至可以将配置与环境变量或标签结合使用,以获得最大的灵活性。配置值可以是通用字符串或二进制内容(最大 500 kb)。

笔记

Docker 配置仅适用于集群服务,不适用于独立容器。要使用此功能,请考虑调整您的容器以作为规模为 1 的服务运行。

Linux 和 Windows 服务均支持配置。

Windows 支持

Docker 支持 Windows 容器上的配置,但实现上存在差异,这些差异将在下面的示例中指出。请记住以下显着差异:

  • 具有自定义目标的配置文件不会直接绑定安装到 Windows 容器中,因为 Windows 不支持非目录文件绑定安装。相反,容器的配置全部安装在 C:\ProgramData\Docker\internal\configs容器内(应用程序不应依赖的实现细节)。符号链接用于从那里指向容器内配置的所需目标。默认目标是C:\ProgramData\Docker\configs.

  • 创建使用 Windows 容器的服务时,配置不支持指定 UID、GID 和模式的选项。当前只有管理员和具有system容器内访问权限的用户才能访问配置。

  • --credential-spec在 Windows 上,使用该 格式创建或更新服务config://<config-name>。这会在容器启动之前将 gMSA 凭据文件直接传递到节点。没有 gMSA 凭据写入工作节点上的磁盘。有关更多信息,请参阅 将服务部署到 swarm

Docker 如何管理配置

当您向 swarm 添加配置时,Docker 会通过双向 TLS 连接将该配置发送到 swarm 管理器。配置存储在 Raft 日志中,并且是加密的。整个 Raft 日志在其他管理器之间复制,确保配置与集群管理数据的其余部分具有相同的高可用性保证。

当您授予新创建或正在运行的服务对配置的访问权限时,该配置将作为文件安装在容器中。容器内挂载点的位置默认为/<config-name>Linux 容器中。在 Windows 容器中,配置全部安装到所需位置C:\ProgramData\Docker\configs,并创建符号链接到所需位置,默认为 C:\<config-name>.

您可以使用数字 ID 或用户或组的名称来设置配置的所有权 (uid和)。gid您还可以指定文件权限 ( mode)。对于 Windows 容器,这些设置将被忽略。

  • root如果未设置,则配置由运行容器命令的用户(通常)和该用户的默认组(也通常)拥有root
  • 如果未设置,则配置具有全局可读权限( mode 0444),除非 umask在容器内设置了 a ,在这种情况下,模式会受到该umask值的影响。

您可以随时更新服务以授予其对其他配置的访问权限或撤销其对给定配置的访问权限。

仅当节点是 swarm 管理器或正在运行已被授予配置访问权限的服务任务时,该节点才有权访问配置。当容器任务停止运行时,共享给它的配置将从该容器的内存文件系统中卸载,并从节点的内存中刷新。

如果节点在运行有权访问配置的任务容器时失go与 swarm 的连接,则任务容器仍然可以访问其配置,但在节点重新连接到 swarm 之前无法接收更新。

您可以随时添加或检查单个配置,或列出所有配置。您无法删除正在运行的服务正在使用的配置。请参阅 轮换配置,了解在不中断正在运行的服务的情况下删除配置的方法。

要更轻松地更新或回滚配置,请考虑在配置名称中添加版本号或日期。通过控制给定容器内配置的安装点,这变得更容易。

要更新堆栈,请更改您的 Compose 文件,然后重新运行docker stack deploy -c <new-compose-file> <stack-name>.如果您在该文件中使用新配​​置,您的服务将开始使用它们。请记住,配置是不可变的,因此您无法更改现有服务的文件。相反,您创建一个新配置来使用不同的文件

您可以运行docker stack rm来停止应用程序并删除堆栈。这将删除docker stack deploy使用相同堆栈名称创建的任何配置。这将删除所有配置,包括服务未引用的配置以及docker service update --config-rm.

阅读有关 docker 配置命令的更多信息

使用这些链接来阅读有关特定命令的信息,或继续阅读 有关将配置与服务一起使用的示例

例子

本节包括说明如何使用 Docker 配置的分级示例。

笔记

为了简单起见,这些示例使用单引擎群和未扩展的服务。这些示例使用 Linux 容器,但 Windows 容器也支持配置。

在撰写文件中定义和使用配置

docker stack命令支持在 Compose 文件中定义配置。但是,configs不支持该密钥docker compose。有关详细信息,请参阅 Compose 文件参考

简单示例:配置入门

这个简单的示例展示了配置如何在几个命令中工作。对于实际示例,请继续 高级示例:将配置与 Nginx 服务结合使用

  1. 向 Docker 添加配置。该docker config create命令读取标准输入,因为最后一个参数(表示从中读取配置的文件)设置为-.

    $ echo "This is a config" | docker config create my-config -
    
  2. 创建一个redis服务并授予其访问配置的权限。默认情况下,容器可以访问 处的配置/my-config,但您可以使用 选项自定义容器上的文件名target

    $ docker service create --name redis --config my-config redis:alpine
    
  3. 使用 验证任务正在运行且没有问题docker service ps。如果一切正常,输出将类似于以下内容:

    $ docker service ps redis
    
    ID            NAME     IMAGE         NODE              DESIRED STATE  CURRENT STATE          ERROR  PORTS
    bkna6bpn8r1a  redis.1  redis:alpine  ip-172-31-46-109  Running        Running 8 seconds ago
    
  4. redis使用 获取服务任务容器的ID docker ps,以便您可以使用docker container exec连接到容器并读取配置数据文件的内容,该文件默认为所有人可读,并且与配置名称同名。下面的第一个命令说明了如何查找容器 ID,第二个和第三个命令使用 shell 补全来自动执行此操作。

    $ docker ps --filter name=redis -q
    
    5cb1c2348a59
    
    $ docker container exec $(docker ps --filter name=redis -q) ls -l /my-config
    
    -r--r--r--    1 root     root            12 Jun  5 20:49 my-config
    
    $ docker container exec $(docker ps --filter name=redis -q) cat /my-config
    
    This is a config
    
  5. 尝试删除配置。删除失败,因为redis服务正在运行并且可以访问配置。

    
    $ docker config ls
    
    ID                          NAME                CREATED             UPDATED
    fzwcfuqjkvo5foqu7ts7ls578   hello               31 minutes ago      31 minutes ago
    
    
    $ docker config rm my-config
    
    Error response from daemon: rpc error: code = 3 desc = config 'my-config' is
    in use by the following service: redis
    
  6. redis通过更新服务,从正在运行的服务中删除对配置的访问。

    $ docker service update --config-rm my-config redis
    
  7. 再次重复步骤 3 和 4,验证服务是否不再有权访问配置。容器 ID 不同,因为该 service update命令重新部署服务。

    $ docker container exec -it $(docker ps --filter name=redis -q) cat /my-config
    
    cat: can't open '/my-config': No such file or directory
  8. 停止并删除该服务,并从 Docker 中删除配置。

    $ docker service rm redis
    
    $ docker config rm my-config
    

简单示例:在 Windows 服务中使用配置

这是一个非常简单的示例,展示了如何将配置与在 Microsoft Windows 10 上运行 Windows 容器的 Docker for Windows 上运行的 Microsoft IIS 服务一起使用。这是一个简单的示例,将网页存储在配置中。

此示例假设您已安装 PowerShell。

  1. 将以下内容保存到新文件中index.html

    <html lang="en">
      <head><title>Hello Docker</title></head>
      <body>
        <p>Hello Docker! You have deployed a HTML page.</p>
      </body>
    </html>
  2. 如果您尚未这样做,请初始化或加入集群。

    docker swarm init
  3. 将文件保存index.html为名为 的 swarm 配置homepage

    docker config create homepage index.html
  4. 创建 IIS 服务并授予其对homepage配置的访问权限。

    docker service create
        --name my-iis
        --publish published=8000,target=8000
        --config src=homepage,target="\inetpub\wwwroot\index.html"
        microsoft/iis:nanoserver
  5. 访问 IIS 服务http://localhost:8000/。它应该从第一步开始提供 HTML 内容。

  6. 删除服务和配置。

    docker service rm my-iis
    
    docker config rm homepage

示例:使用模板化配置

要创建使用模板引擎生成内容的配置,请使用参数--template-driver并指定引擎名称作为其参数。创建容器时将呈现模板。

  1. 将以下内容保存到新文件中index.html.tmpl

    <html lang="en">
      <head><title>Hello Docker</title></head>
      <body>
        <p>Hello {{ env "HELLO" }}! I'm service {{ .Service.Name }}.</p>
      </body>
    </html>
  2. 将文件保存index.html.tmpl为名为 的 swarm 配置homepage。提供参数--template-driver并指定golang为模板引擎。

    $ docker config create --template-driver golang homepage index.html.tmpl
    
  3. 创建一个运行 Nginx 并有权访问环境变量 HELLO 和配置的服务。

    $ docker service create \
         --name hello-template \
         --env HELLO="Docker" \
         --config source=homepage,target=/usr/share/nginx/html/index.html \
         --publish published=3000,target=80 \
         nginx:alpine
    
  4. 验证服务是否可运行:您可以访问 Nginx 服务器,并且正在提供正确的输出。

    $ curl http://0.0.0.0:3000
    
    <html lang="en">
      <head><title>Hello Docker</title></head>
      <body>
        <p>Hello Docker! I'm service hello-template.</p>
      </body>
    </html>
    

高级示例:将配置与 Nginx 服务结合使用

这个例子分为两部分。 第一部分是关于生成站点证书的,根本不直接涉及 Docker 配置,但它设置了 第二部分,您可以在其中存储和使用站点证书作为一系列机密,并将 Nginx 配置作为配置。该示例展示了如何在配置上设置选项,例如容器内的目标位置和文件权限 ( mode)。

生成站点证书

为您的站点生成根 CA 和 TLS 证书和密钥。对于生产站点,您可能希望使用诸如Let’s Encrypt生成 TLS 证书和密钥之类的服务,但此示例使用命令行工具。此步骤有点复杂,但只是一个设置步骤,以便您可以将某些内容存储为 Docker 机密。如果您想跳过这些子步骤,可以 使用 Let's Encrypt生成站点密钥和证书,将文件命名为site.keysite.crt,然后跳到 配置 Nginx 容器

  1. 生成根密钥。

    $ openssl genrsa -out "root-ca.key" 4096
    
  2. 使用根密钥生成 CSR。

    $ openssl req \
              -new -key "root-ca.key" \
              -out "root-ca.csr" -sha256 \
              -subj '/C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA'
    
  3. 配置根 CA。编辑一个名为 的新文件root-ca.cnf并将以下内容粘贴到其中。这限制根 CA 只能签署叶证书而不签署中间 CA。

    [root_ca]
    basicConstraints = critical,CA:TRUE,pathlen:1
    keyUsage = critical, nonRepudiation, cRLSign, keyCertSign
    subjectKeyIdentifier=hash
  4. 签署证书。

    $ openssl x509 -req -days 3650 -in "root-ca.csr" \
                   -signkey "root-ca.key" -sha256 -out "root-ca.crt" \
                   -extfile "root-ca.cnf" -extensions \
                   root_ca
    
  5. 生成站点密钥。

    $ openssl genrsa -out "site.key" 4096
    
  6. 生成站点证书并使用站点密钥对其进行签名。

    $ openssl req -new -key "site.key" -out "site.csr" -sha256 \
              -subj '/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost'
    
  7. 配置站点证书。编辑一个名为 的新文件site.cnf并将以下内容粘贴到其中。这会限制站点证书,使其只能用于对服务器进行身份验证,而不能用于签署证书。

    [server]
    authorityKeyIdentifier=keyid,issuer
    basicConstraints = critical,CA:FALSE
    extendedKeyUsage=serverAuth
    keyUsage = critical, digitalSignature, keyEncipherment
    subjectAltName = DNS:localhost, IP:127.0.0.1
    subjectKeyIdentifier=hash
  8. 签署站点证书。

    $ openssl x509 -req -days 750 -in "site.csr" -sha256 \
        -CA "root-ca.crt" -CAkey "root-ca.key" -CAcreateserial \
        -out "site.crt" -extfile "site.cnf" -extensions server
    
  9. Nginx 服务不需要site.csr和文件,但如果您想生成新的站点证书,则需要它们。site.cnf保护root-ca.key文件。

配置 Nginx 容器

  1. 生成一个非常基本的 Nginx 配置,通过 HTTPS 提供静态文件。 TLS 证书和密钥存储为 Docker 机密,以便可以轻松轮换。

    在当前目录中,创建一个名为的新文件,site.conf其中包含以下内容:

    server {
        listen                443 ssl;
        server_name           localhost;
        ssl_certificate       /run/secrets/site.crt;
        ssl_certificate_key   /run/secrets/site.key;
    
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    }
  2. 创建两个秘密,分别代表密钥和证书。您可以将任何小于 500 KB 的文件存储为机密。这允许您将密钥和证书与使用它们的服务解耦。在这些示例中,秘密名称和文件名相同。

    $ docker secret create site.key site.key
    
    $ docker secret create site.crt site.crt
    
  3. 将文件保存site.conf在 Docker 配置中。第一个参数是配置的名称,第二个参数是从中读取配置的文件。

    $ docker config create site.conf site.conf
    

    列出配置:

    $ docker config ls
    
    ID                          NAME                CREATED             UPDATED
    4ory233120ccg7biwvy11gl5z   site.conf           4 seconds ago       4 seconds ago
    
  4. 创建一个运行 Nginx 并有权访问这两个密钥和配置的服务。将模式设置为0440,以便文件只能由其所有者和该所有者所在的组读取,而不是全世界都可以读取。

    $ docker service create \
         --name nginx \
         --secret site.key \
         --secret site.crt \
         --config source=site.conf,target=/etc/nginx/conf.d/site.conf,mode=0440 \
         --publish published=3000,target=443 \
         nginx:latest \
         sh -c "exec nginx -g 'daemon off;'"
    

    在正在运行的容器中,现在存在以下三个文件:

    • /run/secrets/site.key
    • /run/secrets/site.crt
    • /etc/nginx/conf.d/site.conf
  5. 验证 Nginx 服务是否正在运行。

    $ docker service ls
    
    ID            NAME   MODE        REPLICAS  IMAGE
    zeskcec62q24  nginx  replicated  1/1       nginx:latest
    
    $ docker service ps nginx
    
    NAME                  IMAGE         NODE  DESIRED STATE  CURRENT STATE          ERROR  PORTS
    nginx.1.9ls3yo9ugcls  nginx:latest  moby  Running        Running 3 minutes ago
    
  6. 验证服务是否可运行:您可以访问 Nginx 服务器,并且正在使用正确的 TLS 证书。

    $ curl --cacert root-ca.crt https://0.0.0.0:3000
    
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
        body {
            width: 35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
        }
    </style>
    </head>
    <body>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>
    
    <p>For online documentation and support, refer to
    <a href="https://nginx.org">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="https://www.nginx.com">www.nginx.com</a>.</p>
    
    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>
    
    $ openssl s_client -connect 0.0.0.0:3000 -CAfile root-ca.crt
    
    CONNECTED(00000003)
    depth=1 /C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA
    verify return:1
    depth=0 /C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost
    verify return:1
    ---
    Certificate chain
     0 s:/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost
       i:/C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA
    ---
    Server certificate
    -----BEGIN CERTIFICATE-----
    -----END CERTIFICATE-----
    subject=/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost
    issuer=/C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA
    ---
    No client certificate CA names sent
    ---
    SSL handshake has read 1663 bytes and written 712 bytes
    ---
    New, TLSv1/SSLv3, Cipher is AES256-SHA
    Server public key is 4096 bit
    Secure Renegotiation IS supported
    Compression: NONE
    Expansion: NONE
    SSL-Session:
        Protocol  : TLSv1
        Cipher    : AES256-SHA
        Session-ID: A1A8BF35549C5715648A12FD7B7E3D861539316B03440187D9DA6C2E48822853
        Session-ID-ctx:
        Master-Key: F39D1B12274BA16D3A906F390A61438221E381952E9E1E05D3DD784F0135FB81353DA38C6D5C021CB926E844DFC49FC4
        Key-Arg   : None
        Start Time: 1481685096
        Timeout   : 300 (sec)
        Verify return code: 0 (ok)
    
  7. 除非您要继续执行下一个示例,否则请在运行此示例后通过删除服务nginx以及存储的机密和配置进行清理。

    $ docker service rm nginx
    
    $ docker secret rm site.crt site.key
    
    $ docker config rm site.conf
    

您现在已经配置了一个 Nginx 服务,其配置与其映像解耦。您可以使用完全相同的映像但单独的配置来运行多个站点,而根本不需要构建自定义映像。

示例:旋转配置

要轮换配置,您首先要使用与当前使用的名称不同的名称保存新配置。然后,您重新部署服务,删除旧配置并在容器内的同一安装点添加新配置。此示例通过轮换配置文件建立在前一个示例的基础上site.conf

  1. 在本地编辑site.conf文件。添加index.php到该index行,然后保存文件。

    server {
        listen                443 ssl;
        server_name           localhost;
        ssl_certificate       /run/secrets/site.crt;
        ssl_certificate_key   /run/secrets/site.key;
    
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm index.php;
        }
    }
  2. site.conf使用名为 的新文件创建新的 Docker 配置site-v2.conf

    $ docker config create site-v2.conf site.conf
  3. 更新nginx服务以使用新配置而不是旧配置。

    $ docker service update \
      --config-rm site.conf \
      --config-add source=site-v2.conf,target=/etc/nginx/conf.d/site.conf,mode=0440 \
      nginx
    
  4. 使用验证nginx服务是否已完全重新部署 docker service ps nginx。当它出现时,您可以删除旧的site.conf 配置。

    $ docker config rm site.conf
    
  5. 要进行清理,您可以删除nginx服务以及机密和配置。

    $ docker service rm nginx
    
    $ docker secret rm site.crt site.key
    
    $ docker config rm site-v2.conf
    

您现在已经更新了nginx服务的配置,无需重建其映像。