使用 Docker Configs 儲存設定資料

關於 Configs

Docker Swarm 服務的 Configs 允許您將非敏感性資訊(例如設定檔)儲存在服務映像檔或執行中容器之外。這讓您可以盡可能保持映像檔的通用性,而無需將設定檔繫結到容器或使用環境變數。

Configs 的運作方式與 Secrets 類似,不同之處在於 Configs 在靜態時未加密,並且直接掛載到容器的檔案系統中,而無需使用 RAM 磁碟。Configs 可以隨時新增或移除到服務中,並且服務可以共享 Config。您甚至可以將 Configs 與環境變數或標籤結合使用,以獲得最大的彈性。Config 值可以是通用字串或二進位內容(大小上限為 500 KB)。

注意

Docker Configs 僅適用於 Swarm 服務,不適用於獨立容器。要使用此功能,請考慮將您的容器調整為規模為 1 的服務來執行。

Linux 和 Windows 服務皆支援 Configs。

Windows 支援

Docker 支援 Windows 容器上的 Configs,但實作方式有所不同,以下範例會說明這些差異。請牢記以下幾個重要的差異:

  • 具有自訂目標的設定檔不會直接繫結到 Windows 容器中,因為 Windows 不支援非目錄檔案繫結。相反地,容器的 Configs 都會掛載在容器內的 C:\ProgramData\Docker\internal\configs(應用程式不應依賴的實作細節)中。符號連結用於從該處指向容器內 Config 的所需目標。預設目標為 C:\ProgramData\Docker\configs

  • 建立使用 Windows 容器的服務時,Configs 不支援指定 UID、GID 和模式的選項。目前,Configs 只能由容器內的系統管理員和具有 system 存取權限的使用者存取。

  • 在 Windows 上,使用 --credential-spec 並以 config://<config-name> 格式建立或更新服務。這會在容器啟動之前將 gMSA 認證檔案直接傳遞到節點。沒有 gMSA 認證會寫入工作節點上的磁碟。如需詳細資訊,請參閱 將服務部署到 Swarm

Docker 如何管理 Configs

當您將 Config 新增到 Swarm 時,Docker 會透過相互 TLS 連線將 Config 傳送到 Swarm 管理器。Config 儲存在 Raft 記錄中,該記錄已加密。整個 Raft 記錄會複製到其他管理器,確保 Configs 與其他 Swarm 管理資料具有相同的ئوavailability 保證。

當您授予新建立或執行中的服務存取 Config 的權限時,Config 會以檔案的形式掛載在容器中。掛載點在容器內的位置,在 Linux 容器中預設為 /<config-name>。在 Windows 容器中,Configs 都會掛載到 C:\ProgramData\Docker\configs 中,並建立指向所需位置的符號連結,預設位置為 C:\<config-name>

您可以使用數值 ID 或使用者或群組的名稱來設定 Config 的所有權(uidgid)。您也可以指定檔案權限(mode)。Windows 容器會忽略這些設定。

  • 如果未設定,Config 將由執行容器指令的使用者(通常是 root)和該使用者的預設群組(通常也是 root)所擁有。
  • 如果未設定,Config 具有全域可讀取權限(模式 0444),除非在容器內設定了 umask,在這種情況下,模式會受到 umask 值的影響。

您可以隨時更新服務,以授予其存取其他 Configs 的權限,或撤銷其對特定 Config 的存取權限。

只有當節點是 Swarm 管理器,或者它正在執行已授予存取 Config 權限的服務任務時,節點才能存取 Configs。當容器任務停止執行時,共享給它的 Configs 將從該容器的記憶體檔案系統中卸載,並從節點的記憶體中清除。

如果節點在執行具有 Config 存取權限的任務容器時與 Swarm 失去連線,則任務容器仍然可以存取其 Configs,但在節點重新連線到 Swarm 之前無法接收更新。

您可以隨時新增或檢查個別的 Config,或列出所有 Configs。您無法移除執行中服務正在使用的 Config。請參閱 輪替 Config,了解如何在不中斷執行中服務的情況下移除 Config 的方法。

為了更輕鬆地更新或回復 Configs,請考慮在 Config 名稱中新增版本號碼或日期。由於能夠控制 Config 在特定容器內的掛載點,因此更容易做到這一點。

若要更新堆疊,請變更您的 Compose 檔案,然後重新執行 docker stack deploy -c <新的-compose-檔案> <堆疊-名稱>。如果您在該檔案中使用新的設定,您的服務將開始使用它們。請記住,設定是不可變的,因此您無法更改現有服務的檔案。相反地,您必須建立新的設定才能使用不同的檔案。

您可以執行 docker stack rm 來停止應用程式並移除堆疊。這將移除任何由具有相同堆疊名稱的 docker stack deploy 建立的設定。這會移除*所有*設定,包括那些未被服務參考的設定,以及在 docker service update --config-rm 之後留下的設定。

深入了解 docker config 指令

使用這些連結來閱讀關於特定指令的資訊,或者繼續閱讀關於在服務中使用設定的範例

範例

本節包含逐步進階的範例,說明如何使用 Docker 設定。

注意

為了簡潔起見,這些範例使用單引擎 Swarm 和未擴展的服務。範例使用 Linux 容器,但 Windows 容器也支援設定。

在 Compose 檔案中定義和使用 Configs

docker stack 指令支援在 Compose 檔案中定義設定。但是,docker compose 不支援 configs 鍵。詳情請參閱Compose 檔案參考

簡單範例:Configs 入門

這個簡單的範例示範了設定如何在幾個指令中運作。如需實際範例,請繼續閱讀進階範例:將設定與 Nginx 服務搭配使用

  1. 將設定新增至 Docker。docker config create 指令會讀取標準輸入,因為最後一個參數(代表要讀取設定的檔案)設定為 -

    $ echo "This is a config" | docker config create my-config -
    
  2. 建立 redis 服務並授予其存取設定的權限。預設情況下,容器可以在 /my-config 存取設定,但您可以使用 target 選項自訂容器上的檔案名稱。

    $ docker service create --name redis --config my-config redis:alpine
    
  3. 使用 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
    
  4. 使用 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
    
  5. 嘗試移除設定。移除失敗,因為 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
    
  6. 透過更新服務來移除正在執行的 redis 服務對設定的存取權限。

    $ docker service update --config-rm my-config redis
    
  7. 再次重複步驟 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
  8. 停止並移除服務,然後從 Docker 中移除設定。

    $ docker service rm redis
    
    $ docker config rm my-config
    

簡單範例:在 Windows 服務中使用 Configs

這是一個非常簡單的範例,示範如何在 Microsoft Windows 10 上執行的 Docker for Windows 上,將設定與執行 Windows 容器的 Microsoft IIS 服務搭配使用。這是一個將網頁儲存在設定中的簡單範例。

此範例假設您已安裝 PowerShell。

  1. 將以下內容儲存到新的檔案 index.html 中。

    <html lang="en">
      <head><title>Hello Docker</title></head>
      <body>
        <p>Hello Docker! You have deployed a HTML page.</p>
      </body>
    </html>
  2. 如果您尚未執行此操作,請初始化或加入 Swarm。

    docker swarm init
  3. index.html 檔案儲存為名為 homepage 的 Swarm 設定。

    docker config create homepage index.html
  4. 建立 IIS 服務並授予其存取 homepage 設定的權限。

    docker service create
        --name my-iis
        --publish published=8000,target=8000
        --config src=homepage,target="\inetpub\wwwroot\index.html"
        microsoft/iis:nanoserver
  5. https://#:8000/ 存取 IIS 服務。它應該會提供第一步中的 HTML 內容。

  6. 移除服務和設定。

    docker service rm my-iis
    
    docker config rm homepage

範例:使用範本化的 Config

要建立使用範本引擎產生內容的設定,請使用 --template-driver 參數並指定引擎名稱作為其參數。範本將在建立容器時呈現。

  1. 將以下內容儲存到新的檔案 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>
  2. index.html.tmpl 檔案儲存為名為 homepage 的 Swarm 設定。提供參數 --template-driver 並指定 golang 作為範本引擎。

    $ docker config create --template-driver golang homepage index.html.tmpl
    
  3. 建立一個執行 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
    
  4. 驗證服務是否正常運作:您可以連線到 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>
    

進階範例:將 Configs 與 Nginx 服務搭配使用

此範例分為兩個部分。第一部分是關於產生網站憑證,並且不直接涉及 Docker 設定,但它會設定第二部分,您將網站憑證儲存為一系列密鑰,並將 Nginx 設定儲存為設定。範例示範如何設定設定的選項,例如容器內部的目標位置和檔案權限 (mode)。

產生網站憑證

為您的網站產生根 CA 和 TLS 憑證和金鑰。對於正式網站,您可能需要使用 Let’s Encrypt 之類的服務來產生 TLS 憑證和金鑰,但此範例使用命令列工具。這個步驟有點複雜,但只是一個設定步驟,讓您可以將某些內容儲存為 Docker 密鑰。如果您想跳過這些子步驟,您可以使用 Let's Encrypt設定 Nginx 容器

  1. 產生根金鑰。

    $ openssl genrsa -out "root-ca.key" 4096
    
  2. 使用根金鑰產生 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'
    
  3. 設定根 CA。編輯一個名為 root-ca.cnf 的新檔案,並將以下內容貼到其中。這會限制根 CA 只能簽署葉憑證,而不能簽署中間 CA。

    [root_ca]
    basicConstraints = critical,CA:TRUE,pathlen:1
    keyUsage = critical, nonRepudiation, cRLSign, keyCertSign
    subjectKeyIdentifier=hash
  4. 簽署憑證。

    $ 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
    
  5. 產生網站金鑰。

    $ openssl genrsa -out "site.key" 4096
    
  6. 產生網站憑證並使用網站金鑰進行簽署。

    $ openssl req -new -key "site.key" -out "site.csr" -sha256 \
              -subj '/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost'
    
  7. 設定網站憑證。編輯一個名為 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
  8. 簽署網站憑證。

    $ 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
    
  9. Nginx 服務不需要 site.csrsite.cnf 檔案,但如果您想產生新的網站憑證,則需要它們。保護 root-ca.key 檔案。

設定 Nginx 容器

  1. 產生一個非常基本的 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;
        }
    }
  2. 建立兩個 secret,分別代表金鑰和憑證。您可以儲存任何小於 500 KB 的檔案作為 secret。這允許您將金鑰和憑證與使用它們的服務分離。在這些範例中,secret 名稱和檔案名稱相同。

    $ docker secret create site.key site.key
    
    $ docker secret create site.crt site.crt
    
  3. site.conf 檔案儲存在 Docker 設定中。第一個參數是設定的名稱,第二個參數是要讀取的檔案。

    $ docker config create site.conf site.conf
    

    列出設定

    $ docker config ls
    
    ID                          NAME                CREATED             UPDATED
    4ory233120ccg7biwvy11gl5z   site.conf           4 seconds ago       4 seconds ago
    
  4. 建立一個執行 Nginx 並可存取兩個 secret 和設定的服務。將模式設定為 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
  5. 驗證 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
    
  6. 驗證服務是否正常運作:您可以連線到 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.dev.org.tw">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)
    
  7. 除非您要繼續進行下一個範例,否則請在執行此範例後清除 nginx 服務以及儲存的 secret 和設定。

    $ docker service rm nginx
    
    $ docker secret rm site.crt site.key
    
    $ docker config rm site.conf
    

您現在已設定一個 Nginx 服務,其設定與其映像分離。您可以使用完全相同的映像但使用不同的設定來執行多個站點,而完全不需要建置自定義映像。

範例:輪替 Config

要輪換設定,您首先要儲存一個與目前使用中名稱不同的新設定。然後重新部署服務,移除舊的設定,並在容器內的相同掛載點新增新的設定。此範例以輪換 site.conf 設定檔為基礎,建立於先前的範例之上。

  1. 在本地編輯 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;
        }
    }
  2. 使用新的 site.conf 建立一個名為 site-v2.conf 的新 Docker 設定。

    $ docker config create site-v2.conf site.conf
  3. 更新 nginx 服務以使用新的設定,而不是舊的設定。

    $ docker service update \
      --config-rm site.conf \
      --config-add source=site-v2.conf,target=/etc/nginx/conf.d/site.conf,mode=0440 \
      nginx
    
  4. 使用 docker service ps nginx 驗證 nginx 服務是否已完全重新部署。完成後,您可以移除舊的 site.conf 設定。

    $ docker config rm site.conf
    
  5. 要清除,您可以移除 nginx 服務,以及 secret 和設定。

    $ docker service rm nginx
    
    $ docker secret rm site.crt site.key
    
    $ docker config rm site-v2.conf
    

您現在已更新 nginx 服務的設定,而無需重建其映像。