Docker与Kubernetes环境下的SSL自动化方案
Docker和Kubernetes环境下,SSL证书管理是另一个维度的问题。容器是临时的、可漂移的,传统的”申请证书 → 部署到服务器”模式不适用。
本文整理容器环境下的SSL自动化方案,从单机Docker到Kubernetes集群。
容器环境SSL的挑战
挑战一:容器无状态
容器重启后数据丢失,证书不能存在容器内部。
解决:用Volume挂载、或用Secret存储证书。
挑战二:自动扩缩容
Pod可能在任何节点启动,证书需要跟着Pod走。
解决:用Kubernetes Secret、或用Ingress统一终止SSL。
挑战三:多容器共享
一个域名可能被多个容器服务,证书需要共享。
解决:用共享Volume、或用反向代理统一SSL。
挑战四:自动续签
容器内跑cron不优雅,续签后要重启多个容器。
解决:用专门的证书管理器(cert-manager)。
方案一:Docker Compose + acme.sh
适合单机多容器场景。
架构:
acme.sh容器 → 申请证书 → 挂载Volume → Nginx容器读取
docker-compose.yml:
version: '3'
services:
certbot:
image: neilpang/acme.sh
container_name: acme
volumes:
- ./ssl:/acme.sh
- /var/run/docker.sock:/var/run/docker.sock
command: >
--issue --dns dns_ali
-d example.com -d *.example.com
environment:
- Ali_Key=${ALI_KEY}
- Ali_Secret=${ALI_SECRET}
restart: unless-stopped
nginx:
image: nginx:alpine
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl/example.com:/etc/nginx/ssl:ro
depends_on:
- certbot
restart: unless-stopped
续签后自动重载Nginx:
acme.sh的 --reloadcmd 可以调用Docker API重载容器:
acme.sh --install-cert -d example.com \
--key-file /acme.sh/example.com.key \
--fullchain-file /acme.sh/example.com.crt \
--reloadcmd "curl -X POST --unix-socket /var/run/docker.sock http://localhost/containers/nginx/restart"
方案二:Traefik自动SSL
Traefik是云原生反向代理,内置Let’s Encrypt自动证书。
docker-compose.yml:
version: '3'
services:
traefik:
image: traefik:v3.0
command:
- --providers.docker=true
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --certificatesresolvers.le.acme.email=your@email.com
- --certificatesresolvers.le.acme.storage=/acme.json
- --certificatesresolvers.le.acme.dnschallenge=true
- --certificatesresolvers.le.acme.dnschallenge.provider=alidns
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./acme.json:/acme.json
environment:
- ALICLOUD_ACCESS_KEY=${ALI_KEY}
- ALICLOUD_SECRET_KEY=${ALI_SECRET}
restart: unless-stopped
whoami:
image: traefik/whoami
labels:
- traefik.http.routers.whoami.rule=Host(`example.com`)
- traefik.http.routers.whoami.tls=true
- traefik.http.routers.whoami.tls.certresolver=le
优势:
- •全自动,加个label就HTTPS
- •支持通配符
- •支持Let’s Encrypt和ZeroSSL
劣势:
- •绑定Traefik生态
- •配置语法有学习曲线
方案三:Caddy自动HTTPS
Caddy是现代Web服务器,最大特色是默认自动HTTPS。
Caddyfile:
example.com {
reverse_proxy localhost:8080
}
*.example.com {
reverse_proxy localhost:8081
}
docker-compose.yml:
version: '3'
services:
caddy:
image: caddy:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
restart: unless-stopped
volumes:
caddy_data:
caddy_config:
启动后Caddy自动申请证书、自动续签、自动重定向HTTP到HTTPS。
优势:
- •配置极简
- •全自动HTTPS
- •支持通配符
劣势:
- •生态不如Nginx
- •插件较少
方案四:Kubernetes + cert-manager
cert-manager是Kubernetes上的证书管理标准。
架构:
cert-manager → 申请证书 → 存储到Secret → Ingress/Pod挂载
安装cert-manager:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.0/cert-manager.yaml
配置ClusterIssuer(Let’s Encrypt):
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
email: your@email.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-key
solvers:
- http01:
ingress:
class: nginx
配置DNS验证的ClusterIssuer(阿里云):
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-dns
spec:
acme:
email: your@email.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-dns-key
solvers:
- dns01:
webhook:
groupName: cert-manager-webhook-aliyun
solverName: alidns-solver
config:
accessKeyId: ${ALI_KEY}
accessKeySecret: ${ALI_SECRET}
regionId: cn-hangzhou
申请证书:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com
namespace: default
spec:
secretName: example-com-tls
issuerRef:
name: letsencrypt
kind: ClusterIssuer
dnsNames:
- example.com
- www.example.com
Ingress使用证书:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt
spec:
tls:
- hosts:
- example.com
secretName: example-com-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80
cert-manager会自动申请证书、自动续签、自动更新Secret。
方案五:Nginx Ingress Controller
Kubernetes上最常用的方案,Ingress Controller内置cert-manager集成。
安装Nginx Ingress:
helm install ingress-nginx ingress-nginx/ingress-nginx
配置Ingress自动HTTPS:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
secretName: example-com-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80
优势:
- •标准Kubernetes方案
- •集中SSL终止
- •自动续签
- •支持通配符
选型建议
| 场景 | 推荐方案 |
|——|———-|
| 单机Docker Compose | acme.sh + Volume挂载 |
| 单机多容器,要极简 | Caddy |
| 单机多容器,要灵活 | Traefik |
| 小规模K8s集群 | Nginx Ingress + cert-manager |
| 大规模K8s集群 | cert-manager + 多Issuer |
| 不想学新工具 | acme.sh + 手动挂载 |
容器SSL的最佳实践
1. 证书和代码分离
证书用Volume/Secret挂载,不要打包进镜像。
2. 集中SSL终止
用Ingress/反向代理统一处理SSL,后端服务用HTTP,简化架构。
3. 自动续签 + 自动重载
续签后要触发Web服务器重载。Docker用API触发restart,K8s用reloader控制器。
4. 备份证书存储
acme.json、Secret等证书存储要定期备份。
5. 监控证书状态
用Prometheus + blackbox_exporter监控所有Ingress的证书。
结语
容器环境下的SSL自动化比传统服务器复杂,但用对工具可以更省心。小规模用Caddy/Traefik一键搞定,大规模用cert-manager集中管理。核心思路是让证书管理成为基础设施的一部分,而不是每个应用自己的事。