使用Docker Configs存储配置数据

预计阅读时间:20分钟

关于配置

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

配置的工作方式与机密类似,不同之处在于配置不会在静止状态下进行加密,并且无需使用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可以在容器内访问配置文件。

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

Docker如何管理配置

将配置添加到群集时,Docker会通过双向TLS连接将配置发送到群集管理器。该配置存储在Raft日志中,该日志已加密。整个Raft日志会在其他管理器之间复制,以确保对配置的高可用性保证与其他集群管理数据一样。

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

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

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

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

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

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

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

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

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

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

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

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

例子

本节包含一些分级示例,这些示例说明了如何使用Docker配置。

注意:为了简单起见,这些示例使用单引擎群集和未缩放的服务。这些示例使用Linux容器,但是Windows容器也支持配置。

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

docker stack命令支持在Compose文件中定义配置。但是,configs不支持该密钥docker 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. 使用获取redis服务任务容器的ID docker ps,以便您可以docker container exec用来连接到容器并读取config数据文件的内容,该文件默认为所有人可读,并且与config的名称相同。下面的第一个命令说明了如何查找容器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服务中使用配置

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

本示例假定您已安装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文件另存为名为的群集配置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文件另存为名为的群集配置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,然后跳至 Configure 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. site.csrsite.cnf文件不需要由Nginx的服务,但你需要他们,如果你想生成一个新的站点证书。保护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服务的配置,而无需重建其映像。

配置配置