在側車容器以 Caddy 啟用自動 HTTPS
本文說明 Caddy 如何在容器群組當成側車容器使用,發揮反向 Proxy 的功能,為應用程式提供自動管理的 HTTPS 端點。
Caddy 是功能強大的企業就緒開放原始碼 Web 伺服器,其自動 HTTPS 是以 Go 撰寫,代表 Nginx 的替代方案。
Caddy 支援的 ACMEv2 API (RFC 8555) 與 Let's Encrypt 互動發行憑證,因此可以將憑證自動化。
在此範例中,只有 Caddy 容器會在連接埠 80/TCP 和 443/TCP 公開。 反向 Proxy 後方的應用程式會繼續維持私人狀態。 Caddy 與應用程式之間的網路通訊透過 localhost 進行。
注意
相較之下,Docker Compose 已知的容器群組內部通訊,其容器可以依名稱參考,形成了鮮明對比。
此範例會從裝載在 Microsoft Azure 儲存體帳戶的檔案共用掛接 Caddyfile,這是設定反向 Proxy 的必要條件。
注意
針對實際執行部署,使用者大多想根據 caddy,將 Caddyfile 聲場模擬至自訂 Docker 映像。 這樣一來,就不需要將檔案掛接至容器。
必要條件
在 Azure Cloud Shell 中使用 Bash 環境。 如需詳細資訊,請參閱 Azure Cloud Shell 中的 Bash 快速入門。
若要在本地執行 CLI 參考命令,請安裝 Azure CLI。 若您在 Windows 或 macOS 上執行,請考慮在 Docker 容器中執行 Azure CLI。 如需詳細資訊,請參閱〈如何在 Docker 容器中執行 Azure CLI〉。
如果您使用的是本機安裝,請使用 az login 命令,透過 Azure CLI 來登入。 請遵循您終端機上顯示的步驟,完成驗證程序。 如需其他登入選項,請參閱使用 Azure CLI 登入。
出現提示時,請在第一次使用時安裝 Azure CLI 延伸模組。 如需擴充功能詳細資訊,請參閱使用 Azure CLI 擴充功能。
執行 az version 以尋找已安裝的版本和相依程式庫。 若要升級至最新版本,請執行 az upgrade。
- 本文需要 2.0.55 版或更新版本的 Azure CLI。 如果您是使用 Azure Cloud Shell,就已安裝最新版本。
準備 Caddyfile
建立稱為 Caddyfile
的檔案並貼上下列設定。 此設定會建立反向 Proxy 設定,指向 5000/TCP 上接聽的應用程式容器。
my-app.westeurope.azurecontainer.io {
reverse_proxy http://localhost:5000
}
請務必注意,設定會參考網域名稱,而不是 IP 位址。 若要執行 ACME 通訊協定所需的挑戰步驟,並成功從 Let's Encrypt 擷取憑證,必須透過此 URL 觸達 Caddy。
注意
針對實際執行部署,使用者不妨使用他們控制的網域名稱,例如 api.company.com
,並且建立指向 my-app.westeurope.azurecontainer.io
的這類 CNAME 記錄。 若是如此,則必須確保自訂網域名稱也會用於 Caddyfile,而不是使用 Azure 指派的網域名稱 (例如, *.westeurope.azurecontainer.io
)。 此外,必須在本範例稍後所述的 ACI YAML 設定參考自訂網域名稱。
準備儲存體帳戶
建立儲存體帳戶
az storage account create \
--name <storage-account> \
--resource-group <resource-group> \
--location westeurope
將連接字串儲存至環境變數
AZURE_STORAGE_CONNECTION_STRING=$(az storage account show-connection-string --name <storage-account> --resource-group <resource-group> --output tsv)
建立儲存容器狀態和 Caddy 設定所需的檔案共用。
az storage share create \
--name proxy-caddyfile \
--account-name <storage-account>
az storage share create \
--name proxy-config \
--account-name <storage-account>
az storage share create \
--name proxy-data \
--account-name <storage-account>
擷取儲存體帳戶金鑰,並記下供稍後使用
az storage account keys list -g <resource-group> -n <storage-account>
部署容器群組
建立 YAML 檔案
建立稱為 ci-my-app.yaml
的檔案,然後貼上以下內容。 請務必將 <account-key>
換成先前收到的其中一個存取金鑰,並且據以 <storage-account>
。
此 YAML 檔案定義 reverse-proxy
和 my-app
這兩個容器。 reverse-proxy
容器會掛接先前建立的三個檔案共用。 設定也會公開 reverse-proxy
容器的連接埠 80/TCP 和 443/TCP。 這兩個容器之間的通訊只會在 localhost 進行。
注意
請務必注意,dnsNameLabel
金鑰會定義可觸達容器執行個體群組的公用 DNS 名稱,它必須符合 Caddyfile
定義的 FQDN
name: ci-my-app
apiVersion: "2021-10-01"
location: westeurope
properties:
containers:
- name: reverse-proxy
properties:
image: caddy:2.6
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 443
resources:
requests:
memoryInGB: 1.0
cpu: 1.0
limits:
memoryInGB: 1.0
cpu: 1.0
volumeMounts:
- name: proxy-caddyfile
mountPath: /etc/caddy
- name: proxy-data
mountPath: /data
- name: proxy-config
mountPath: /config
- name: my-app
properties:
image: mcr.microsoft.com/azuredocs/aci-helloworld
ports:
- port: 5000
protocol: TCP
environmentVariables:
- name: PORT
value: 5000
resources:
requests:
memoryInGB: 1.0
cpu: 1.0
limits:
memoryInGB: 1.0
cpu: 1.0
ipAddress:
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 443
type: Public
dnsNameLabel: my-app
osType: Linux
volumes:
- name: proxy-caddyfile
azureFile:
shareName: proxy-caddyfile
storageAccountName: "<storage-account>"
storageAccountKey: "<account-key>"
- name: proxy-data
azureFile:
shareName: proxy-data
storageAccountName: "<storage-account>"
storageAccountKey: "<account-key>"
- name: proxy-config
azureFile:
shareName: proxy-config
storageAccountName: "<storage-account>"
storageAccountKey: "<account-key>"
部署容器群組
使用 az group create 命令,建立資源群組:
az group create --name <resource-group> --location westeurope
使用 az container create 命令部署容器群組,並將 YAML 檔案作為引數進行傳遞。
az container create --resource-group <resource-group> --file ci-my-app.yaml
檢視部署狀態
若要檢視部署狀態,請使用下列 az container show 命令:
az container show --resource-group <resource-group> --name ci-my-app --output table
驗證 TLS 連線
確認一切順利之前,請先等容器群組完全啟動,並且留時間讓 Caddy 要求憑證。
OpenSSL
為此,我們可以使用 OpenSSL 的 s_client
子命令。
echo "Q" | openssl s_client -connect my-app.westeurope.azurecontainer.io:443
CONNECTED(00000188)
---
Certificate chain
0 s:CN = my-app.westeurope.azurecontainer.io
i:C = US, O = Let's Encrypt, CN = R3
1 s:C = US, O = Let's Encrypt, CN = R3
i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
2 s:C = US, O = Internet Security Research Group, CN = ISRG Root X1
i:O = Digital Signature Trust Co., CN = DST Root CA X3
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIEgTCCA2mgAwIBAgISAxxidSnpH4vVuCZk9UNG/pd2MA0GCSqGSIb3DQEBCwUA
MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
EwJSMzAeFw0yMzA0MDYxODAzMzNaFw0yMzA3MDUxODAzMzJaMC4xLDAqBgNVBAMT
I215LWFwcC53ZXN0ZXVyb3BlLmF6dXJlY29udGFpbmVyLmlvMFkwEwYHKoZIzj0C
AQYIKoZIzj0DAQcDQgAEaaN/wGyFcimM+1O4WzbFgO6vIlXxXqp9vgmLZHpFrNwV
aO8JbaB7hE+M5EAg34LDY80RyHgY+Ff4vTh2Z96rVqOCAl4wggJaMA4GA1UdDwEB
/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/
BAIwADAdBgNVHQ4EFgQUoL5DP+4PWiyE79hL5o+v8uymHdAwHwYDVR0jBBgwFoAU
FC6zF7dYVsuuUAlA5h+vnYsUwsYwVQYIKwYBBQUHAQEESTBHMCEGCCsGAQUFBzAB
hhVodHRwOi8vcjMuby5sZW5jci5vcmcwIgYIKwYBBQUHMAKGFmh0dHA6Ly9yMy5p
LmxlbmNyLm9yZy8wLgYDVR0RBCcwJYIjbXktYXBwLndlc3RldXJvcGUuYXp1cmVj
b250YWluZXIuaW8wTAYDVR0gBEUwQzAIBgZngQwBAgEwNwYLKwYBBAGC3xMBAQEw
KDAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwggEEBgor
BgEEAdZ5AgQCBIH1BIHyAPAAdgC3Pvsk35xNunXyOcW6WPRsXfxCz3qfNcSeHQmB
Je20mQAAAYdX8+CQAAAEAwBHMEUCIQC9Ztqd3DXoJhOIHBW+P7ketGrKlVA6nPZl
9CiOrn6t8gIgXHcrbBqItemndRMv+UJ3DaBfTkYOqECecOJCgLhSYNUAdgDoPtDa
PvUGNTLnVyi8iWvJA9PL0RFr7Otp4Xd9bQa9bgAAAYdX8+CAAAAEAwBHMEUCIBJ1
24z44vKFUOLCi1a7ymVuWErkmLb/GtysvcxILaj0AiEAr49hyKfen4BbSTwC8Fg4
/LgZnn2F3uHI+9p+ZMO9xTAwDQYJKoZIhvcNAQELBQADggEBACqxa21eiW3JrZwk
FHgpd6SxhUeecrYXxFNva1Y6G//q2qCmGeKK3GK+ZGPqDtcoASH5t5ghV4dIT4WU
auVDLFVywXzR8PT6QUu3W8QxU+W7406twBf23qMIgrF8PIWhStI5mn1uCpeqlnf5
HpRaj2f5/5n19pcCZcrRx94G9qhPYdMzuy4mZRhxXRqrpIsabqX3DC2ld8dszCvD
pkV61iuARgm3MIQz1yL/x5Bn4nywjnhYZA4KFktC0Ti55cPRh1mkzGQAsYQDdWrq
dVav+U9dOLQ4Sq4suaDmzDzApr+hpQSJhwgRN16+tLMyZ6INAU2JWKDxiyDTdOuH
jz456og=
-----END CERTIFICATE-----
subject=CN = my-app.westeurope.azurecontainer.io
issuer=C = US, O = Let's Encrypt, CN = R3
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: ECDSA
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 4208 bytes and written 401 bytes
Verification error: unable to get local issuer certificate
---
New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 20 (unable to get local issuer certificate)
---
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_AES_128_GCM_SHA256
Session-ID: 85F1A4290F99A0DD28C8CB21EF4269E7016CC5D23485080999A8548057729B24
Session-ID-ctx:
Resumption PSK: 752D438C19A5DBDBF10781F863D5E5D9A8859230968A9EAFFF7BBA86937D004F
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 604800 (seconds)
TLS session ticket:
0000 - 2f 25 98 90 9d 46 9b 01-03 78 db bd 4d 64 b3 a6 /%...F...x..Md..
0010 - 52 c0 7a 8a b6 3d b8 4b-c0 d7 fc 04 e8 63 d4 bb R.z..=.K.....c..
0020 - 15 b3 25 b7 be 64 3d 30-2b d7 dc 7a 1a d1 22 63 ..%..d=0+..z.."c
0030 - 42 30 90 65 6b b5 e1 83-a3 6c 76 c8 f6 ae e9 31 B0.ek....lv....1
0040 - 45 91 33 57 8e 9f 4b 6a-2e 2c 9b f9 87 5f 71 1d E.3W..Kj.,..._q.
0050 - 5a 84 59 50 17 31 1f 62-2b 0e 1e e5 70 03 d9 e9 Z.YP.1.b+...p...
0060 - 50 1c 5d 1f a4 3c 8a 0e-f4 c5 7d ce 9e 5c 98 de P.]..<....}..\..
0070 - e5 .
Start Time: 1680808973
Timeout : 7200 (sec)
Verify return code: 20 (unable to get local issuer certificate)
Extended master secret: no
Max Early Data: 0
---
read R BLOCK
Chrome 瀏覽器
瀏覽至 https://my-app.westeurope.azurecontainer.io
,然後按一下 URL 旁的掛鎖驗證憑證。
若要查看憑證詳細資料,請先後選取 [連線安全] 與 [憑證有效]。