资讯动态

k3s必备:Traefik 2.x入口配置实战与踩坑指南

发布时间:2026/10/14 15:59:17 来源:尧图企业网站定制
1. 为什么我最终把k3s的入口方案定在了Traefik 2.x先交代一下背景。我之前维护的一套集群最开始用的是k3s默认带的那套Traefik 1.x当时图省事装完k3s直接用确实也没出什么大乱子。但等到服务数量上来之后问题就暴露得很明显IngressRoute这个CRD虽然好用可1.x版本的配置模型太死板中间件Middleware要单独装插件版本升级还容易断档。最让我头疼的是团队里新来的同事总是分不清“我改了Ingress规则之后到底要不要重启Traefik”甚至出现过改完配置忘了apply、线上流量全打到旧后端的情况。后来我把集群整体升级到k3s较新版本默认自带的已经是Traefik 2.x而2.x和1.x完全是两个物种。说不夸张一点2.x把我之前很多“靠习惯硬撑”的地方全部重构成了声明式配置最直观的变化就是路由规则从Ingress注解风格全面转向IngressRouteCRD虽然k3s也保留了传统Ingress兼容但官方主推的玩法明显是CRD中间件Middleware变成一等公民可以像搭积木一样串联在路由上端口、TLS、重定向、流量复制等能力全部拆成了独立CRD对象不再靠乱七八糟的注解堆砌。这篇文章不是我第一次接触Traefik的笔记而是我在k3s上从1.x迁到2.x、再逐步完善的一套完整实操记录。全程都是用“最终能跑通”的角度来写的适合刚接触k3s的人也适合那些跟我一样在旧版本上踩过坑、想一次性把入口方案理顺的人。先给你吃一颗定心丸只要k3s装好、Traefik是2.x下面这套Step by Step基本不会翻车。我会先讲清楚2.x在k3s上到底以什么样的形态存在再带你从零到一部署一个示例服务、编写IngressRoute、挂中间件、配HTTPS最后讲几个我在生产环境里踩过的坑和解决办法。2. k3s里的Traefik 2.x到底是什么形态先把它看清楚2.1 k3s的默认Traefik和社区版Traefik其实不完全一样很多人一听到“k3s内置Traefik”就以为它跟Docker镜像里的traefik:2.x完全一致。事实上k3s的Traefik是以Helm Chart方式内置打包的它封装了Traefik自身的镜像、默认配置、RBAC规则以及一些k3s自定义的兼容逻辑。用一句话概括你看到的是Traefik但指挥Traefik的很多默认参数是由k3s提前定死的。比如默认端口绑定了80和443并且通过Service暴露到宿主机上默认支持Ingress和IngressRoute两种资源类型默认带了一个Traefik的Deployment而不是DaemonSet除非你手动改默认的values.yaml是k3s维护的和社区Helm Chart的默认值有细微差别。这意味着你单独用Helm去装社区版Traefik、再手动改成一个类似k3s内置的配置是可以的但没必要。k3s内置版本能覆盖绝大多数场景而且升级k3s时会跟着一起升级省心。我建议你做的第一件事不是去改配置而是先看一下当前集群里的Traefik到底是什么状态。执行命令kubectl get pods -n kube-system | grep traefik kubectl get svc -n kube-system traefik正常情况下你会看到一个traefik-xxxxx-xxxxx的Pod以及一个ClusterIP或LoadBalancer类型的Service。如果你用的是k3s默认安装这个Service通常长这样NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE traefik LoadBalancer 10.43.x.x pending 80:30080/TCP,443:30443/TCP 7d这里的80:30080/TCP意思是Traefik的80端口被映射到了宿主机上的30080端口。也就是说你访问宿主机IP的30080端口流量会进入Traefik的80入口。这个映射关系很重要后面排查“为什么我访问不到”的时候十有八九跟它有关。2.2 理解Traefik 2.x的三个核心概念Provider、Router、Middleware在动手配置之前我先把2.x的核心模型给你讲明白。很多人一开始看文档会被EntryPoints、Routers、Services、Middlewares搞得晕头转向其实它们的逻辑非常简单EntryPointsTraefik监听哪些端口比如web80、websecure443。相当于“门口”。Routers根据请求的域名、路径等规则把流量路由到后端的某个Service。相当于“门卫”。Middleware在Router和后端Service之间拦截请求做认证、限流、改写路径、加Header等操作。相当于“安检员”。ServicesTraefik后端要负载均衡的目标通常对应k8s里的Service。你可以把它们理解成一条流水线请求进来 → EntryPoints → Router匹配 → Middleware加工 → Service转发。下面是一个最朴素的IngressRoute示例apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: demo-ingressroute namespace: default spec: entryPoints: - web routes: - kind: Rule match: Host(demo.example.com) services: - name: demo-service port: 80这个YAML的意思是当请求的域名是demo.example.com时Traefik把流量转发到default命名空间里的demo-service的80端口。注意entryPoints里写的是web对应的是Traefik的80端口入口。对比你可能会更熟悉的传统IngressapiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: demo-ingress annotations: traefik.ingress.kubernetes.io/router.entrypoints: web spec: rules: - host: demo.example.com http: paths: - path: / pathType: Prefix backend: service: name: demo-service port: number: 80说实话传统Ingress在简单场景下也没问题但你的路由一旦变复杂——比如多域名、多路径、中间件串联注解风格会变得很痛苦。这也是我强烈建议你用IngressRouteCRD的原因它把路由描述从“注解字符串”变成了“结构化对象”可读性和可维护性都上了好几个档次。2.3 先确认你的k3s里Traefik是不是2.x如果你是从老版本k3s升上来的可能会遇到“我以为我是2.x结果还是1.x”的情况。判断方法很简单kubectl -n kube-system get pods -l apptraefik -o jsonpath{.items[0].spec.containers[0].image}如果镜像名里带2.x那就是2.x如果还是1.7说明你的k3s版本太旧或者你之前手动改过镜像。我碰到过一种情况某公司内部有镜像仓库运维把所有镜像统一打了个旧标签结果k3s升级之后Traefik还是1.7直到排查到镜像Tag才发现。如果你的k3s确实还停留在1.x我建议优先升级k3s本身而不是单独替换Traefik镜像。因为Traefik 1.x和2.x的CRD完全不兼容你在2.x里写的IngressRoute在1.x里根本不认。3. 实战部署从零到一跑通一个示例服务3.1 部署一个演示用的后端服务Traefik本身只是一个流量入口它必须要有后端服务可以转发。我们先用一个简单的echoserver来当“小白鼠”这个镜像是用来回显请求信息的非常适合验证路由、中间件、HTTPS是否生效。创建一个Deployment和ServiceapiVersion: apps/v1 kind: Deployment metadata: name: demo-app namespace: default spec: replicas: 2 selector: matchLabels: app: demo-app template: metadata: labels: app: demo-app spec: containers: - name: demo-app image: k8s.gcr.io/echoserver:1.10 ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: demo-service namespace: default spec: selector: app: demo-app ports: - port: 80 targetPort: 8080这里我把Service的port设为80、targetPort设为8080是因为Traefik在IngressRoute里默认转发的端口通常是80避免端口混乱。Echoserver镜像会在8080端口监听HTTP请求。启动之后先用kubectl get pods确认Pod处于Running状态再用一条临时Pod测试Service是否正常kubectl run test-curl --rm -it --imagecurlimages/curl --restartNever -- curl http://demo-service.default.svc.cluster.local如果能看到echoserver返回的请求信息说明后端服务没问题。这个“先验证后端”的习惯我强烈建议你保留Traefik配置出问题的时候如果你能确认后端是好的排查范围直接就缩小了一半。3.2 创建最简单的IngressRoute连通公网入口后端就绪后我们来创建第一个IngressRoute。假设你有一个测试域名demo.local没有真实域名没关系后面用curl --resolve来模拟规则为Host(\demo.local)apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: demo-ingressroute namespace: default spec: entryPoints: - web routes: - kind: Rule match: Host(demo.local) services: - name: demo-service port: 80执行kubectl apply -f demo-ingressroute.yaml然后怎么验证如果你在k3s宿主机上可以直接curl -H Host: demo.local http://127.0.0.1:30080如果你是从外面访问把127.0.0.1替换成宿主机IP。上面我们提到过Traefik的80端口被映射成了宿主机的30080所以这里必须带端口。如果你忘了端口直接访问http://宿主机IP大概率会请求超时。那如果你的域名是真实解析的比如demo.example.com已经解析到宿主机IP就可以用Host头直接访问curl http://demo.example.com:30080总而言之第一步的目标是只要Host头匹配就能拿到echoserver的响应。这一步通了后面的中间件、HTTPS都是锦上添花。3.3 用路径前缀区分多个服务避免每个服务都占一个域名实际生产里不可能一个服务一个域名更多时候是同一个域名下用不同路径区分不同应用。Traefik的Router匹配规则里Host和PathPrefix可以组合使用。比如我有个demo.local域名/app路径走demo-service/api路径走另一个api-serviceapiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: demo-multi-path namespace: default spec: entryPoints: - web routes: - kind: Rule match: Host(demo.local) PathPrefix(/app) services: - name: demo-service port: 80 - kind: Rule match: Host(demo.local) PathPrefix(/api) services: - name: api-service port: 80注意Traefik对多个路由的match顺序是按照在routes列表里的先后顺序进行匹配。所以如果你有/api和/api/v2这种前缀重叠的规则要把更具体的规则放在前面否则流量会被先匹配到的规则吃掉。我第一次用的时候就被这个坑过先写了PathPrefix(\/)的兜底规则再写了PathPrefix(/api)结果所有请求都走了兜底路由。后来把/api放在前面问题立刻解决。官方文档其实写得很清楚但人嘛不踩一次总记不住。还要提醒你一点PathPrefix匹配的是请求路径的前缀不是路径段。也就是说PathPrefix(\/app)会同时匹配/app、/application、/app/x。如果你只想精确匹配/app这个路径段需要写成PathPrefix(/app) !PathPrefix(/app/)或者干脆用Path(/app)。4. 中间件实战给流量加上限流、认证和路径改写4.1 为什么一定要用Middleware而不是在后端代码里做Traefik 2.x的中间件机制本质上就是把一些“流量治理”的通用能力从业务代码里剥离出来。以限流为例如果你有十个服务每个服务都要做限流傻乎乎在每个服务里写一套限流逻辑管理和维护成本都很高。而通过Traefik的RateLimit中间件你只需要在流量入口统一配置一次。我自己常用的中间件就三类RateLimit限流BasicAuth给内部工具加一层简单认证StripPrefix把请求路径里的某个前缀去掉后再转发给后端。这里我先演示一个最常用的组合BasicAuth RateLimit StripPrefix同时挂到一个路由上。4.2 用htpasswd生成认证信息创建BasicAuth中间件BasicAuth依赖htpasswd生成的哈希。如果你本地没有装apache2-utils这类工具也可以用容器执行docker run --rm httpd:2.4 htpasswd -nbB admin supersecret拿到类似admin:$2y$05$4FShp5XJXg...注意Traefik的BasicAuth从Secret里读取认证信息而Secret的要求是users这个key必须是一行一个“用户名:密码哈希”。所以在创建Secret的时候要先把这个哈希写到文件里echo admin:$2y$05$4FShp5XJXg... users.txt kubectl create secret generic demo-auth --from-fileusers.txt然后定义MiddlewareapiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: demo-auth namespace: default spec: basicAuth: secret: demo-auth这里有个关键点Middleware和IngressRoute最好在同一个命名空间。如果你要在别的命名空间引用它要么把Middleware放到对应命名空间要么用namespaceprovider这种跨命名空间引用语法。我在一开始没注意导致在另一个命名空间写路由时引用不到白白查了半天。4.3 RateLimit中间件的参数到底该怎么填Traefik 2.x的RateLimit是基于平均速率突发大小的令牌桶实现。具体配置里有两个核心参数average每秒平均请求数burst允许突发的请求数。比如我要限制每个客户端IP每秒最多10个请求、突发允许20个apiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: demo-ratelimit namespace: default spec: rateLimit: average: 10 burst: 20这个中间件默认是按客户端IP维度进行限流因为sourceCriterion默认策略就是ipStrategy。如果某些场景下你需要按Header维度限流比如按用户ID可以通过sourceCriterion.ipStrategy和requestHeaderName来配置。不过实际生产中按IP限流已经能满足绝大多数需求。4.4 StripPrefixPrefix中间件让后端不用关心路径前缀假设你的后端服务只处理/根路径但前端访问的路径是/api/v1/users。如果你直接把请求转发给后端后端看到的是/api/v1/users可能就404了。这时可以用StripPrefix中间件把前缀剥掉apiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: demo-stripprefix namespace: default spec: stripPrefix: prefixes: - /api - /v1注意prefixes是一个数组而且它是串行匹配的也就是说请求路径/api/v1/users会先剥掉/api再剥掉/v1最终变成/users。如果你只想剥一层那就只写一个。当时我在迁移一个老系统的时候后端服务用了两个不同的BasePath这个数组机制帮了大忙。4.5 把中间件挂到路由上看看中间件链怎么生效中间件创建好之后在IngressRoute的routes段落中通过middlewares字段引用apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: demo-ingressroute namespace: default spec: entryPoints: - web routes: - kind: Rule match: Host(demo.local) PathPrefix(/api) middlewares: - name: demo-auth - name: demo-ratelimit - name: demo-stripprefix services: - name: demo-service port: 80中间件在middlewares数组里的顺序就是它们的执行顺序。也就是说请求先经过demo-auth再经过demo-ratelimit最后经过demo-stripprefix然后才到后端Service。这里最重要的经验是中间件顺序不能乱写。一般来说认证应该在限流之前因为非法的请求没必要占限流额度而StripPrefix最好放在靠近后端的位置避免剥前缀后影响后续中间件对路径的判断。我之前试过把StripPrefix放在RateLimit前面结果限流规则的客户端IP识别没受影响但有个场景下路径改写影响了路由匹配调了很久才意识到是顺序问题。验证中间件链是否生效直接带认证信息访问curl -u admin:supersecret http://127.0.0.1:30080/api/v1/users如果返回正常说明BasicAuth生效如果连续快速请求超过阈值你会看到429 Too Many Requests说明RateLimit也生效如果后端收到的路径变成了/users说明StripPrefix也生效了。5. HTTPS配置从自签名证书到Lets Encrypt自动签发5.1 给Traefik配置TLS的通用流程Traefik 2.x支持两种HTTPS配置方式使用已有的TLS证书比如你从证书厂商买来的或者内部自签名使用Lets Encrypt自动签发和续期TLS证书全自动管理。无论哪种方式核心思路都是在Traefik的EntryPoint上启用websecure端口并配置证书的存储或动态加载。但k3s内置的Traefik默认参数里websecure入口是开放的你只要在IngressRoute里指定entryPoints: [websecure]再在routes下面加上tls配置即可。先看最简单的方式用已有证书。5.2 用已有证书配置TLS假如你已经有一个证书文件tls.crt和私钥文件tls.key先创建Secretkubectl create secret tls demo-tls --certtls.crt --keytls.key然后在IngressRoute里加上tls字段apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: demo-ingressroute-tls namespace: default spec: entryPoints: - websecure routes: - kind: Rule match: Host(demo.local) services: - name: demo-service port: 80 tls: secretName: demo-tls这里有一个细节tls字段是挂在IngressRoute的spec层级而不是routes里。如果你有多个域名需要不同证书可以写成:tls: options: name: my-tls-options certResolver: letsencrypt或者用secretName指定单个证书。如果你有多个路由共用同一个证书secretName直接放在spec.tls下就行。配置完成后如果Traefik的websecure入口被映射到了宿主机30443端口那么访问方式就是curl -k https://demo.local:30443-k参数是忽略自签名证书的警告。如果能看到echoserver的响应HTTPS就通了。5.3 使用Lets Encrypt自动签发证书k3s常见配置生产环境里我不建议手动管理证书文件因为证书有效期只有90天手工续期太痛苦。Traefik 2.x内置了ACME能力可以在values.yaml或动态配置里开启certResolver。k3s内置的Traefik想开启Lets Encrypt一般是在k3s启动时通过--kubelet-arg之类的参数修改Traefik的Helm values或者在/var/lib/rancher/k3s/server/manifests/traefik.yaml里改。不过直接改这个文件有一定风险因为k3s升级时会重置。更稳妥的方式是修改HelmChartConfig。k3s从某一版本开始支持通过HelmChartConfig来自定义内置Chart的values。我们可以创建一个HelmChartConfig:apiVersion: helm.cattle.io/v1 kind: HelmChartConfig metadata: name: traefik namespace: kube-system spec: valuesContent: |- additionalArguments: - --certificatesresolvers.letsencrypt.acme.emailyour-emailexample.com - --certificatesresolvers.letsencrypt.acme.storage/data/acme.json - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypointweb然后重启Traefik Pod让它重新加载配置。之后在IngressRoute里指定tls.certResolver: letsencryptapiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: demo-letsencrypt namespace: default spec: entryPoints: - web - websecure routes: - kind: Rule match: Host(demo.example.com) services: - name: demo-service port: 80 tls: certResolver: letsencrypt这个配置会让Traefik在收到HTTPS请求时自动向Lets Encrypt申请证书并续期。这里需要注意几个前提域名必须能正常解析到你的Traefik入口IP80端口必须能从公网访问因为默认使用HTTP-01挑战邮箱最好写真实可用邮箱用于接收证书过期提醒。我当时实际踩过一次坑域名解析没问题但k3s宿主机上80端口被防火墙挡了HTTP-01挑战一直失败页面一直提示证书签发超时。后来放开80端口后秒签成功。所以如果你用Lets Encrypt请第一时间检查80端口是否真的通。5.4 强制HTTP跳转HTTPS很多场景下你需要访问http://domain时自动跳转到https://domain。Traefik 2.x实现这个跳转不需要改后端服务只需要用一个RedirectScheme中间件apiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: redirect-https namespace: default spec: redirectScheme: scheme: https permanent: true然后把它挂到监听web的IngressRoute上apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: demo-http-to-https namespace: default spec: entryPoints: - web routes: - kind: Rule match: Host(demo.example.com) middlewares: - name: redirect-https services: - name: demo-service port: 80注意这里我依然写了services但实际流量会被中间件截获返回301跳转并不会真正到达后端。所以这个services其实随便写一个合法的就行但官方要求必须有所以别删。我见过有人想省事把中间件单独挂在一个没有services的路由上结果Traefik直接把这条路由报错了。6. k3s上Traefik的端口映射和Service对外暴露方式不再傻傻分不清6.1 为什么你访问30080而不是80很多刚用k3s的人都会困惑我明明在IngressRoute里写了entryPoints: [web]为什么访问宿主机80端口不行原因在于k3s的Traefik Service是NodePort或LoadBalancer类型它把Traefik容器的80端口映射成了宿主机的30080端口。这个端口范围默认是30000-32767是k8s的NodePort默认范围。所以你在kubectl get svc -n kube-system traefik里看到80:30080/TCP意思是容器端口80映射到宿主机端口30080。如果你不想看到这个“丑陋”的端口可以改Traefik Service类型为LoadBalancer然后借助云厂商负载均衡直接监听80。但在裸机或自建环境里LoadBalancer需要额外的负载均衡插件比如MetalLB否则EXTERNAL-IP会一直是pending。我自己的建议是测试环境用NodePort临时访问就行正式环境优先在Traefik前面加一个云LB或独立Nginx把80/443转发到节点的30080/30443如果集群是裸机可以装MetalLB把LoadBalancer类型的Service分配一个虚拟IP让Traefik直接占用80/443。6.2 直接暴露80端口给外网修改Service端口映射网上有个很粗暴但常见的做法就是把Traefik的Service改成“宿主机监听80端口”。如果你用的是k3s可以通过修改traefik这个Service的spec.ports[].nodePort来实现。但这样做有个隐患如果你一台宿主机上同时跑了多个需要占用80端口的服务端口就冲突了。更可靠的方案是在Traefik前面加一层宿主机Nginx代理。Nginx监听80/443反向代理到127.0.0.1:30080/30443。这样既保留Traefik的原生NodePort映射又让外部统一从标准端口进来。我实际生产环境用的就是这种结构排错也很清晰先看Nginx日志再看Traefik日志很快就能定位问题。6.3 如果外部访问还是不通按这个顺序排查这是我踩过无数次坑后总结出来的排查顺序先验证Traefik Pod是否Runningkubectl get pods -n kube-system -l apptraefik再验证Service的端口映射kubectl get svc -n kube-system traefik然后验证宿主机端口是否监听ss -lntp | grep 30080接着验证宿主机防火墙是否放行iptables -L -n | grep 30080或者ufw status最后用curl -H Host: demo.local http://127.0.0.1:30080测试如果还不行去看Traefik日志kubectl logs -n kube-system -l apptraefik大多数情况下问题出在宿主机防火墙没放行端口或者你访问的外部机器和k3s宿主机之间有安全组拦截。跟Traefik配置本身没太大关系。7. 踩坑实录从1.x迁移到2.x时我遇到的那些“坑中坑”7.1 CRD版本不兼容treafik.containo.us/v1alpha1和traefik.io/v1alpha1Traefik 2.x发展过程中CRD的API Group经历了一次变化。你的IngressRoute可能写的是apiVersion: traefik.containo.us/v1alpha1但有些新版本Traefik同时支持traefik.io/v1alpha1。如果你从网上复制了一段YAML却发现kubectl apply报“no matches for kind”先检查API Group是否一致。判断你当前集群支持哪些版本kubectl api-resources | grep ingressroute如果输出里出现traefik.containo.us/v1alpha1就继续用这个如果只有traefik.io/v1alpha1就把YAML里的apiVersion改掉。两种其实底层结构一样只是前缀不同。很多老教程还在用旧Group直接复制就会出现莫名奇妙的错误。7.2 Middleware跨命名空间引用时报错某个项目的服务在project-a命名空间但我想复用根命名空间里的demo-auth中间件于是一开始直接写了middlewares: - name: demo-auth结果kubectl apply通过但Traefik日志里一直报找不到中间件。后来查了文档才知道跨命名空间引用要用namespaceprovider格式middlewares: - name: defaultkubernetescrd看到没格式是中间件名字provider而provider是kubernetescrd。如果你不写providerTraefik默认只会在当前IngressRoute所在命名空间里找。这个设计本身合理但刚接触时确实容易懵。7.3 k3s升级后Traefik配置被重置有一段时间我升级k3s小版本升级完发现之前通过kubectl edit -n kube-system deploy traefik改过的启动参数全部被重置了。原因是k3s通过Helm管理Traefik直接改Deployment是“临时修改”下次Helm reconcile时会变回去。后来我学乖了所有自定义配置都通过HelmChartConfig来管理。你可以这样修改kubectl edit helmchartconfig traefik -n kube-system然后在valuesContent里写你想要追加的Traefik启动参数、镜像版本、资源限制等。改完保存后k3s会自动重新应用。这个方法最稳k3s升级也不会把你的配置冲掉。7.4 一个容易被忽略的细节entryPoints里的web和websecure到底代表什么Traefik自带两个默认EntryPointsweb是80端口websecure是443端口。如果你在k3s的Helm values里自定义了额外的entryPoints比如加了metrics或dashboard那你的IngressRoute里也可以引用它们。否则不要写一个不存在的entryPoint名字Traefik会直接拒绝加载整个路由。我自己曾经试图用entryPoints: [http]结果怀疑了半天是不是IngressRoute格式写错了最后才想到我写的entryPoint名字根本不存在。这属于低级别但极其隐蔽的错误排查起来很耗时间。所以写任何配置前先确认entryPoints名别拍脑袋。7.5 日志级别和访问日志排查问题最实用的两个开关Traefik默认日志不多出问题时经常一头雾水。你可以通过HelmChartConfig把访问日志打开并调整日志级别spec: valuesContent: |- logs: access: enabled: true general: level: DEBUG改完重启Traefik后你会看到大量“Route defined”和“Middlewares loaded”之类的信息。尤其是当IngressRoute加载异常时日志里会直接告诉你具体哪一段YAML有问题。这两个开关在排错时价值极高生产环境长期开着也行但要控制存储日志的容量。8. 进阶玩法把Dashboard安全地暴露出来但我劝你慎重8.1 Traefik Dashboard是个好东西但别裸奔Traefik自带一个Dashboard可以看到路由、Service、中间件等实时状态。但它非常危险如果暴露到公网又没有认证相当于把你的整个路由结构免费送人。所以我的建议是一定要加BasicAuth或者干脆只在内网访问。通过HelmChartConfig开启Dashboardspec: valuesContent: |- dashboard: enabled: true然后创建一个带认证的IngressRouteapiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: traefik-dashboard namespace: kube-system spec: entryPoints: - websecure routes: - kind: Rule match: Host(traefik.admin.local) middlewares: - name: dashboard-auth namespace: defaultkubernetescrd services: - name: traefik port: 9000 tls: certResolver: letsencrypt这里有个关键点Traefik Dashboard端口默认是9000但k3s内置的Traefik Service并没有把9000端口暴露出来。如果你要访问Dashboard需要在Service定义里加上9000端口的映射。这也是很多人开完Dashboard却访问不到的原因。8.2 如何把Service端口加回9000你可以在HelmChartConfig的valuesContent里指定Service端口配置或者在Traefik的Deployment、Service里追加端口。后者不推荐因为升级会被重置。在HelmChartConfig里可以这样spec: valuesContent: |- service: enabled: true ports: - name: web port: 80 targetPort: web - name: websecure port: 443 targetPort: websecure - name: dashboard port: 9000 targetPort: dashboard改完后kubectl get svc -n kube-system traefik应该能看到9000端口映射。之后再访问Dashboard就能在浏览器里看到图形界面了。不过说实话很多时候我并不会去看这个Dashboard因为kubectl describe ingressroute和Traefik日志已经足够排查问题。Dashboard更多是用来给团队里非技术同事看“服务入口是不是正常”的。如果你自己维护集群开不开无所谓别让安全风险变大就行。9. 基于实际经验的一份“最少必要配置”总结写了这么多最后我把自己认为“开箱即用”的一组配置放在这里。假设你有一个后端服务my-service部署在default命名空间端口为80想通过app.example.com对外提供HTTPS访问并且要求限流和BasicAuth。你需要创建的东西一共四个Secretmy-basic-authMiddlewaremy-authMiddlewaremy-ratelimitIngressRoutemy-routeSecrethtpasswd -nbB admin strongpasswordkubectl create secret generic my-basic-auth --from-fileusers.txtMiddleware YAMLapiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: my-auth namespace: default spec: basicAuth: secret: my-basic-auth --- apiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: my-ratelimit namespace: default spec: rateLimit: average: 100 burst: 200IngressRoute YAMLapiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: my-route namespace: default spec: entryPoints: - websecure routes: - kind: Rule match: Host(app.example.com) middlewares: - name: my-auth - name: my-ratelimit services: - name: my-service port: 80 tls: certResolver: letsencrypt只要你的域名的解析、宿主机端口映射和Lets Encrypt配置没问题这套东西直接就能跑。后续扩展新服务时照着这个模板改域名和Service名即可非常省事。10. 最后再分享两个我实际用着很舒服的小技巧第一个技巧修改IngressRoute后可以用kubectl wait等待Traefik完成配置加载而不是急着发请求。比如kubectl rollout status deployment/traefik -n kube-system --timeout60s如果你改的是configmap或HelmChartConfig等Deployment滚动完成后再发请求测试。否则你可能改完YAML立刻测试发现还是旧行为白白浪费几分钟。第二个技巧给IngressRoute打标签方便批量管理和排查。比如给所有生产环境的IngressRoute打上envproduction标签kubectl label ingressroute my-route envproduction然后你想看看生产环境总共有哪些路由一条命令就出来了kubectl get ingressroute -l envproduction -n default说实话这个习惯一开始觉得很“虚”但当你集群里路由越来越多靠文件夹管理YAML文件远不如靠标签管理实时资源来得高效。我把k3s上的Traefik从1.x迁到2.x之后最大的感触是很多原先需要绕路解决的问题在2.x里都变成了“声明一个对象”就能搞定的事。虽然中间件的顺序、CRD的apiGroup、端口映射这类细枝末节还会时不时冒出来绊你一下但只要你把核心模型——EntryPoints、Router、Middleware、Service——理解透彻绝大多数问题都能一眼看穿。希望这篇Step by Step的记录能帮你少走我之前走过的弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑