你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
本文介绍如何将 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 映像中。 这样,就无需将文件装载到容器中。
Prerequisites
在 Azure Cloud Shell 中使用 Bash 环境。 有关详细信息,请参阅 Azure Cloud Shell 入门。
如果要在本地运行 CLI 引用命令,请安装 Azure CLI。 如果在 Windows 或 macOS 上运行,请考虑在 Docker 容器中运行 Azure CLI。 有关详细信息,请参阅如何在 Docker 容器中运行 Azure CLI。
如果使用的是本地安装,请使用 az login 命令登录到 Azure CLI。 要完成身份验证过程,请遵循终端中显示的步骤。 有关其他登录选项,请参阅 使用 Azure CLI 向 Azure 进行身份验证。
如果系统发出提示,则在首次使用时安装 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
创建存储容器状态和 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 旁边的挂锁来验证证书。
该屏幕截图显示了验证证书的 URL 旁边的挂锁。
若要查看证书详细信息,请选择“连接是安全的”,后跟“证书有效”。
Let's Encrypt 颁发的证书屏幕截图