你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
在挎斗容器中使用 Caddy 启用自动 HTTPS
本文介绍如何将 Caddy 用作容器组中的挎斗容器,并充当反向代理,以便为应用程序提供自动托管的 HTTPS 终结点。
Caddy 是一款功能强大、企业就绪的开源 Web 服务器,具有使用 Go 编写的自动 HTTPS,是 Nginx 的替代方法。
能够实现证书的自动化,因为 Caddy 支持 ACMEv2 API (RFC 8555),该 API 与 Let's Encrypt 交互以颁发证书。
在此示例中,只有 Caddy 容器在端口 80/TCP 和 443/TCP 上公开。 反向代理后面的应用程序仍旧是专用的。 Caddy 与应用程序之间的网络通信通过 localhost 进行。
注意
这与 Docker Compose 中已知的容器组内通信形成鲜明对比;如果使用后者,可按名称引用容器。
该示例从 Azure 存储帐户上托管的文件共享装载 Caddyfile,这是配置反向代理所必需的。
注意
对于生产部署,大多数用户都希望将 Caddy 文件烘焙到基于 caddy 的自定义 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
的文件并粘贴下面的配置。 此配置会创建一个反向代理配置,指向 5000/TCP 上的应用程序容器侦听。
my-app.westeurope.azurecontainer.io {
reverse_proxy http://localhost:5000
}
请务必注意,配置引用的是域名,不是 IP 地址。 需要可通过此 URL 访问 Caddy 才能执行 ACME 协议要求的质询步骤,并成功从 Let's Encrypt 检索证书。
注意
对于生产部署,用户可能需要使用他们控制的域名(例如 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 旁边的挂锁来验证证书。
若要查看证书详细信息,请选择“连接安全”,然后单击“证书有效”。