©
本文档使用
php.cn手册 发布
就Docker Swarm服务而言,秘密是一组数据,如密码,SSH私钥,SSL证书或另一部分数据,这些数据不应通过网络传输或在Dockerfile或应用程序中未加密存储源代码。在Docker 1.13及更高版本中,您可以使用Docker 机密来集中管理这些数据,并将其安全地传输给需要访问的那些容器。在运输过程中密码被加密,并在Docker群中休息。给定的秘密只能被那些被授予明确访问权限的服务访问,并且只有在这些服务任务正在运行时才能访问。
您可以使用秘密来管理容器在运行时需要的任何敏感数据,但不想将其存储在映像或源代码管理中,例如:
用户名和密码
TLS证书和密钥
SSH密钥
其他重要数据,如数据库或内部服务器的名称
通用字符串或二进制内容(最大为500 kb)
注意:Docker机密仅适用于群集服务,而不适用于独立容器。要使用此功能,请考虑将您的容器作为1级服务运行。
另一个使用秘密的用例是在容器和一组证书之间提供一个抽象层。考虑一个场景,您可以为应用程序分别开发,测试和生产环境。这些环境中的每一个都可以拥有不同的凭证,并以相同的秘密名称存储在开发,测试和生产群中。您的容器只需要知道秘密的名称,以便在三种环境中都能正常工作。
您还可以使用机密来管理非敏感数据,例如配置文件。但是,Docker 17.06和更高版本支持使用configs来存储非敏感数据。配置直接安装到容器的文件系统中,而不使用RAM磁盘。
Docker 17.06和更高版本包含对Windows容器上的秘密的支持。在实现中存在差异的地方,它们在下面的例子中被调用。牢记以下显着差异:
Microsoft Windows没有用于管理RAM磁盘的内置驱动程序,因此在运行Windows容器中,秘密以明文形式保存到容器的根磁盘。但是,当容器停止时,秘密将被明确删除。另外,Windows不支持将正在运行的容器作为使用图像docker commit
或类似命令的图像。
在Windows上,我们建议在主机上包含Docker根目录的卷上启用BitLocker(https://technet.microsoft.com/en-us/library/cc732774(v = ws.11%29.aspx)以确保运行容器的秘密在休息时被加密。
自定义目标的秘密文件不直接绑定到Windows容器中,因为Windows不支持非目录文件绑定挂载。相反,容器的秘密都安装在C:\ProgramData\Docker\internal\secrets
容器内的(应用程序不应该依赖的实现细节中)。符号链接用于指向容器内的秘密所需的目标。默认目标是C:\ProgramData\Docker\secrets
。
在创建使用Windows容器的服务时,用于指定UID,GID和模式的选项不受秘密支持。当前只能由管理员和system
容器内的访问权限的用户访问秘密。
当您为swarm添加秘密时,Docker会通过相互TLS连接将密钥发送给swarm管理器。秘密存储在加密的Raft日志中。整个Raft日志被复制到其他管理者中,确保与其他群管理数据相同的高可用性保证。
警告:Raft数据在Docker 1.13和更高版本中被加密。如果您的任何Swarm管理人员运行早期版本,并且其中一位经理成为群体经理,则秘密将以未加密方式存储在该节点的Raft日志中。在添加任何秘密之前,将所有管理器节点更新到Docker 1.13或更高版本,以防止将秘密写入纯文本的Raft日志。
当您授予新创建或正在运行的服务对秘密的访问权限时,解密的秘密将被装入容器中的内存中文件系统。 容器中安装点的位置默认为Linux容器中的/ run / secrets / <secret_name>,或Windows容器中的C:\ ProgramData \ Docker \ secrets。 您可以在Docker 17.06和更高版本中指定自定义位置。
您可以更新服务,授权其访问其他机密或随时撤销对指定机密的访问权限。
如果节点是群管理器或者它正在运行已被授权访问秘密的服务任务,那么节点只能访问(加密的)秘密。当容器任务停止运行时,共享给它的解密秘密将从该容器的内存中文件系统卸载,并从节点的内存刷新。
如果节点在运行可访问秘密的任务容器时失去与群集的连接,则任务容器仍可访问其秘密,但在节点重新连接群集之前无法接收更新。
您可以随时添加或检查个人密码,或列出所有密码。您无法删除正在运行的服务正在使用的秘密。请参阅旋转秘密以在不中断正在运行的服务的情况下移除秘密。
为了更容易地更新或回滚秘密,请考虑在秘密名称中添加版本号或日期。通过控制给定容器内秘密的安装点的能力使这变得更容易。
docker secret
命令的信息使用这些链接阅读有关特定命令的内容,或继续关于在服务中使用秘密的示例。
docker secret create
docker secret inspect
docker secret ls
docker secret rm
--secret
标志为 docker service create
--secret-add
和--secret-rm
标志docker service update
本节包含三个演示如何使用Docker机密的毕业示例。这些示例中使用的图像已更新,以便于使用Docker机密。要了解如何以类似的方式修改自己的图像,请参阅将Docker机密支持构建到图像中。
注意:为简单起见,这些示例使用单引擎群和非标度服务。这些示例使用Linux容器,但Windows容器也支持Docker 17.06和更高版本中的秘密。请参阅Windows支持。
这个简单的例子展示了秘密如何在几个命令中工作。对于真实世界的例子,继续到中级例子:使用Nginx服务的秘密。
给Docker添加一个秘密。该docker secret create
命令读取标准输入,因为最后一个参数表示要读取密钥的文件设置为-
。$ echo "This is a secret" | docker secret create my_secret_data -
创建一个redis
服务并授予它访问该秘密的权限。默认情况下,容器可以访问该密码/run/secrets/<secret_name>
,但您可以使用该target
选项自定义容器上的文件名。$ docker service create --name redis --secret my_secret_data 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 agoIf there were an error, and the task were failing and repeatedly restarting, you would see something like this: $ docker service ps redis NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS redis.1.siftice35gla redis:alpine moby Running Running 4 seconds ago \ redis.1.whum5b7gu13e redis:alpine moby Shutdown Failed 20 seconds ago "task: non-zero exit (1)" \ redis.1.2s6yorvd9zow redis:alpine moby Shutdown Failed 56 seconds ago "task: non-zero exit (1)" \ redis.1.ulfzrcyaf6pg redis:alpine moby Shutdown Failed about a minute ago "task: non-zero exit (1)" \ redis.1.wrny5v4xyps6 redis:alpine moby Shutdown Failed 2 minutes ago "task: non-zero exit (1)"
获取redis
使用的服务任务容器的ID docker ps
,以便您可以使用docker exec
连接到容器并读取秘密数据文件的内容,该内容默认为全部可读,并且与秘密的名称相同。下面的第一条命令说明了如何找到容器ID,第二个和第三个命令使用shell完成来自动执行此操作。$ docker ps --filter name=redis -q 5cb1c2348a59 $ docker exec $(docker ps --filter name=redis -q) ls -l /run/secrets total 4 -r--r--r-- 1 root root 17 Dec 13 22:48 my_secret_data $ docker exec $(docker ps --filter name=redis -q) cat /run/secrets/my_secret_data This is a secret
验证如果您提交容器,秘密不可用。$ docker commit $(docker ps --filter name=redis -q) committed_redis $ docker run --rm -it committed_redis cat /run/secrets/my_secret_data cat: can't open '/run/secrets/my_secret_data': No such file or directory
尝试删除秘密。删除失败,因为该redis
服务正在运行并可以访问该秘密。$ docker secret ls ID NAME CREATED UPDATED wwwrxza8sxy025bas86593fqs my_secret_data 4 hours ago 4 hours ago $ docker secret rm my_secret_data Error response from daemon: rpc error: code = 3 desc = secret 'my_secret_data' is in use by the following service: redis
redis
通过更新服务,从正在运行的服务中移除对秘密的访问权限。$ docker service update --secret-rm my_secret_data redis
重复步骤3和4,验证该服务不再有权访问该秘密。容器ID将不同,因为该service update
命令重新部署服务。$ docker exec -it $(docker ps --filter name=redis -q) cat /run/secrets/my_secret_data cat: can't open '/run/secrets/my_secret_data': No such file or directory
停止并删除服务,并从Docker中删除密钥。$ docker service rm redis $ docker secret rm my_secret_data
这是一个非常简单的例子,它展示了如何使用运行在Microsoft Windows Server 2016上的Docker 17.06 EE或Microsoft Windows 10上的Docker for Mac 17.06上运行的Microsoft IIS服务的秘密。这是一个理想的例子,它将网页存储在一个秘密中。
此示例假定您已安装PowerShell。
将以下内容保存到一个新文件中:index.html
<html> <head> <title> Hello Docker </ title> </ head> <body> <p> Hello Docker!您已经部署了一个HTML页面。</ p> </ body> </ html>
如果你还没有这样做,请初始化或加入群。PS> docker swarm init
将该index.html
文件保存为名为swarm的秘密homepage
。PS> docker secret创建主页index.html
创建一个IIS服务并授予它对homepage
秘密的访问权限。PS> docker service create --name my-iis -p 8000:8000 --secret src = homepage,target =“\ inetpub \ wwwroot \ index.html”microsoft / iis:nanoserver 注意:技术上没有理由使用机密对于这个例子。使用Docker 17.06或更高版本,configs更适合。这个例子仅用于说明。
访问IIS服务http://localhost:8000/
。它应该从第一步开始提供HTML内容。
删除服务和秘密。PS> docker service rm my-iis PS> docker secret rm homepage PS> docker image remove secret-test
这个例子分为两部分。第一部分是关于生成站点证书的内容,并不直接涉及Docker机密,但是它建立了第二部分,在那里存储和使用站点证书和Nginx配置作为秘密。
为您的站点生成根CA和TLS证书和密钥。对于生产站点,您可能希望使用服务Let’s Encrypt
来生成TLS证书和密钥,但此示例使用命令行工具。这一步有点复杂,但只是一个设置步骤,以便您可以将某些内容存储为Docker的秘密。如果你想跳过这些子步骤,您可以使用我们的加密生成网站密钥和证书,命名文件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
在site.csr
和site.cnf
文件不需要由Nginx的服务,但你需要他们,如果你想生成一个新的站点证书。保护root-ca.key
文件。
生成一个非常基本的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; } }
创建三个机密,代表密钥,证书和密钥 site.conf
。只要小于500 KB,您就可以将任何文件存储为秘密文件。这使您可以将密钥,证书和配置与将使用它们的服务分离。在每一个这些命令中,最后一个参数代表从主机文件系统读取密钥的文件路径。在这些示例中,秘密名称和文件名是相同的。$ docker secret create site.key site.key $ docker secret create site.crt site.crt $ docker secret create site.conf site.conf $ docker secret ls ID NAME CREATED UPDATED 2hvoi9mnnaof7olr3z5g3g7fp site.key 58 seconds ago 58 seconds ago aya1dh363719pkiuoldpter4b site.crt 24 seconds ago 24 seconds ago zoa5df26f7vpcoz42qf2csth8 site.conf 11 seconds ago 11 seconds ago
创建一个运行Nginx并可以访问这三个秘密的服务。 docker service create命令的最后一部分创建一个从site.conf秘密位置到/etc/nginx.conf.d/的符号链接,其中Nginx会查找额外的配置文件。 这一步发生在Nginx实际启动之前,因此如果您更改Nginx配置,则不需要重新生成映像。
注意:通常您会创建一个Dockerfile,将site.conf复制到适当位置,构建映像并使用自定义映像运行容器。 此示例不需要自定义图像。 它将site.conf放置到位,并且一步到位运行容器。
在Docker 17.05及更早版本中,机密总是位于/run/secrets/
目录中。Docker 17.06及更高版本允许您为容器中的秘密指定自定义位置。下面的两个例子说明了它们的区别。该命令的较早版本要求您创建一个到site.conf
文件的真实位置的符号链接,以便Nginx可以读取它,但是较新的版本不需要这样做。较旧的示例已保存,以便您可以看到差异。
- **Docker 17.06 and higher**: $ docker service create \ --name nginx \ --secret site.key \ --secret site.crt \ --secret source=site.conf,target=/etc/nginx/conf.d/site.conf \ --publish 3000:443 \ nginx:latest \ sh -c "exec nginx -g 'daemon off;'"
- **Docker 17.05 and earlier**: $ docker service create \ --name nginx \ --secret site.key \ --secret site.crt \ --secret site.conf \ --publish 3000:443 \ nginx:latest \ sh -c "ln -s /run/secrets/site.conf /etc/nginx/conf.d/site.conf && exec nginx -g 'daemon off;'"
第一个示例显示秘密的短语和长语,而第二个示例仅显示短语法。简短语法创建/run/secrets/
与机密具有相同名称的文件。在正在运行的容器中,现在存在以下三个文件:
- `/run/secrets/site.key`- `/run/secrets/site.crt`- `/etc/nginx/conf.d/site.conf` (or `/run/secrets/site.conf` if you used the second example)
验证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://localhost: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 please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> $ openssl s_client -connect localhost: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 site.conf
在本例中,您使用自定义root密码创建单节点MySQL服务,将凭证添加为秘密,并创建使用这些凭证连接到MySQL的单节点WordPress服务。下一个示例基于这个示例,向您展示如何旋转MySQL密码并更新服务,以便WordPress服务仍然可以连接到MySQL。
此示例说明了一些使用Docker机密的技巧,以避免将敏感凭证保存在映像中或直接在命令行上传递它们。
注意:为简单起见,此示例使用单引擎群,并使用单节点MySQL服务,因为单个MySQL服务器实例无法通过简单地使用复制服务来扩展,并且设置MySQL群集超出了本示例的范围。另外,更改MySQL根密码并不像更改磁盘上的文件那么简单。您必须使用查询或
mysqladmin
命令来更改MySQL中的密码。
为MySQL生成一个随机的字母数字密码,并mysql_password
使用该docker secret create
命令将其作为Docker机密存储。要使密码更短或更长,请调整该openssl
命令的最后一个参数。这只是创建相对随机密码的一种方式。如果您选择,您可以使用其他命令来生成密码。 注意:创建秘密后,您无法更新它。您只能删除并重新创建它,并且无法删除服务正在使用的秘密。但是,您可以使用授予或撤销正在运行的服务对秘密的访问权限docker service update
。如果您需要更新密码的功能,请考虑在密码名称中添加一个版本组件,以便稍后添加新版本,更新服务以使用它,然后删除旧版本。
最后一个参数设置为-
,表示输入是从标准输入读取的。
$ openssl rand -base64 20 | docker secret create mysql_password - l1vinzevzhj4goakjap5ya409
返回的值不是密码,而是密码的ID。在本教程的其余部分中,ID输出被省略。
为MySQL root
用户生成第二个秘密。此秘密不会与稍后创建的WordPress服务共享。它只需要引导mysql
服务。
$ openssl rand -base64 20 | docker secret create mysql_root_password -
列出由Docker管理的秘密docker secret ls
:
$ docker secret ls ID NAME CREATED UPDATED l1vinzevzhj4goakjap5ya409 mysql_password 41 seconds ago 41 seconds ago yvsczlx9votfw3l0nz5rlidig mysql_root_password 12 seconds ago 12 seconds ago
秘密存储在群集的加密的Raft日志中。
创建用于MySQL和WordPress服务之间通信的用户定义覆盖网络。不需要将MySQL服务公开给任何外部主机或容器。$ docker network create -d overlay mysql_private
创建MySQL服务。MySQL服务将具有以下特征:
- Because the scale is set to `1`, only a single MySQL task runs. Load-balancing MySQL is left as an exercise to the reader and involves more than just scaling the service.- Only reachable by other containers on the `mysql_private` network.- Uses the volume `mydata` to store the MySQL data, so that it persists across restarts to the `mysql` service.- The secrets are each mounted in a `tmpfs` filesystem at `/run/secrets/mysql_password` and `/run/secrets/mysql_root_password`. They are never exposed as environment variables, nor can they be committed to an image if the `docker commit` command is run. The `mysql_password` secret is the one used by the non-privileged WordPress container to connect to MySQL.- Sets the environment variables `MYSQL_PASSWORD_FILE` and `MYSQL_ROOT_PASSWORD_FILE` to point to the files `/run/secrets/mysql_password` and `/run/secrets/mysql_root_password`. The `mysql` image reads the password strings from those files when initializing the system database for the first time. Afterward, the passwords are stored in the MySQL system database itself.- Sets environment variables `MYSQL_USER` and `MYSQL_DATABASE`. A new database called `wordpress` is created when the container starts, and the `wordpress` user will have full permissions for this database only. This user will not be able to create or drop databases or change the MySQL configuration. $ docker service create \ --name mysql \ --replicas 1 \ --network mysql_private \ --mount type=volume,source=mydata,destination=/var/lib/mysql \ --secret source=mysql_root_password,target=mysql_root_password \ --secret source=mysql_password,target=mysql_password \ -e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/mysql_root_password" \ -e MYSQL_PASSWORD_FILE="/run/secrets/mysql_password" \ -e MYSQL_USER="wordpress" \ -e MYSQL_DATABASE="wordpress" \ mysql:latest
验证mysql
容器是否正在使用该docker service ls
命令运行。$ docker service ls ID NAME MODE REPLICAS IMAGE wvnh0siktqr3 mysql replicated 1/1 mysql:latest 在这一点上,你实际上可以撤销该mysql
服务对访问mysql_password
和mysql_root_password
秘密,因为密码已被保存在MySQL系统数据库。现在不要这样做,因为稍后我们会使用它们来方便旋转MySQL密码。
现在MySQL已经建立,创建一个连接到MySQL服务的WordPress服务。WordPress服务具有以下特点:
- Because the scale is set to `1`, only a single WordPress task runs. Load-balancing WordPress is left as an exercise to the reader, because of limitations with storing WordPress session data on the container filesystem.- Exposes WordPress on port 30000 of the host machine, so that you can access it from external hosts. You can expose port 80 instead if you do not have a web server running on port 80 of the host machine.- Connects to the `mysql_private` network so it can communicate with the `mysql` container, and also publishes port 80 to port 30000 on all swarm nodes.- Has access to the `mysql_password` secret, but specifies a different target file name within the container. The WordPress container will use the mount point `/run/secrets/wp_db_password`. Also specifies that the secret is not group-or-world-readable, by setting the mode to `0400`.- Sets the environment variable `WORDPRESS_DB_PASSWORD_FILE` to the file path where the secret is mounted. The WordPress service will read the MySQL password string from that file and add it to the `wp-config.php` configuration file.- Connects to the MySQL container using the username `wordpress` and the password in `/run/secrets/wp_db_password` and creates the `wordpress` database if it does not yet exist.- Stores its data, such as themes and plugins, in a volume called `wpdata` so these files persist when the service restarts.
$ docker service create \ --name wordpress \ --replicas 1 \ --network mysql_private \ --publish 30000:80 \ --mount type=volume,source=wpdata,destination=/var/www/html \ --secret source=mysql_password,target=wp_db_password,mode=0400 \ -e WORDPRESS_DB_USER="wordpress" \ -e WORDPRESS_DB_PASSWORD_FILE="/run/secrets/wp_db_password" \ -e WORDPRESS_DB_HOST="mysql:3306" \ -e WORDPRESS_DB_NAME="wordpress" \ wordpress:latest
验证服务正在使用docker service ls
和docker service ps
命令运行。$ docker service ls ID NAME MODE REPLICAS IMAGE wvnh0siktqr3 mysql replicated 1/1 mysql:latest nzt5xzae4n62 wordpress replicated 1/1 wordpress:latest $ docker service ps wordpress ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS aukx6hgs9gwc wordpress.1 wordpress:latest moby Running Running 52 seconds ago 此时,您实际上可以撤消WordPress服务对mysql_password
秘密的访问,因为WordPress已将秘密复制到其配置文件中wp-config.php
。现在不要这样做,因为我们稍后会使用它来方便旋转MySQL密码。
http://localhost:30000/
从任何swarm节点访问并使用基于Web的向导设置WordPress。所有这些设置都存储在MySQL wordpress
数据库中。WordPress自动为您的WordPress用户生成密码,这与WordPress用于访问MySQL的密码完全不同。安全地存储此密码,例如在密码管理器中。旋转秘密后,您将需要它登录WordPress。继续撰写一篇或两篇博文,并安装一个WordPress插件或主题,以验证WordPress是否完全正常运行,并且在重新启动服务时保存其状态。
如果您打算继续下一个示例,演示如何旋转MySQL根密码,请不要清除任何服务或秘密。
这个例子建立在前一个例子上。在这种情况下,您使用新的MySQL密码创建一个新密码,更新mysql
和wordpress
使用它的服务,然后删除旧密码。
注意:更改MySQL数据库的密码涉及运行额外的查询或命令,而不是仅仅更改单个环境变量或文件,因为如果数据库尚不存在,映像只设置MySQL密码,并且MySQL存储默认情况下,MySQL数据库中的密码。轮换密码或其他秘密可能涉及Docker之外的其他步骤。
创建新密码并将其存储为一个名为secret的密码mysql_password_v2
。$ openssl rand -base64 20 | docker secret create mysql_password_v2 -
更新MySQL服务,使其能够访问旧的和新的秘密。请记住,您无法更新或重命名密钥,但可以撤销秘密并使用新的目标文件名授予对其的访问权限。$ docker service update \ --secret-rm mysql_password mysql $ docker service update \ --secret-add source=mysql_password,target=old_mysql_password \ --secret-add source=mysql_password_v2,target=mysql_password \ mysql 更新服务会导致它重新启动,并且当MySQL服务第二次重新启动时,它有权访问旧密钥/run/secrets/old_mysql_password
和新密钥/run/secrets/mysql_password
。尽管MySQL服务现在可以访问旧的和新的机密,但WordPress用户的MySQL密码尚未更改。 注意:这个例子不会旋转MySQL root
密码。
现在,wordpress
使用mysqladmin
CLI 更改用户的MySQL密码。该命令从文件中读取旧密码和新密码,/run/secrets
但不在命令行上公开它们或将它们保存在shell历史记录中。快速做到这一点,并继续下一步,因为WordPress将失去连接到MySQL的能力。首先,找到mysql
容器任务的ID 。$ docker ps --filter name = mysql -q c7705cf6176f 在下面的命令中替换ID,或者使用第二个使用shell扩展的变体在一个步骤中完成所有操作。 $ docker exec <CONTAINER_ID> \ bash -c'mysqladmin --user = wordpress --password =“$(</ run / secrets / old_mysql_password)”password“$(</ run / secrets / mysql_password)” 或:$ docker exec $(docker ps --filter name = mysql -q)\ bash -c'mysqladmin --user = wordpress --password =“$(</ run / secrets / old_mysql_password)”password“$(<运行/秘密/ mysql_password)“”
更新wordpress
服务以使用新密码,保留目标路径/run/secrets/wp_db_secret
并保持文件权限0400
。这将触发WordPress服务的滚动重启,并且将使用新的秘密。$ docker service update \ --secret-rm mysql_password \ --secret-add source = mysql_password_v2,target = wp_db_password,mode = 0400 \ wordpress \ wordpress
通过再次浏览任何swarm节点上的http:// localhost:30000 /来验证WordPress是否工作正常。您需要使用在上一个任务中通过WordPress向导时使用的WordPress用户名和密码。验证您写的博文是否仍然存在,如果您更改了任何配置值,请确认它们仍然发生更改。
撤消对MySQL服务的旧密钥的访问权限,并从Docker中删除旧密钥。$ docker service update \ --secret-rm mysql_password \ mysql $ docker secret rm mysql_password
如果您想要再次运行所有这些示例,或者只是想在运行完所有示例后进行清理,请使用这些命令来删除WordPress服务,MySQL容器,mydata和wpdata卷以及Docker机密。$ docker service rm wordpress mysql $ docker volume rm mydata wpdata $ docker secret rm mysql_password_v2 mysql_root_password
如果您开发的容器可以作为服务进行部署,并且需要敏感数据(如凭证)作为环境变量,那么可以考虑调整图像以充分利用Docker机密。一种方法是确保在创建容器时传递给图像的每个参数也可以从文件中读取。
Docker库中的许多官方图像,例如上面示例中使用的wordpress图像,都以这种方式进行了更新。
当你启动一个WordPress容器时,通过将它们设置为环境变量来提供它所需的参数。WordPress图片已经更新,因此包含WordPress重要数据的环境变量(如WORDPRESS_DB_PASSWORD
变量)也可以从文件(WORDPRESS_DB_PASSWORD_FILE
)中读取它们的值。这种策略可确保向后兼容性得到保留,同时允许容器从Docker管理的秘密中读取信息,而不是直接传递。
注意:Docker机密不会直接设置环境变量。这是一个有意识的决定,因为环境变量可能会无意中泄漏到容器之间(例如,使用
--link
)。
version: '3.1'services: db: image: mysql:latest volumes: - db_data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD_FILE: /run/secrets/db_password secrets: - db_root_password - db_password wordpress: depends_on: - db image: wordpress:latest ports: - "8000:80" environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password secrets: - db_password secrets: db_password: file: db_password.txt db_root_password: file: db_root_password.txt volumes: db_data:
本示例使用撰写文件中的两个秘密创建一个简单的WordPress网站。
关键字secrets:
定义了两个秘密db_password:
和db_root_password:
。
部署时,Docker将创建这两个秘密,并使用撰写文件中指定的文件中的内容填充它们。
数据库服务使用两个秘密,并且wordpress使用一个。
在部署时,Docker将/run/secrets/<secret_name>
在服务下安装一个文件。这些文件永远不会保存在磁盘中,而是在内存中进行管理。
每个服务使用环境变量来指定服务应该在哪里查找该秘密数据。
有关秘密短语和长语法的更多信息可以在Compose文件版本3参考中找到。