使用 Docker Configs 存储配置数据

关于 configs

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

Configs 的操作方式类似于secrets,不同之处在于它们在静态存储时不会被加密,并且会直接安装到容器的文件系统中,而无需使用 RAM 磁盘。可以随时向服务添加或删除 Configs,并且服务可以共享一个 Config。为了获得最大的灵活性,您甚至可以将 Configs 与环境变量或标签结合使用。Config 值可以是通用字符串或二进制内容(大小最多 500 kb)。

注意

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

Configs 在 Linux 和 Windows 服务上都受支持。

Windows 支持

Docker 包含对 Windows 容器中 configs 的支持,但实现方式存在差异,如下面的示例中所述。请记住以下显着差异

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

  • 创建使用 Windows 容器的服务时,不支持为 configs 指定 UID、GID 和模式的选项。Configs 目前仅可供管理员和具有容器内system访问权限的用户访问。

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

Docker 如何管理 configs

将 config 添加到 Swarm 时,Docker 会通过相互 TLS 连接将 config 发送到 Swarm 管理器。config 存储在 Raft 日志中,该日志已加密。整个 Raft 日志会在其他管理器之间复制,确保 configs 与 Swarm 管理数据的其余部分具有相同的高可用性保证。

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

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

  • 如果未设置,则配置由运行容器命令的用户(通常为root)及其用户的默认组(通常也为root)拥有。
  • 如果未设置,则配置具有世界可读权限(模式0444),除非在容器中设置了umask,在这种情况下,模式将受到该umask值的影响。

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

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

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

您可以随时添加或检查单个配置,或列出所有配置。您不能删除正在运行的服务正在使用的配置。有关无需中断运行服务即可删除配置的方法,请参阅旋转配置

为了更轻松地更新或回滚配置,请考虑向配置名称添加版本号或日期。通过能够控制给定容器内配置的挂载点,这变得更容易。

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

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

阅读更多关于docker config 命令的信息

使用这些链接阅读有关特定命令的信息,或继续访问关于使用带有服务的配置的示例

示例

本节包含逐步示例,说明如何使用 Docker 配置。

注意

这些示例出于简化目的,使用了单引擎 Swarm 和未缩放的服务。这些示例使用 Linux 容器,但 Windows 容器也支持配置。

在 compose 文件中定义和使用 configs

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

简单示例:开始使用 configs

此简单示例展示了配置如何在几个命令中工作。有关实际示例,请继续访问高级示例:使用带有 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. 使用docker ps获取redis服务任务容器的 ID,以便您可以使用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 服务中使用 configs

这是一个非常简单的示例,它展示了如何在运行 Windows 容器的 Microsoft Windows 10 上运行的 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. 如果您尚未这样做,请初始化或加入 Swarm。

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

    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. http://localhost:8000/访问 IIS 服务。它应该提供第一步中的 HTML 内容。

  6. 删除服务和配置。

    docker service rm my-iis
    
    docker config rm homepage

示例:使用模板化 config

要创建内容将使用模板引擎生成的配置,请使用--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文件保存为名为homepage的 Swarm 配置。提供参数--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>
    

高级示例:将 configs 与 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.csrsite.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.ac.cn">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 服务,其配置与其镜像分离。您可以运行多个具有完全相同镜像但配置不同的站点,而无需构建自定义镜像。

示例:轮换 config

要旋转配置,您首先要保存一个新配置,其名称与当前正在使用的配置不同。然后,重新部署服务,删除旧配置并在容器内的相同挂载点添加新配置。此示例通过旋转site.conf配置文件来构建之前的示例。

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

    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. 使用docker service ps nginx验证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服务的配置,而无需重新构建其镜像。