背景
之前有在 docker 中部署 Traefik 来实现服务发现和 TLS证书自动申请的经历,k3s 中默认 Ingress 也是 Traefik,所以考虑在此基础上扩展而不是切换到其他的 Ingress 了。
基于此我们需要解决以下几个问题:
- 修改 Traefik默认配置
- 服务发现
默认配置修改
这里我们在看 k3s 官方文档有提到使用 HelmChartConfig 自定义打包组件, 需要我们通过traefik-config.yaml
配置 HelmChartConfig 来覆盖原有的配置,当前也可以直接修改kubectl -n kube-system edit cm traefik
该命令允许你在终端中编辑ConfigMap。
操作步骤如下:
-
创建持久卷(K3S 默认安装了本地存储服务,方便支持部署有状态的服务,可以使用
kubectl get storageclass
查看)yml# nano /var/lib/rancher/k3s/server/manifests/traefik-pv.yaml apiVersion: v1 kind: PersistentVolume metadata: name: traefik-pv labels: type: local spec: storageClassName: traefik-config capacity: storage: 10Gi accessModes: - ReadWriteOnce hostPath: path: "/home/k3s/data/traefik"
这里创建完成会自动应用配置,如果我们没有在此目录创建,需要手动应用配置
bashkubectl create -f /your-path/traefik-pv.yaml
应用完成后查看状态:
也可以直接在rancher中创建
-
新建
traefik-config.yaml
,这里我们使用 nano(不使用 vim似乎在 pve 中输入法影响 vim相关命令,具体未深入探究)以下配置开启 traefik 的 Dashboard,开启 TLS、启用数据持久化、接入Prometheus监控
bash# nano /var/lib/rancher/k3s/server/manifests/traefik-config.yaml apiVersion: helm.cattle.io/v1 kind: HelmChartConfig metadata: name: traefik namespace: kube-system spec: valuesContent: |- ports: traefik: port: 9000 expose: true exposedPort: 9000 websecure: tls: enabled: true certResolver: "le" additionalArguments: - "--entrypoints.websecure.http.tls.domains[0].main=ipc.xxx.com" - "--entrypoints.websecure.http.tls.domains[0].sans=*.ipc.xxx.com" - "--certificatesresolvers.le.acme.email=xxx@qq.com" - "--certificatesresolvers.le.acme.storage=/data/acme.json" - "--certificatesresolvers.le.acme.dnschallenge=true" - "--certificatesresolvers.le.acme.dnschallenge.provider=dnspod" # link: https://doc.traefik.io/traefik/https/acme/#providers - "--certificatesresolvers.le.acme.dnschallenge.delaybeforecheck=0" - "--certificatesresolvers.le.acme.dnschallenge.resolvers=f1g1ns1.dnspod.net,f1g1ns2.dnspod.net,steam.dnspod.net,athena.dnspod.net" persistence: enabled: true name: data accessMode: ReadWriteOnce storageClass: "traefik-config" path: /data metrics: expose: true env: - name: "DNSPOD_API_KEY" value: "id,key" - name: "DNSPOD_HTTP_TIMEOUT" value: "150" - name: "DNSPOD_POLLING_INTERVAL" value: "5" - name: "DNSPOD_PROPAGATION_TIMEOUT" value: "300" # logs: # general: # level: DEBUG
-
保存后K3s 将通过**
helm-install-traefik
**来更新 Pod -
错误解决
如果遇到
helm-install-rraefik-xx
的 STATUS 状态不是 Completed,比如这里遇到过状态为 CrashLoopBackOff,具体原因是因为手动指定了ymlimage: name: traefik tag: v2.10.4
Pod无法找到这个版本的资源,需要我们手动拉取镜像或者去除此配置,使用默认版本即可
-
如果已经存在之前版本可以使用kubectl删除相关配置
bashkubectl delete -f /var/lib/rancher/k3s/server/manifests/traefik-config.yam systemctl daemon-reload systemctl restart k3s
服务发现
这里我们使用一个模板来测试 Ingress 是否能够正常进行服务发现
bash
kubectl apply -f https://k8s.io/examples/service/load-balancer-example.yaml
并且开启外部访问
bash
kubectl expose deployment hello-world --type=LoadBalancer --name=hl
然后我们就可以在 rancher 的服务发现里面看到我们暴露出的Service

创建对应的Ingress绑定到对应的服务

创建完成后访问 http://h1.xx.com
就可以看到测试页面

但是的但是,我发现无论如果配置都没法直接启用 TLS
证书自动申请,在 traefik Dashboard
中查看 TLS 状态也是正常

暂时没有找到解决方案,只能转而采用配置ClusterIssuer
的方案,这里我们创建cluster-issuer-letsencrypt.yaml
yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
namespace: cert-manager
name: letsencrypt
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: your@qq.com
privateKeySecretRef:
name: letsencrypt
solvers:
- http01:
ingress:
class: traefik
使用kubectl apply -f cluster-issuer-letsencrypt.yaml
部署,使用kubectl describe clusterissuer letsencrypt
查看状态。
修改Ingress配置如下:
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test
namespace: test
annotations:
kubernetes.io/ingress.class: 'traefik' # 在创建 Issuer 资源的时候有配置 ingress.class,需要保持一致
cert-manager.io/cluster-issuer: letsencrypt # 指定 cert-manager 的 Issuer 的名字
kubernetes.io/tls-acme: 'true' # 可选
ingress.kubernetes.io/ssl-redirect: "true" # 强制从 HTTP 重定向 HTTPS
spec:
rules:
- host: h2.xx.xxx.com # 此 Ingress 资源识别的 域名
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: hl
port:
number: 8080
# routes:
# - match: Host(`h2.xx.xxx.com`)
# kind: Rule
# services:
# - name: hl
# port: 8080
tls: # [12]
- secretName: h1-secret # [13]
hosts:
- h2.xx.xxx.com
# certResolver: le # [17]
# domains: # [18]
# - main: h2.xx.xxx.com
如果中间碰到问题可以使用以下两个命令来排查
bash
# 查看状态
kubectl get certificate -A
kubectl get ingress -n test
# 查看具体出错原因
kubectl describe certificate -A
kubectl describe certificate -n hoteler-namespace
再次访问你的域名,查看证书应该为有效状态

这里给一个完整的应用部署配置:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
labels:
app: demo-nginx
spec:
selector:
matchLabels:
app: demo-nginx
replicas: 1
template:
metadata:
labels:
app: demo-nginx
spec:
containers:
- image: nginx
name: demo-nginx
ports:
- containerPort: 80
name: 'demo-nginx'
protocol: 'TCP'
---
apiVersion: v1
kind: Service
metadata:
name: demo-nginx
namespace: default
labels:
app: demo-nginx
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
selector:
app: demo-nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-nginx
annotations:
kubernetes.io/ingress.class: 'traefik'
cert-manager.io/cluster-issuer: letsencrypt
kubernetes.io/tls-acme: 'true'
ingress.kubernetes.io/ssl-redirect: "true"
spec:
rules:
- host: ng.xx.xxx.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo-nginx
port:
number: 80
tls: # [12]
- secretName: ng-secret # [13]
hosts:
- ng.xx.xxx.com