使用Docker config 存储数据
关于配置
Docker swarm服务配置允许我们在服务镜像或运行容器之外存储非敏感信息,例如配置文件。这允许您保持镜像尽可能通用,而无需将配置文件绑定到容器或使用环境变量。
配置的操作方式与密钥类似,只是它们在静态时没有加密,并且在不使用RAM磁盘的情况下直接挂载到容器的文件系统中。配置可以随时从服务中添加或删除,服务可以共享配置。甚至可以将配置与环境变量或标签结合使用,以获得最大的灵活性。配置值可以是通用字符串或二进制内容(大小高达500kb)。
注意:Docker配置仅适用于swarm服务,不适用于独立容器。要使用此功能,请考虑调整容器以作为规模为1的服务运行。
Linux和Windows服务都支持配置。
Docker如何管理配置
当我们将配置添加到集群中时,Docker会通过相互TLS连接将配置发送到群管理器。配置存储在Raft日志中,该日志是加密的。整个Raft日志在其他管理器中复制,确保配置与其他群管理数据相同的高可用性保证。
当我们授予新创建或正在运行的服务对配置的访问权限时,该配置将作为文件挂载到容器中。在Linux容器中,容器中挂载点的位置默认为/<config-name>
。在Windows容器中,配置都挂载到C:\ProgramData\Docker\configs
中,并创建符号链接到所需的位置,默认为C:\<config-name>
。
可以使用数字ID或用户或组的名称为配置设置所有权(uid
和gid
)。我们还可以指定文件权限(mode
)。对于Windows容器,这些设置被忽略。
- 如果没有设置,则配置由运行容器命令(通常是
root
)的用户和该用户的默认组(也经常是root
)拥有。 - 如果没有设置,则配置具有世界可读权限(模式
0444
),除非在容器内设置了umask
,在这种情况下,该模式会受到该umask
值的影响。
我们可以随时更新服务,授予其对其他配置的访问权限或撤销对给定配置的访问权限。
只有当节点是集群的管理节点或正在运行已授予配置访问权限的服务任务时,节点才能访问配置。当容器任务停止运行时,与之共享的配置将从该容器的内存文件系统中卸载,并从节点的内存中刷新。
如果节点在运行可以访问配置的任务容器时失去与群的连接,则任务容器仍然可以访问其配置,但在节点重新连接到群之前无法接收更新。
我们可以随时添加或检查单个配置,或列出所有配置。但是无法删除正在运行的服务正在使用的配置。
要更轻松地更新或回滚配置,请考虑在配置名称中添加版本号或日期。由于能够在给定容器中控制配置的挂载点,这变得更加容易。
要更新堆栈,请更改您的Compose文件,然后重新运行docker stack deploy -c <new-compose-file> <stack-name>
。如果在该文件中使用新的配置,集群服务将开始使用它们。
我们可以运行docker stack rm
来停止应用程序并删除堆栈。这将删除由具有相同堆栈名称的docker stack deploy
创建的任何配置。这将删除所有配置,包括服务未引用的配置和docker service update --config-rm
后剩余的配置。
docker config
命令的信息
例子
我们跟着以下的示例来了解配置相关指令,这些示例说明了Docker配置是如何使用的。
在编写文件中定义和使用配置
docker stack
命令支持在Compose文件中定义配置。然而,docker compose
不支持configs
配置。
简单示例:开始配置m
这个简单的示例仅在几个命令中就显示了配置的工作原理。对于我们实际部署的示例,请继续高级示例:将配置与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
-
使用
docker ps
获取redis
服务任务容器的ID,以便您可以使用docker container exec
连接到容器并读取配置文件数据文件的内容,该文件默认为可被所有人读取,并且与配置文件名称相同。下面的第一个命令说明了如何查找容器ID,第二个和第三个命令使用shell完成来自动执行此操作。docker ps --filter name=redis -q docker container exec $(docker ps --filter name=redis -q) ls -l /my-config docker container exec $(docker ps --filter name=redis -q) cat /my-config
-
尝试删除配置。删除失败,因为
redis
服务正在运行并可以访问配置。docker config ls docker config rm my-config
-
通过更新服务,从正在运行的
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
示例:使用模板配置
要创建使用模板引擎生成内容的配置,请使用--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
的群配置。提供参数--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
-
验证服务是否正常:执行
curl http://0.0.0.0:3000
可以访问 nginx 的页面。<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 server
-
Nginx服务不需要
site.csr
和site.cnf
文件,但如果您想生成新的站点证书,则需要它们。保护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
-
将
site.conf
文件保存在Docker配置中。第一个参数是配置的名称,第二个参数是读取它的文件。docker config create site.conf site.conf
列出配置:
docker config ls
-
创建一个运行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 docker service ps nginx
-
验证服务是否正常:您可以访问Nginx服务器,并且正在使用正确的TLS证书。
curl --cacert root-ca.crt https://0.0.0.0:3000 Welcome to nginx!</title> Welcome to nginx!</h1> If you see this page, the nginx web server is successfully installed and For online documentation and support, refer to nginx.org</a>.<br/> www.nginx.com</a>.</p> <em>Thank you for using nginx.</em></p>
openssl s_client -connect 0.0.0.0:3000 -CAfile root-ca.crt
-
除非您要继续下一个示例,否则在运行此示例后,通过删除thenginx服务以及存储的秘密和配置进行清理。
docker service rm nginx docker secret rm site.crt site.key docker config rm site.conf
您现在已经配置了Nginx服务,其配置与其映像解耦。您可以运行多个具有完全相同映像但配置不同的站点,而根本不需要构建自定义映像。
示例:更新配置
要更新配置,您首先要保存一个与当前使用的名称不同的新配置。然后,您重新部署服务,删除旧配置,并在容器内的同一挂载点添加新配置。此示例通过旋转site.conf
配置文件构建在前一个示例之上。
-
在本地编辑
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; } }
-
使用新的
site.conf
创建一个新的Docker配置,称为site-v2.conf
。$ 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
服务的配置,而无需重建其映像。