?
This document uses PHP Chinese website manual Release
就Docker Swarm服務而言,秘密是一組數(shù)據(jù),如密碼,SSH私鑰,SSL證書或另一部分數(shù)據(jù),這些數(shù)據(jù)不應通過網(wǎng)絡傳輸或在Dockerfile或應用程序中未加密存儲源代碼。在Docker 1.13及更高版本中,您可以使用Docker 機密來集中管理這些數(shù)據(jù),并將其安全地傳輸給需要訪問的那些容器。在運輸過程中密碼被加密,并在Docker群中休息。給定的秘密只能被那些被授予明確訪問權(quán)限的服務訪問,并且只有在這些服務任務正在運行時才能訪問。
您可以使用秘密來管理容器在運行時需要的任何敏感數(shù)據(jù),但不想將其存儲在映像或源代碼管理中,例如:
用戶名和密碼
TLS證書和密鑰
SSH密鑰
其他重要數(shù)據(jù),如數(shù)據(jù)庫或內(nèi)部服務器的名稱
通用字符串或二進制內(nèi)容(最大為500 kb)
注意:Docker機密僅適用于群集服務,而不適用于獨立容器。要使用此功能,請考慮將您的容器作為1級服務運行。
另一個使用秘密的用例是在容器和一組證書之間提供一個抽象層??紤]一個場景,您可以為應用程序分別開發(fā),測試和生產(chǎn)環(huán)境。這些環(huán)境中的每一個都可以擁有不同的憑證,并以相同的秘密名稱存儲在開發(fā),測試和生產(chǎn)群中。您的容器只需要知道秘密的名稱,以便在三種環(huán)境中都能正常工作。
您還可以使用機密來管理非敏感數(shù)據(jù),例如配置文件。但是,Docker 17.06和更高版本支持使用configs來存儲非敏感數(shù)據(jù)。配置直接安裝到容器的文件系統(tǒng)中,而不使用RAM磁盤。
Docker 17.06和更高版本包含對Windows容器上的秘密的支持。在實現(xiàn)中存在差異的地方,它們在下面的例子中被調(diào)用。牢記以下顯著差異:
Microsoft Windows沒有用于管理RAM磁盤的內(nèi)置驅(qū)動程序,因此在運行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
容器內(nèi)的(應用程序不應該依賴的實現(xiàn)細節(jié)中)。符號鏈接用于指向容器內(nèi)的秘密所需的目標。默認目標是C:\ProgramData\Docker\secrets
。
在創(chuàng)建使用Windows容器的服務時,用于指定UID,GID和模式的選項不受秘密支持。當前只能由管理員和system
容器內(nèi)的訪問權(quán)限的用戶訪問秘密。
當您為swarm添加秘密時,Docker會通過相互TLS連接將密鑰發(fā)送給swarm管理器。秘密存儲在加密的Raft日志中。整個Raft日志被復制到其他管理者中,確保與其他群管理數(shù)據(jù)相同的高可用性保證。
警告:Raft數(shù)據(jù)在Docker 1.13和更高版本中被加密。如果您的任何Swarm管理人員運行早期版本,并且其中一位經(jīng)理成為群體經(jīng)理,則秘密將以未加密方式存儲在該節(jié)點的Raft日志中。在添加任何秘密之前,將所有管理器節(jié)點更新到Docker 1.13或更高版本,以防止將秘密寫入純文本的Raft日志。
當您授予新創(chuàng)建或正在運行的服務對秘密的訪問權(quán)限時,解密的秘密將被裝入容器中的內(nèi)存中文件系統(tǒng)。 容器中安裝點的位置默認為Linux容器中的/ run / secrets / <secret_name>,或Windows容器中的C:\ ProgramData \ Docker \ secrets。 您可以在Docker 17.06和更高版本中指定自定義位置。
您可以更新服務,授權(quán)其訪問其他機密或隨時撤銷對指定機密的訪問權(quán)限。
如果節(jié)點是群管理器或者它正在運行已被授權(quán)訪問秘密的服務任務,那么節(jié)點只能訪問(加密的)秘密。當容器任務停止運行時,共享給它的解密秘密將從該容器的內(nèi)存中文件系統(tǒng)卸載,并從節(jié)點的內(nèi)存刷新。
如果節(jié)點在運行可訪問秘密的任務容器時失去與群集的連接,則任務容器仍可訪問其秘密,但在節(jié)點重新連接群集之前無法接收更新。
您可以隨時添加或檢查個人密碼,或列出所有密碼。您無法刪除正在運行的服務正在使用的秘密。請參閱旋轉(zhuǎn)秘密以在不中斷正在運行的服務的情況下移除秘密。
為了更容易地更新或回滾秘密,請考慮在秘密名稱中添加版本號或日期。通過控制給定容器內(nèi)秘密的安裝點的能力使這變得更容易。
docker secret
命令的信息使用這些鏈接閱讀有關(guān)特定命令的內(nèi)容,或繼續(xù)關(guān)于在服務中使用秘密的示例。
docker secret create
docker secret inspect
docker secret ls
docker secret rm
--secret
標志為 docker service create
--secret-add
和--secret-rm
標志docker service update
本節(jié)包含三個演示如何使用Docker機密的畢業(yè)示例。這些示例中使用的圖像已更新,以便于使用Docker機密。要了解如何以類似的方式修改自己的圖像,請參閱將Docker機密支持構(gòu)建到圖像中。
注意:為簡單起見,這些示例使用單引擎群和非標度服務。這些示例使用Linux容器,但Windows容器也支持Docker 17.06和更高版本中的秘密。請參閱Windows支持。
這個簡單的例子展示了秘密如何在幾個命令中工作。對于真實世界的例子,繼續(xù)到中級例子:使用Nginx服務的秘密。
給Docker添加一個秘密。該docker secret create
命令讀取標準輸入,因為最后一個參數(shù)表示要讀取密鑰的文件設置為-
。$ echo "This is a secret" | docker secret create my_secret_data -
創(chuàng)建一個redis
服務并授予它訪問該秘密的權(quán)限。默認情況下,容器可以訪問該密碼/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
連接到容器并讀取秘密數(shù)據(jù)文件的內(nèi)容,該內(nèi)容默認為全部可讀,并且與秘密的名稱相同。下面的第一條命令說明了如何找到容器ID,第二個和第三個命令使用shell完成來自動執(zhí)行此操作。$ 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
通過更新服務,從正在運行的服務中移除對秘密的訪問權(quán)限。$ docker service update --secret-rm my_secret_data redis
重復步驟3和4,驗證該服務不再有權(quán)訪問該秘密。容器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服務的秘密。這是一個理想的例子,它將網(wǎng)頁存儲在一個秘密中。
此示例假定您已安裝PowerShell。
將以下內(nèi)容保存到一個新文件中:index.html
<html> <head> <title> Hello Docker </ title> </ head> <body> <p> Hello Docker!您已經(jīng)部署了一個HTML頁面。</ p> </ body> </ html>
如果你還沒有這樣做,請初始化或加入群。PS> docker swarm init
將該index.html
文件保存為名為swarm的秘密homepage
。PS> docker secret創(chuàng)建主頁index.html
創(chuàng)建一個IIS服務并授予它對homepage
秘密的訪問權(quán)限。PS> docker service create --name my-iis -p 8000:8000 --secret src = homepage,target =“\ inetpub \ wwwroot \ index.html”microsoft / iis:nanoserver 注意:技術(shù)上沒有理由使用機密對于這個例子。使用Docker 17.06或更高版本,configs更適合。這個例子僅用于說明。
訪問IIS服務http://localhost:8000/
。它應該從第一步開始提供HTML內(nèi)容。
刪除服務和秘密。PS> docker service rm my-iis PS> docker secret rm homepage PS> docker image remove secret-test
這個例子分為兩部分。第一部分是關(guān)于生成站點證書的內(nèi)容,并不直接涉及Docker機密,但是它建立了第二部分,在那里存儲和使用站點證書和Nginx配置作為秘密。
為您的站點生成根CA和TLS證書和密鑰。對于生產(chǎn)站點,您可能希望使用服務Let’s Encrypt
來生成TLS證書和密鑰,但此示例使用命令行工具。這一步有點復雜,但只是一個設置步驟,以便您可以將某些內(nèi)容存儲為Docker的秘密。如果你想跳過這些子步驟,您可以使用我們的加密生成網(wǎng)站密鑰和證書,命名文件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
并將以下內(nèi)容粘貼到其中。這限制了根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
的新文件并將以下內(nèi)容粘貼到其中。這限制了站點證書,因此它只能用于對服務器進行身份驗證,并且不能用于簽名證書。server authorityKeyIdentifier = keyid,issuer basicConstraints = critical,CA:FALSE extendedKeyUsage = serverAuth keyUsage = critical,digitalSignature,keyEncipherment subjectAltName = DNS:localhost,IP:127.0.0.1 subjectKeyIdentifier = hash
簽署網(wǎng)站證書。$ 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
文件。
生成一個非?;镜腘ginx配置,通過HTTPS提供靜態(tài)文件。TLS證書和密鑰將作為Docker機密存儲,以便它們可以輕松旋轉(zhuǎn)。在當前目錄中,site.conf
使用以下內(nèi)容創(chuàng)建一個新文件: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; } }
創(chuàng)建三個機密,代表密鑰,證書和密鑰 site.conf
。只要小于500 KB,您就可以將任何文件存儲為秘密文件。這使您可以將密鑰,證書和配置與將使用它們的服務分離。在每一個這些命令中,最后一個參數(shù)代表從主機文件系統(tǒng)讀取密鑰的文件路徑。在這些示例中,秘密名稱和文件名是相同的。$ 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
創(chuàng)建一個運行Nginx并可以訪問這三個秘密的服務。 docker service create命令的最后一部分創(chuàng)建一個從site.conf秘密位置到/etc/nginx.conf.d/的符號鏈接,其中Nginx會查找額外的配置文件。 這一步發(fā)生在Nginx實際啟動之前,因此如果您更改Nginx配置,則不需要重新生成映像。
注意:通常您會創(chuàng)建一個Dockerfile,將site.conf復制到適當位置,構(gòu)建映像并使用自定義映像運行容器。 此示例不需要自定義圖像。 它將site.conf放置到位,并且一步到位運行容器。
在Docker 17.05及更早版本中,機密總是位于/run/secrets/
目錄中。Docker 17.06及更高版本允許您為容器中的秘密指定自定義位置。下面的兩個例子說明了它們的區(qū)別。該命令的較早版本要求您創(chuàng)建一個到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;'"
第一個示例顯示秘密的短語和長語,而第二個示例僅顯示短語法。簡短語法創(chuàng)建/run/secrets/
與機密具有相同名稱的文件。在正在運行的容器中,現(xiàn)在存在以下三個文件:
- `/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密碼創(chuàng)建單節(jié)點MySQL服務,將憑證添加為秘密,并創(chuàng)建使用這些憑證連接到MySQL的單節(jié)點WordPress服務。下一個示例基于這個示例,向您展示如何旋轉(zhuǎn)MySQL密碼并更新服務,以便WordPress服務仍然可以連接到MySQL。
此示例說明了一些使用Docker機密的技巧,以避免將敏感憑證保存在映像中或直接在命令行上傳遞它們。
注意:為簡單起見,此示例使用單引擎群,并使用單節(jié)點MySQL服務,因為單個MySQL服務器實例無法通過簡單地使用復制服務來擴展,并且設置MySQL群集超出了本示例的范圍。另外,更改MySQL根密碼并不像更改磁盤上的文件那么簡單。您必須使用查詢或
mysqladmin
命令來更改MySQL中的密碼。
為MySQL生成一個隨機的字母數(shù)字密碼,并mysql_password
使用該docker secret create
命令將其作為Docker機密存儲。要使密碼更短或更長,請調(diào)整該openssl
命令的最后一個參數(shù)。這只是創(chuàng)建相對隨機密碼的一種方式。如果您選擇,您可以使用其他命令來生成密碼。 注意:創(chuàng)建秘密后,您無法更新它。您只能刪除并重新創(chuàng)建它,并且無法刪除服務正在使用的秘密。但是,您可以使用授予或撤銷正在運行的服務對秘密的訪問權(quán)限docker service update
。如果您需要更新密碼的功能,請考慮在密碼名稱中添加一個版本組件,以便稍后添加新版本,更新服務以使用它,然后刪除舊版本。
最后一個參數(shù)設置為-
,表示輸入是從標準輸入讀取的。
$ openssl rand -base64 20 | docker secret create mysql_password - l1vinzevzhj4goakjap5ya409
返回的值不是密碼,而是密碼的ID。在本教程的其余部分中,ID輸出被省略。
為MySQL root
用戶生成第二個秘密。此秘密不會與稍后創(chuàng)建的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日志中。
創(chuàng)建用于MySQL和WordPress服務之間通信的用戶定義覆蓋網(wǎng)絡。不需要將MySQL服務公開給任何外部主機或容器。$ docker network create -d overlay mysql_private
創(chuàng)建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系統(tǒng)數(shù)據(jù)庫。現(xiàn)在不要這樣做,因為稍后我們會使用它們來方便旋轉(zhuǎn)MySQL密碼。
現(xiàn)在MySQL已經(jīng)建立,創(chuàng)建一個連接到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
。現(xiàn)在不要這樣做,因為我們稍后會使用它來方便旋轉(zhuǎn)MySQL密碼。
http://localhost:30000/
從任何swarm節(jié)點訪問并使用基于Web的向?qū)гO置WordPress。所有這些設置都存儲在MySQL wordpress
數(shù)據(jù)庫中。WordPress自動為您的WordPress用戶生成密碼,這與WordPress用于訪問MySQL的密碼完全不同。安全地存儲此密碼,例如在密碼管理器中。旋轉(zhuǎn)秘密后,您將需要它登錄WordPress。繼續(xù)撰寫一篇或兩篇博文,并安裝一個WordPress插件或主題,以驗證WordPress是否完全正常運行,并且在重新啟動服務時保存其狀態(tài)。
如果您打算繼續(xù)下一個示例,演示如何旋轉(zhuǎn)MySQL根密碼,請不要清除任何服務或秘密。
這個例子建立在前一個例子上。在這種情況下,您使用新的MySQL密碼創(chuàng)建一個新密碼,更新mysql
和wordpress
使用它的服務,然后刪除舊密碼。
注意:更改MySQL數(shù)據(jù)庫的密碼涉及運行額外的查詢或命令,而不是僅僅更改單個環(huán)境變量或文件,因為如果數(shù)據(jù)庫尚不存在,映像只設置MySQL密碼,并且MySQL存儲默認情況下,MySQL數(shù)據(jù)庫中的密碼。輪換密碼或其他秘密可能涉及Docker之外的其他步驟。
創(chuàng)建新密碼并將其存儲為一個名為secret的密碼mysql_password_v2
。$ openssl rand -base64 20 | docker secret create mysql_password_v2 -
更新MySQL服務,使其能夠訪問舊的和新的秘密。請記住,您無法更新或重命名密鑰,但可以撤銷秘密并使用新的目標文件名授予對其的訪問權(quán)限。$ 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服務第二次重新啟動時,它有權(quán)訪問舊密鑰/run/secrets/old_mysql_password
和新密鑰/run/secrets/mysql_password
。盡管MySQL服務現(xiàn)在可以訪問舊的和新的機密,但WordPress用戶的MySQL密碼尚未更改。 注意:這個例子不會旋轉(zhuǎn)MySQL root
密碼。
現(xiàn)在,wordpress
使用mysqladmin
CLI 更改用戶的MySQL密碼。該命令從文件中讀取舊密碼和新密碼,/run/secrets
但不在命令行上公開它們或?qū)⑺鼈儽4嬖趕hell歷史記錄中。快速做到這一點,并繼續(xù)下一步,因為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
并保持文件權(quán)限0400
。這將觸發(fā)WordPress服務的滾動重啟,并且將使用新的秘密。$ docker service update \ --secret-rm mysql_password \ --secret-add source = mysql_password_v2,target = wp_db_password,mode = 0400 \ wordpress \ wordpress
通過再次瀏覽任何swarm節(jié)點上的http:// localhost:30000 /來驗證WordPress是否工作正常。您需要使用在上一個任務中通過WordPress向?qū)r使用的WordPress用戶名和密碼。驗證您寫的博文是否仍然存在,如果您更改了任何配置值,請確認它們?nèi)匀话l(fā)生更改。
撤消對MySQL服務的舊密鑰的訪問權(quán)限,并從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
如果您開發(fā)的容器可以作為服務進行部署,并且需要敏感數(shù)據(jù)(如憑證)作為環(huán)境變量,那么可以考慮調(diào)整圖像以充分利用Docker機密。一種方法是確保在創(chuàng)建容器時傳遞給圖像的每個參數(shù)也可以從文件中讀取。
Docker庫中的許多官方圖像,例如上面示例中使用的wordpress圖像,都以這種方式進行了更新。
當你啟動一個WordPress容器時,通過將它們設置為環(huán)境變量來提供它所需的參數(shù)。WordPress圖片已經(jīng)更新,因此包含WordPress重要數(shù)據(jù)的環(huán)境變量(如WORDPRESS_DB_PASSWORD
變量)也可以從文件(WORDPRESS_DB_PASSWORD_FILE
)中讀取它們的值。這種策略可確保向后兼容性得到保留,同時允許容器從Docker管理的秘密中讀取信息,而不是直接傳遞。
注意:Docker機密不會直接設置環(huán)境變量。這是一個有意識的決定,因為環(huán)境變量可能會無意中泄漏到容器之間(例如,使用
--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:
本示例使用撰寫文件中的兩個秘密創(chuàng)建一個簡單的WordPress網(wǎng)站。
關(guān)鍵字secrets:
定義了兩個秘密db_password:
和db_root_password:
。
部署時,Docker將創(chuàng)建這兩個秘密,并使用撰寫文件中指定的文件中的內(nèi)容填充它們。
數(shù)據(jù)庫服務使用兩個秘密,并且wordpress使用一個。
在部署時,Docker將/run/secrets/<secret_name>
在服務下安裝一個文件。這些文件永遠不會保存在磁盤中,而是在內(nèi)存中進行管理。
每個服務使用環(huán)境變量來指定服務應該在哪里查找該秘密數(shù)據(jù)。
有關(guān)秘密短語和長語法的更多信息可以在Compose文件版本3參考中找到。