14 KiB
14 KiB
K3s + Caddy + Traefik 部署文档
架构概述
互联网
↓
Caddy (宿主机 80/443) - SSL 终止 + 自动证书
↓
Traefik (ClusterIP) - Ingress 路由
↓
应用 Services
↓
应用 Pods
职责分工:
- Caddy: SSL/TLS 终止,自动获取和续期 Let's Encrypt 证书
- Traefik: Kubernetes Ingress 控制器,根据 Ingress 规则路由流量
- 应用: 通过 Service 和 Ingress 暴露服务
前置要求
系统要求
- Linux 系统(Ubuntu/Debian/CentOS 等)
- 至少 2GB RAM
- sudo 权限
- 域名已解析到服务器 IP
端口要求
- 80 (HTTP)
- 443 (HTTPS)
- 6443 (K3s API,可选)
安装步骤
1. 安装 K3s
# 下载并安装 k3s
curl -sfL https://get.k3s.io -o /tmp/k3s-install.sh
sudo sh /tmp/k3s-install.sh
# 验证安装
sudo kubectl get nodes
预期输出:
NAME STATUS ROLES AGE VERSION
host Ready control-plane 10s v1.34.3+k3s1
2. 配置 Traefik 为 ClusterIP
K3s 默认安装 Traefik 为 LoadBalancer 类型,需要改为 ClusterIP 以便 Caddy 使用宿主机端口。
# 将 Traefik Service 改为 ClusterIP
sudo kubectl patch svc traefik -n kube-system -p '{"spec":{"type":"ClusterIP"}}'
# 验证
sudo kubectl get svc -n kube-system traefik
预期输出:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
traefik ClusterIP 10.43.x.x <none> 80/TCP,443/TCP
3. 部署 Caddy
创建 Caddy 配置文件 caddy-deployment.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: caddy-config
namespace: default
data:
Caddyfile: |
{
email your-email@example.com
}
# 添加你的域名配置
app1.example.com {
reverse_proxy traefik.kube-system.svc.cluster.local:80
}
app2.example.com {
reverse_proxy traefik.kube-system.svc.cluster.local:80
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: caddy
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: caddy
template:
metadata:
labels:
app: caddy
spec:
containers:
- name: caddy
image: caddy:latest
ports:
- containerPort: 80
hostPort: 80
- containerPort: 443
hostPort: 443
volumeMounts:
- name: config
mountPath: /etc/caddy
- name: data
mountPath: /data
volumes:
- name: config
configMap:
name: caddy-config
- name: data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: caddy
namespace: default
spec:
selector:
app: caddy
ports:
- name: http
port: 80
targetPort: 80
- name: https
port: 443
targetPort: 443
type: ClusterIP
部署 Caddy:
# 应用配置
sudo kubectl apply -f caddy-deployment.yaml
# 验证 Caddy 运行状态
sudo kubectl get pods -n default -l app=caddy
4. 部署测试应用
创建测试应用 test-app.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: test-html
namespace: default
data:
index.html: |
<!DOCTYPE html>
<html>
<head>
<title>K3s Test</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.container {
text-align: center;
padding: 40px;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
}
</style>
</head>
<body>
<div class="container">
<h1>K3s + Caddy + Traefik</h1>
<p>SSL Termination Working!</p>
</div>
</body>
</html>
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-app
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: test-app
template:
metadata:
labels:
app: test-app
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
configMap:
name: test-html
---
apiVersion: v1
kind: Service
metadata:
name: test-app
namespace: default
spec:
selector:
app: test-app
ports:
- port: 80
targetPort: 80
type: ClusterIP
部署应用:
sudo kubectl apply -f test-app.yaml
5. 创建 Ingress 规则
创建 Ingress 配置 test-ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-app-ingress
namespace: default
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
rules:
- host: app1.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: test-app
port:
number: 80
应用 Ingress:
sudo kubectl apply -f test-ingress.yaml
# 查看 Ingress 状态
sudo kubectl get ingress -n default
验证部署
1. 检查所有组件状态
# 查看所有 Pods
sudo kubectl get pods -A
# 查看 Services
sudo kubectl get svc -A
# 查看 Ingress
sudo kubectl get ingress -A
2. 测试 HTTP 访问
# 测试 HTTP(会自动重定向到 HTTPS)
curl -I http://app1.example.com
预期输出:
HTTP/1.1 308 Permanent Redirect
Location: https://app1.example.com/
3. 测试 HTTPS 访问
# 测试 HTTPS
curl https://app1.example.com
预期输出: HTML 页面内容
4. 检查 SSL 证书
# 查看证书信息
echo | openssl s_client -connect app1.example.com:443 -servername app1.example.com 2>/dev/null | openssl x509 -noout -dates
添加新应用
步骤 1: 更新 Caddy 配置
# 编辑 Caddy ConfigMap
sudo kubectl edit configmap caddy-config -n default
在 Caddyfile 中添加新域名:
newapp.example.com {
reverse_proxy traefik.kube-system.svc.cluster.local:80
}
步骤 2: 重启 Caddy
sudo kubectl rollout restart deployment caddy -n default
步骤 3: 部署应用
# 创建应用的 Deployment 和 Service
sudo kubectl apply -f your-app.yaml
步骤 4: 创建 Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: newapp-ingress
namespace: default
spec:
rules:
- host: newapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: your-service-name
port:
number: 80
sudo kubectl apply -f newapp-ingress.yaml
步骤 5: 等待证书获取
# 查看 Caddy 日志,确认证书获取成功
sudo kubectl logs -n default -l app=caddy --tail=50
常用管理命令
查看日志
# Caddy 日志
sudo kubectl logs -n default -l app=caddy -f
# Traefik 日志
sudo kubectl logs -n kube-system -l app.kubernetes.io/name=traefik -f
# 应用日志
sudo kubectl logs -n default -l app=your-app -f
重启服务
# 重启 Caddy
sudo kubectl rollout restart deployment caddy -n default
# 重启应用
sudo kubectl rollout restart deployment your-app -n default
查看资源状态
# 查看所有资源
sudo kubectl get all,ingress -n default
# 查看 ConfigMap
sudo kubectl get configmap -n default
# 查看详细信息
sudo kubectl describe pod <pod-name> -n default
更新配置
# 编辑 Caddy 配置
sudo kubectl edit configmap caddy-config -n default
# 编辑 Ingress
sudo kubectl edit ingress <ingress-name> -n default
故障排查
问题 1: Caddy Pod 无法启动(Pending 状态)
症状:
sudo kubectl get pods -n default
# caddy pod 显示 Pending
原因: 端口 80/443 被占用
解决方案:
# 检查端口占用
sudo ss -tlnp | grep -E ':(80|443)\s'
# 如果 Traefik 占用,确保已改为 ClusterIP
sudo kubectl get svc -n kube-system traefik
# 如果是 LoadBalancer,执行:
sudo kubectl patch svc traefik -n kube-system -p '{"spec":{"type":"ClusterIP"}}'
问题 2: SSL 证书获取失败
症状: 访问 HTTPS 时证书错误
检查步骤:
# 1. 查看 Caddy 日志
sudo kubectl logs -n default -l app=caddy --tail=100
# 2. 确认域名解析正确
nslookup your-domain.com
# 3. 确认端口 80 可访问(Let's Encrypt 需要)
curl -I http://your-domain.com
常见原因:
- 域名未正确解析到服务器 IP
- 防火墙阻止 80/443 端口
- Let's Encrypt 速率限制(每周最多 5 次失败)
问题 3: 访问域名返回 404
症状: HTTPS 可访问,但返回 404
检查步骤:
# 1. 检查 Ingress 配置
sudo kubectl get ingress -n default
sudo kubectl describe ingress <ingress-name> -n default
# 2. 检查 Service
sudo kubectl get svc -n default
# 3. 检查 Pod 状态
sudo kubectl get pods -n default
# 4. 测试 Traefik 路由
sudo kubectl exec -n default deployment/caddy -- \
curl -H "Host: your-domain.com" http://traefik.kube-system.svc.cluster.local:80
解决方案:
- 确认 Ingress 的 host 和 service name 正确
- 确认 Service selector 匹配 Pod labels
- 确认 Pod 正在运行
问题 4: 证书自动续期失败
检查:
# 查看证书过期时间
echo | openssl s_client -connect your-domain.com:443 -servername your-domain.com 2>/dev/null | openssl x509 -noout -dates
# 查看 Caddy 日志中的续期信息
sudo kubectl logs -n default -l app=caddy | grep -i renew
解决方案:
- Caddy 会自动续期,通常无需手动干预
- 如果失败,检查域名解析和端口访问
- 必要时重启 Caddy:
sudo kubectl rollout restart deployment caddy -n default
高级配置
使用持久化存储保存证书
默认配置使用 emptyDir,Pod 重启后证书会丢失。生产环境建议使用持久化存储:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: caddy-data
namespace: default
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
# 在 Deployment 中使用 PVC
spec:
template:
spec:
volumes:
- name: data
persistentVolumeClaim:
claimName: caddy-data
配置 Caddy 日志级别
在 Caddyfile 中添加:
{
email your-email@example.com
log {
level DEBUG
}
}
配置自定义 TLS 选项
your-domain.com {
tls {
protocols tls1.2 tls1.3
ciphers TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
}
reverse_proxy traefik.kube-system.svc.cluster.local:80
}
配置 Traefik 中间件
为 Ingress 添加中间件(如重定向、认证等):
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: redirect-https
namespace: default
spec:
redirectScheme:
scheme: https
permanent: true
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
traefik.ingress.kubernetes.io/router.middlewares: default-redirect-https@kubernetescrd
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 80
安全建议
-
限制 K3s API 访问
# 仅允许本地访问 sudo kubectl config set-cluster default --server=https://127.0.0.1:6443 -
配置防火墙
# 仅开放必要端口 sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw allow 22/tcp sudo ufw enable -
定期更新
# 更新 K3s curl -sfL https://get.k3s.io | sudo sh - # 更新 Caddy sudo kubectl set image deployment/caddy caddy=caddy:latest -n default -
备份证书数据
# 如果使用 PVC,定期备份 sudo kubectl exec -n default deployment/caddy -- tar czf - /data > caddy-backup.tar.gz
性能优化
1. 增加 Caddy 副本数(可选)
sudo kubectl scale deployment caddy --replicas=2 -n default
注意: 使用 hostPort 时,每个节点只能运行一个副本。
2. 配置资源限制
spec:
template:
spec:
containers:
- name: caddy
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
3. 启用 HTTP/3
Caddy 默认启用 HTTP/3,确保 UDP 443 端口开放:
sudo ufw allow 443/udp
卸载
# 删除应用
sudo kubectl delete -f test-app.yaml
sudo kubectl delete -f test-ingress.yaml
# 删除 Caddy
sudo kubectl delete -f caddy-deployment.yaml
# 卸载 K3s
sudo /usr/local/bin/k3s-uninstall.sh
参考资源
总结
这个架构的优势:
✅ 自动化 SSL 管理 - Caddy 自动获取和续期证书 ✅ 灵活的路由 - Traefik 提供强大的 Ingress 功能 ✅ 简单部署 - 一键部署,无需手动配置证书 ✅ 高可用 - 支持多副本和负载均衡 ✅ 易于维护 - 声明式配置,版本控制友好
适用场景:
- 个人项目和小型应用
- 开发和测试环境
- 需要快速部署的场景
- 多域名多应用托管
文档版本: 1.0 最后更新: 2026-01-29 适用于: K3s v1.34+, Caddy v2.8+, Traefik v3.5+