使用 Docker Secrets 管理敏感資料
關於 Secrets
就 Docker Swarm 服務而言,*Secret* 是一段資料區塊,例如密碼、SSH 私鑰、SSL 憑證或其他不應透過網路傳輸或以未加密形式儲存在 Dockerfile 或應用程式原始碼中的資料。您可以使用 Docker *Secrets* 集中式管理此資料,並將其安全地傳輸到只有需要存取它的容器。Secrets 在 Docker Swarm 中傳輸和靜止時都會加密。指定的 Secret 只能由被授予明確存取權限的服務存取,並且只有在這些服務任務正在執行時才能存取。
您可以使用 Secrets 來管理容器在執行階段需要的任何敏感資料,但您不想將其儲存在映像檔或原始碼控制中,例如
- 使用者名稱和密碼
- TLS 憑證和金鑰
- SSH 金鑰
- 其他重要資料,例如資料庫名稱或內部伺服器名稱
- 通用字串或二進位內容(大小上限為 500 kb)
注意
Docker Secrets 僅適用於 Swarm 服務,不適用於獨立容器。要使用此功能,請考慮將您的容器調整為以服務方式執行。狀態容器通常可以以縮放比例 1 執行,而無需更改容器程式碼。
使用 Secrets 的另一個應用案例是在容器和一組憑證之間提供一層抽象。考慮一個場景,您的應用程式有獨立的開發、測試和生產環境。這些環境中的每一個都可以有不同的憑證,這些憑證儲存在開發、測試和生產 Swarm 中,並使用相同的 Secret 名稱。您的容器只需要知道 Secret 的名稱即可在所有三個環境中運作。
您也可以使用 Secrets 來管理非敏感資料,例如設定檔。但是,Docker 支援使用 configs 來儲存非敏感資料。Configs 直接掛載到容器的檔案系統中,而無需使用 RAM 磁碟。
Windows 支援
Docker 包含對 Windows 容器上的 Secrets 的支援。如果實作方式存在差異,則會在以下範例中說明。請記住以下顯著差異
Microsoft Windows 沒有用於管理 RAM 磁碟的內建驅動程式,因此在執行的 Windows 容器中,Secrets 會以明文形式持續保存到容器的根磁碟。但是,當容器停止時,Secrets 會被明確移除。此外,Windows 不支援使用
docker commit
或類似指令將正在執行的容器保存為映像檔。在 Windows 上,建議您在主機電腦上包含 Docker 根目錄的磁碟區上啟用 BitLocker,以確保正在執行的容器的 Secrets 在靜止時已加密。
由於 Windows 不支援非目錄檔案的繫結掛載,因此具有自訂目標的機密檔案不會直接繫結掛載到 Windows 容器中。相對地,容器的機密檔案都會掛載到容器內的 `C:\ProgramData\Docker\internal\secrets`(應用程式不應依賴的實作細節)。符號連結則用於從該處指向容器內機密檔案的所需目標。預設目標是 `C:\ProgramData\Docker\secrets`。
建立使用 Windows 容器的服務時,機密檔案不支援指定 UID、GID 和模式的選項。目前,只有管理員和具有容器內 `system` 存取權限的使用者才能存取機密檔案。
Docker 如何管理 Secrets
當您將機密檔案新增到叢集時,Docker 會透過相互 TLS 連線將機密檔案傳送到叢集管理員。機密檔案會儲存在 Raft 日誌中,該日誌已加密。整個 Raft 日誌會在其他管理員之間複寫,確保機密檔案與其他叢集管理資料具有相同的 高可用性 保證。
當您授予新建立或正在執行的服務存取機密檔案的權限時,解密後的機密檔案會掛載到容器內的記憶體檔案系統中。掛載點在容器內的位置,在 Linux 容器中預設為 `/run/secrets/<secret_name>`,在 Windows 容器中則為 `C:\ProgramData\Docker\secrets`。您也可以指定自訂位置。
您可以隨時更新服務,以授予其存取其他機密檔案的權限,或撤銷其對特定機密檔案的存取權限。
只有當節點是叢集管理員,或是正在執行已授予存取機密檔案權限的服務任務時,該節點才能存取(已加密的)機密檔案。當容器任務停止執行時,分享給它的解密後機密檔案會從該容器的記憶體檔案系統中卸載,並從節點的記憶體中清除。
如果節點在執行具有存取機密檔案權限的任務容器時與叢集失去連線,則任務容器仍然可以存取其機密檔案,但在節點重新連線到叢集之前無法接收更新。
您可以隨時新增或檢查個別的機密檔案,或列出所有機密檔案。您無法移除正在執行的服務正在使用的機密檔案。請參閱輪替機密檔案,了解如何在不中斷正在執行的服務的情況下移除機密檔案。
為了更輕鬆地更新或回滾機密檔案,請考慮在機密檔案名稱中加入版本號碼或日期。透過控制機密檔案在特定容器內的掛載點,可以更輕鬆地做到這一點。
閱讀更多關於 docker secret
指令
使用這些連結來閱讀有關特定指令的資訊,或繼續閱讀關於將機密檔案與服務搭配使用的範例。
docker secret create
docker secret inspect
docker secret ls
docker secret rm
- `docker service create` 的 `--secret` 旗標
- `docker service update` 的 `--secret-add` 和 `--secret-rm` 旗標
範例
本節包含三個循序漸進的範例,說明如何使用 Docker 機密檔案。這些範例中使用的映像檔已更新,以便更輕鬆地使用 Docker 機密檔案。若要了解如何在您自己的映像檔中進行類似的修改,請參閱在您的映像檔中建置 Docker 機密檔案的支援。
注意
為了簡潔起見,這些範例使用單引擎叢集和未擴展的服務。範例使用 Linux 容器,但 Windows 容器也支援機密檔案。請參閱Windows 支援。
在 Compose 檔案中定義和使用 Secrets
`docker-compose` 和 `docker stack` 指令都支援在 compose 檔案中定義機密檔案。詳情請參閱Compose 檔案參考。
簡單範例:Secrets 入門
這個簡單的範例示範了如何在幾個指令中使用機密檔案。如需實際範例,請繼續閱讀中級範例:將機密檔案與 Nginx 服務搭配使用。
將機密檔案新增到 Docker。`docker secret create` 指令會讀取標準輸入,因為最後一個參數(代表要讀取機密檔案的檔案)設定為 `-`。
$ printf "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 ago
如果發生錯誤,且任務失敗並重複重新啟動,您會看到如下所示的內容
$ 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)"
使用 `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 /run/secrets total 4 -r--r--r-- 1 root root 17 Dec 13 22:48 my_secret_data $ docker container 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 container 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
簡單範例:在 Windows 服務中使用 Secrets
這是一個非常簡單的範例,示範如何在執行 Windows 容器的 Microsoft Windows 10 上的 Docker for Windows 上,使用在 Docker 上執行的 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` 的叢集機密檔案。
> docker secret create homepage index.html
建立 IIS 服務並授予其存取 `homepage` 機密檔案的權限。
> docker service create ` --name my-iis ` --publish published=8000,target=8000 ` --secret src=homepage,target="\inetpub\wwwroot\index.html" ` microsoft/iis:nanoserver
注意
技術上來說,沒有理由在此範例中使用機密檔案;configs 更適合。此範例僅供說明之用。
在 `http://localhost:8000/` 存取 IIS 服務。它應該會提供第一步中的 HTML 內容。
移除服務和機密檔案。
> docker service rm my-iis > docker secret rm homepage > docker image remove secret-test
中級範例:將 Secrets 與 Nginx 服務一起使用
此範例分為兩個部分。第一部分 說明產生網站憑證,且不直接涉及 Docker 機密檔案,但它會設定 第二部分,您可以在其中儲存網站憑證和 Nginx 設定並將其用作機密檔案。
產生網站憑證
為您的網站產生根 CA 和 TLS 憑證及金鑰。對於正式網站,您可能需要使用 `Let’s Encrypt` 等服務來產生 TLS 憑證和金鑰,但此範例使用命令列工具。這個步驟有點複雜,但只是一個設定步驟,讓您可以將某些內容儲存為 Docker 機密檔案。如果您想略過這些子步驟,您可以 使用 Let's Encrypt。
產生根金鑰。
$ 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; } }
建立三個機密檔案,分別代表金鑰、憑證和 `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
放置到位並一步執行容器。預設情況下,Secrets 位於容器中的
/run/secrets/
目錄內,這可能需要在容器中執行額外步驟才能在不同的路徑中使用 Secret。以下範例建立一個指向site.conf
檔案實際位置的符號連結,以便 Nginx 可以讀取它。$ docker service create \ --name nginx \ --secret site.key \ --secret site.crt \ --secret site.conf \ --publish published=3000,target=443 \ nginx:latest \ sh -c "ln -s /run/secrets/site.conf /etc/nginx/conf.d/site.conf && exec nginx -g 'daemon off;'"
Secrets 允許您使用
target
選項指定自訂位置,而不是建立符號連結。以下範例說明如何在不使用符號連結的情況下,在容器內將site.conf
secret 提供於/etc/nginx/conf.d/site.conf
。$ docker service create \ --name nginx \ --secret site.key \ --secret site.crt \ --secret source=site.conf,target=/etc/nginx/conf.d/site.conf \ --publish published=3000,target=443 \ nginx:latest \ sh -c "exec nginx -g 'daemon off;'"
site.key
和site.crt
secrets 使用簡短語法,沒有設定自訂target
位置。簡短語法會將 secrets 掛載在 `/run/secrets/` 中,名稱與 secret 相同。在執行的容器中,現在存在以下三個檔案:/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://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. refer to <a href="https://nginx.dev.org.tw">nginx.org</a>.<br/> Commercial support is available at <a href="https://www.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
服務和儲存的 secrets。$ docker service rm nginx $ docker secret rm site.crt site.key site.conf
進階範例:將 Secrets 與 WordPress 服務一起使用
在此範例中,您將使用自訂 root 密碼建立單節點 MySQL 服務,將憑證新增為 secrets,並建立一個使用這些憑證連線到 MySQL 的單節點 WordPress 服務。下一個範例以此為基礎,並向您展示如何輪替 MySQL 密碼並更新服務,以便 WordPress 服務仍然可以連線到 MySQL。
此範例說明了一些使用 Docker secrets 的技巧,以避免將敏感憑證儲存在映像檔中或直接在命令列上传遞它們。
注意
為了簡化起見,此範例使用單引擎 Swarm,並使用單節點 MySQL 服務,因為單個 MySQL 伺服器執行個體無法僅透過使用複製服務來擴展,且設定 MySQL 叢集不在此範例的範圍內。
此外,變更 MySQL root 密碼不像變更磁碟上的檔案那麼簡單。您必須使用查詢或
mysqladmin
命令來變更 MySQL 中的密碼。
使用
docker secret create
命令,為 MySQL 產生一個隨機的英數字密碼,並將其儲存為名為mysql_password
的 Docker secret。要縮短或加長密碼,請調整openssl
命令的最後一個參數。這只是建立相對隨機密碼的一種方法。您可以選擇使用其他命令來產生密碼。注意
建立 secret 後,您無法更新它。您只能移除並重新建立它,而且您無法移除服務正在使用的 secret。但是,您可以使用
docker service update
來授予或撤銷正在執行的服務對 secrets 的存取權。如果您需要更新 secret 的能力,請考慮在 secret 名稱中新增版本元件,以便您稍後可以新增新版本,更新服務以使用它,然後移除舊版本。最後一個參數設定為
-
,表示輸入是從標準輸入讀取的。$ openssl rand -base64 20 | docker secret create mysql_password - l1vinzevzhj4goakjap5ya409
傳回的值不是密碼,而是 secret 的 ID。在本教學課程的其餘部分中,會省略 ID 輸出。
為 MySQL
root
使用者產生第二個 secret。此 secret 不會與稍後建立的 WordPress 服務共享。它僅用於啟動mysql
服務。$ openssl rand -base64 20 | docker secret create mysql_root_password -
使用
docker secret ls
列出 Docker 管理的 secrets。$ 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
Secrets 儲存在 Swarm 的加密 Raft 日誌中。
建立一個使用者定義的覆蓋網路,用於 MySQL 和 WordPress 服務之間的通訊。無需將 MySQL 服務公開給任何外部主機或容器。
$ docker network create -d overlay mysql_private
建立 MySQL 服務。MySQL 服務具有以下特性:
因為規模設定為
1
,所以只會執行單個 MySQL 工作。負載平衡 MySQL 留給讀者自行練習,它不僅僅是擴展服務而已。僅可由
mysql_private
網路上的其他容器存取。使用磁碟區
mydata
來儲存 MySQL 資料,以便在mysql
服務重新啟動時保持持久性。每個 secrets 都掛載在
/run/secrets/mysql_password
和/run/secrets/mysql_root_password
的tmpfs
檔案系統中。它們永遠不會公開為環境變數,如果執行docker commit
命令,它們也無法提交到映像檔。mysql_password
secret 是非特權 WordPress 容器用於連線到 MySQL 的 secret。設定環境變數
MYSQL_PASSWORD_FILE
和MYSQL_ROOT_PASSWORD_FILE
,使其指向檔案/run/secrets/mysql_password
和/run/secrets/mysql_root_password
。mysql
映像檔在第一次初始化系統資料庫時,會從這些檔案中讀取密碼字串。之後,密碼會儲存在 MySQL 系統資料庫本身中。設定環境變數
MYSQL_USER
和MYSQL_DATABASE
。容器啟動時會建立一個名為wordpress
的新資料庫,且wordpress
使用者僅對此資料庫具有完整權限。此使用者無法建立或刪除資料庫或變更 MySQL 設定。$ 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
使用
docker service ls
命令驗證mysql
容器是否正在執行。$ docker service ls ID NAME MODE REPLICAS IMAGE wvnh0siktqr3 mysql replicated 1/1 mysql:latest
現在 MySQL 已設定完成,請建立一個連線到 MySQL 服務的 WordPress 服務。WordPress 服務具有以下特性:
- 因為規模設定為
1
,所以只會執行單個 WordPress 工作。負載平衡 WordPress 留給讀者自行練習,因為將 WordPress 工作階段資料儲存在容器檔案系統上存在限制。 - 在主機的連接埠 30000 上公開 WordPress,以便您可以從外部主機存取它。如果您的主機的連接埠 80 上沒有執行網路伺服器,則可以改為公開連接埠 80。
- 連線到
mysql_private
網路,以便它可以與mysql
容器通訊,並且將連接埠 80 發佈到所有 Swarm 節點上的連接埠 30000。 - 可以存取
mysql_password
secret,但在容器內指定了不同的目標檔名。WordPress 容器使用掛載點/run/secrets/wp_db_password
。 - 將環境變數
WORDPRESS_DB_PASSWORD_FILE
設定為掛載 secret 的檔案路徑。WordPress 服務會從該檔案中讀取 MySQL 密碼字串,並將其新增到wp-config.php
設定檔中。 - 使用使用者名稱
wordpress
和/run/secrets/wp_db_password
中的密碼連線到 MySQL 容器,如果wordpress
資料庫尚不存在,則建立它。 - 將其資料(例如佈景主題和外掛程式)儲存在名為
wpdata
的磁碟區中,以便在服務重新啟動時這些檔案保持持久性。
$ docker service create \ --name wordpress \ --replicas 1 \ --network mysql_private \ --publish published=30000,target=80 \ --mount type=volume,source=wpdata,destination=/var/www/html \ --secret source=mysql_password,target=wp_db_password \ -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
secret 的存取權,因為 WordPress 已將 secret 複製到其設定檔wp-config.php
中。現在先不要這樣做,因為我們稍後會使用它來方便輪替 MySQL 密碼。從任何 Swarm 節點存取
http://localhost:30000/
並使用網路精靈設定 WordPress。所有這些設定都儲存在 MySQLwordpress
資料庫中。WordPress 會自動為您的 WordPress 使用者產生一個密碼,該密碼與 WordPress 用於存取 MySQL 的密碼完全不同。請將此密碼安全地儲存,例如儲存在密碼管理員中。您需要它才能在輪替 secret 後登入 WordPress。繼續撰寫一兩篇部落格文章,並安裝 WordPress 外掛程式或佈景主題,以驗證 WordPress 是否完全正常運作,以及其狀態是否在服務重新啟動後儲存。
如果您打算繼續下一個範例(示範如何輪替 MySQL root 密碼),請勿清除任何服務或 secrets。
範例:輪替 Secret
此範例建立在前一個範例的基礎上。在此情境中,您將使用新的 MySQL 密碼建立新的 secret,更新 mysql
和 wordpress
服務以使用它,然後移除舊的 secret。
注意
變更 MySQL 資料庫上的密碼涉及執行額外的查詢或命令,而不僅僅是變更單個環境變數或檔案,因為映像檔僅在資料庫尚不存在時才設定 MySQL 密碼,而且 MySQL 預設會將密碼儲存在 MySQL 資料庫中。輪替密碼或其他 secrets 可能涉及 Docker 以外的額外步驟。
建立新密碼並將其儲存為名為
mysql_password_v2
的 secret。$ openssl rand -base64 20 | docker secret create mysql_password_v2 -
更新 MySQL 服務,使其可以存取舊的和新的 secrets。請記住,您無法更新或重新命名 secret,但您可以撤銷 secret 並使用新的目標檔名授予對它的存取權。
$ 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
下的舊 secret 和/run/secrets/mysql_password
下的新 secret。即使 MySQL 服務現在可以存取舊的和新的 secrets,但 WordPress 使用者的 MySQL 密碼尚未變更。
注意
此範例不會輪替 MySQL
root
密碼。現在,使用
mysqladmin
CLI 變更wordpress
使用者的 MySQL 密碼。此命令會從/run/secrets
中的檔案讀取舊密碼和新密碼,但不會在命令列上公開它們或將它們儲存在 Shell 歷程記錄中。請快速執行此操作並繼續下一步,因為 WordPress 會失去連線到 MySQL 的能力。
首先,找到
mysql
容器工作的 ID。$ docker ps --filter name=mysql -q c7705cf6176f
將 ID 替換到以下命令中,或使用第二個變體,該變體使用 Shell 展開來一步完成所有操作。
$ docker container exec <CONTAINER_ID> \ bash -c 'mysqladmin --user=wordpress --password="$(< /run/secrets/old_mysql_password)" password "$(< /run/secrets/mysql_password)"'
或者
$ docker container exec $(docker ps --filter name=mysql -q) \ bash -c 'mysqladmin --user=wordpress --password="$(< /run/secrets/old_mysql_password)" password "$(< /run/secrets/mysql_password)"'
更新
wordpress
服務以使用新密碼,將目標路徑保持在/run/secrets/wp_db_password
。這會觸發 WordPress 服務的滾動重新啟動,並使用新的 secret。$ docker service update \ --secret-rm mysql_password \ --secret-add source=mysql_password_v2,target=wp_db_password \ wordpress
再次瀏覽到任何 Swarm 節點上的 http://localhost:30000/ 以驗證 WordPress 是否正常運作。使用您在先前任務中執行 WordPress 精靈時使用的 WordPress 使用者名稱和密碼。
驗證您撰寫的部落格文章仍然存在,如果您變更了任何設定值,請驗證它們是否仍然已變更。
撤銷 MySQL 服務對舊 secret 的存取權,並從 Docker 中移除舊 secret。
$ docker service update \ --secret-rm mysql_password \ mysql $ docker secret rm mysql_password
執行以下命令以移除 WordPress 服務、MySQL 容器、
mydata
和wpdata
磁碟區,以及 Docker secrets。$ docker service rm wordpress mysql $ docker volume rm mydata wpdata $ docker secret rm mysql_password_v2 mysql_root_password
在您的映像檔中建置 Docker Secrets 支援
如果您開發的容器可以作為服務部署並且需要敏感資料(例如憑證)作為環境變數,請考慮調整您的映像檔以利用 Docker secrets。一種方法是確保您在建立容器時傳遞給映像檔的每個參數也可以從檔案中讀取。
許多 Docker 官方映像檔在 Docker 程式庫 中,例如上述範例中使用的 wordpress 映像檔,都已以此方式更新。
當您啟動 WordPress 容器時,您可以透過將參數設定為環境變數來提供它所需的參數。WordPress 映像檔已更新,因此包含 WordPress 重要資料的環境變數(例如 WORDPRESS_DB_PASSWORD
)也具有可以從檔案讀取其值的變體(WORDPRESS_DB_PASSWORD_FILE
)。此策略可確保保留向下相容性,同時允許您的容器從 Docker 管理的密鑰讀取資訊,而不是直接傳遞。
注意
Docker 密鑰不會直接設定環境變數。這是一個經過深思熟慮的決定,因為環境變數可能會在容器之間意外洩漏(例如,如果您使用
--link
)。
在 Compose 中使用 Secrets
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:
此範例使用 Compose 檔案中的兩個密鑰建立一個簡單的 WordPress 網站。
頂層元素 secrets
定義了兩個密鑰 db_password
和 db_root_password
。
部署時,Docker 會建立這兩個密鑰,並使用 Compose 檔案中指定檔案的內容來填充它們。
db
服務使用兩個密鑰,而 wordpress
使用一個。
當您部署時,Docker 會在服務中的 /run/secrets/<secret_name>
下掛載一個檔案。這些檔案永遠不會持久保存在磁碟上,而是在記憶體中管理。
每個服務都使用環境變數來指定服務應在何處尋找該密鑰資料。
更多關於密鑰簡短語法和完整語法的資訊,請參閱 Compose 規格。