使用 Docker Configs 存储配置数据
关于配置
Docker Swarm 服务配置允许您将非敏感信息(例如配置文件)存储在服务的镜像或运行中的容器之外。 这使您能够保持镜像尽可能通用,而无需将配置文件绑定挂载到容器中或使用环境变量。
配置项的运作方式与 密钥类似,不同之处在于它们不会在静止时加密,并且是直接挂载到容器的文件系统中,而无需使用 RAM 磁盘。配置项可以随时随地从服务中添加或移除,并且多个服务可以共享同一个配置项。为了获得最大的灵活性,您甚至可以将配置项与环境变量或标签结合使用。 配置值可以是通用字符串或二进制内容(最大500 KB)。
注意
Docker 配置仅适用于 Swarm 服务,不适用于独立容器。要使用此功能,请考虑将您的容器调整为以规模 1 运行的服务。
配置支持 Linux 和 Windows 服务。
Windows 支持
Docker 支持 Windows 容器的配置功能,但实现方式存在差异,以下示例中将对此进行说明。请注意以下主要区别:
带有自定义目标的配置文件不会直接绑定挂载到 Windows 容器中,因为 Windows 不支持非目录文件的绑定挂载。 相反,容器的所有配置文件都会挂载在容器内的
C:\ProgramData\Docker\internal\configs(这是一个应用程序不应依赖的实现细节)。 符号链接用于从该位置指向容器内配置的目标路径。默认目标为C:\ProgramData\Docker\configs。在创建使用 Windows 容器的服务时,配置(configs)不支持指定 UID、GID 和 mode 选项。目前,只有管理员以及容器内具有
system权限的用户才能访问配置。在 Windows 上,使用
--credential-spec以config://<config-name>格式创建或更新服务。这会在容器启动前将 gMSA 凭据文件直接传递给节点。工作节点上不会写入任何 gMSA 凭据。有关更多信息,请参阅 将服务部署到 swarm。
Docker 如何管理配置
当你将配置添加到swarm时,Docker通过相互TLS连接将配置发送到swarm管理器。配置存储在加密的Raft日志中。整个Raft日志在其他管理器之间进行复制,为配置提供了与swarm管理数据其余部分相同的高可用性保证。
当你授予新创建或正在运行的服务访问配置的权限时,配置会被挂载为容器内的一个文件。在 Linux 容器中,挂载点的位置默认为 /<config-name>。在 Windows 容器中,配置会被挂载到 C:\ProgramData\Docker\configs,并创建符号链接到所需位置,该位置默认为 C:\<config-name>。
您可以为配置设置所有权(uid 和 gid),可以使用用户或组的数字ID或名称。您还可以指定文件权限(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 文件中定义和使用配置
docker stack 命令支持在 Compose 文件中定义配置。
但是,configs 键不支持用于 docker compose。详情请参阅
Compose 文件参考。
简单示例:开始使用配置
这个简单的示例展示了如何仅用几个命令即可使用配置。要查看实际示例,请继续阅读 高级示例:在 Nginx 服务中使用配置。
将配置添加到 Docker。命令
docker config create从标准输入读取,因为最后一个参数(表示要读取配置的文件)被设置为-。$ echo "This is a config" | docker config create my-config -创建一个
redis服务并授予其访问配置文件的权限。默认情况下, 容器可以在/my-config路径访问该配置文件,但 您可以使用target选项在容器中自定义文件名。$ docker service create --name redis --config my-config redis:alpine使用
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使用
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尝试移除配置。移除失败,因为正在运行的
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通过更新服务,移除正在运行的
redis服务对配置的访问权限。$ docker service update --config-rm my-config redis再次重复步骤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停止并移除该服务,并从 Docker 中移除配置。
$ docker service rm redis $ docker config rm my-config
简单示例:在 Windows 服务中使用配置
这是一个非常简单的示例,展示了如何在运行 Windows 容器的 Microsoft Windows 10 上运行的 Docker for Windows 上使用配置与 Microsoft IIS 服务。这是一个天真的示例,它将网页存储在配置中。
本示例假设您已安装 PowerShell。
将以下内容保存到新文件
index.html。<html lang="en"> <head><title>Hello Docker</title></head> <body> <p>Hello Docker! You have deployed a HTML page.</p> </body> </html>如果尚未操作,请初始化或加入集群。
docker swarm init将
index.html文件保存为名为homepage的 swarm 配置。docker config create homepage index.html创建一个IIS服务并授予其访问
homepage配置的权限。docker service create --name my-iis --publish published=8000,target=8000 --config src=homepage,target="\inetpub\wwwroot\index.html" microsoft/iis:nanoserver在
http://localhost:8000/访问 IIS 服务。它应该提供第一步中的 HTML 内容。移除服务和配置。
docker service rm my-iis docker config rm homepage
示例:使用模板化配置
要创建一个使用模板引擎生成内容的配置,请使用 --template-driver 参数并将引擎名称作为其参数指定。当容器创建时,模板将被渲染。
将以下内容保存到新文件
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>将
index.html.tmpl文件保存为名为homepage的 swarm 配置。提供参数--template-driver,并将golang指定为模板引擎。$ docker config create --template-driver golang homepage index.html.tmpl创建一个运行 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验证服务是否正常运行:您可以访问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.key和site.crt,然后跳转到
配置Nginx容器。
生成根密钥。
$ openssl genrsa -out "root-ca.key" 4096使用根密钥生成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'配置根 CA。编辑一个名为
root-ca.cnf的新文件,并将以下内容粘贴到其中。这将限制根 CA 仅签署叶证书,而不是中间 CA。[root_ca] basicConstraints = critical,CA:TRUE,pathlen:1 keyUsage = critical, nonRepudiation, cRLSign, keyCertSign subjectKeyIdentifier=hash签署证书。
$ 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生成站点密钥。
$ openssl genrsa -out "site.key" 4096生成站点证书并使用站点密钥进行签名。
$ openssl req -new -key "site.key" -out "site.csr" -sha256 \ -subj '/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost'配置站点证书。编辑一个名为
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签署站点证书。
$ 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 serversite.csr和site.cnf文件对 Nginx 服务不是必需的,但如果你想生成新的站点证书,则需要它们。请保护root-ca.key文件。
配置 Nginx 容器
生成一个非常基础的 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; } }创建两个密钥,分别表示密钥和证书。只要文件小于500 KB,您可以将其存储为密钥。这使您能够将密钥和证书与其使用的服务分离。 在这些示例中,密钥名称和文件名称相同。
$ docker secret create site.key site.key $ docker secret create site.crt site.crt在 Docker 配置中保存
site.conf文件。第一个参数是配置的名称,第二个参数是要从中读取的文件。$ docker config create site.conf site.conf列出配置文件:
$ docker config ls ID NAME CREATED UPDATED 4ory233120ccg7biwvy11gl5z site.conf 4 seconds ago 4 seconds ago创建一个运行 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
验证 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验证服务是否正常运行:您可以访问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)除非您打算继续进行下一个示例,否则请在运行此示例后清理,删除
nginx服务以及存储的密钥和配置。$ docker service rm nginx $ docker secret rm site.crt site.key $ docker config rm site.conf
您现在已经配置了一个与镜像解耦的 Nginx 服务。您可以运行多个站点,使用完全相同的镜像但具有独立的配置,而无需构建任何自定义镜像。
示例:轮换配置
要轮换配置,请先使用与当前正在使用的配置不同的名称保存新的配置。然后重新部署服务,在容器内的同一挂载点删除旧配置并添加新配置。此示例在前面的基础上轮换 site.conf 配置文件。
在本地编辑
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; } }使用新的
site.conf创建一个名为site-v2.conf的新 Docker 配置。$ docker config create site-v2.conf site.conf更新
nginx服务以使用新配置而不是旧配置。$ docker service update \ --config-rm site.conf \ --config-add source=site-v2.conf,target=/etc/nginx/conf.d/site.conf,mode=0440 \ nginx验证使用
docker service ps nginx的nginx服务是否已完全重新部署。完成后,您可以移除旧的site.conf配置。$ docker config rm site.conf要进行清理,您可以移除
nginx服务,以及密钥和配置。$ docker service rm nginx $ docker secret rm site.crt site.key $ docker config rm site-v2.conf
您现在已更新了 nginx 服务的配置,无需重建其镜像。