12 KiB
03-04-k3s Cloudflare Tunnel 配置接入
本文覆盖 Tunnel 完整流程:Zero Trust 云端创建、域名映射,以及将
cloudflared安装到 K3s 并跑起 Pod,使 Traefik 通过 Tunnel 对外提供服务。状态:已验证(2026-03,本仓库实验室 K3s 集群;详见
00-02-验证矩阵.md)。
访问链路(如何通过 Tunnel 访问 K3s 资源)
整体流程:公网域名 → Cloudflare Edge → Tunnel → cloudflared Pod → Traefik → 根据 Host/Path 路由到具体 Service(如 Dashboard、GitLab、Homer 等)。
Traefik 是唯一入口。所有流量经 Tunnel 进入后,由 Traefik 的 IngressRoute/Ingress 按 Host 和 Path 分发到不同后端。先保证 Traefik 内有对应路由(如 Dashboard 的 IngressRoute),再在 Zero Trust 中把域名指到 Traefik,即可访问。
前置条件
- 控制节点已就绪:
01-01-k3s-控制节点含traefik.md - Traefik 已可用;若要通过 Tunnel 访问 Dashboard,需先部署
03-01-k3s-traefik-dashboard.md或03-03-k3s-traefik-dashboard-acme.md - 域名已托管在 Cloudflare,且 Nameserver 已指向 Cloudflare
- 已创建 Cloudflare Zero Trust 账号
云端创建 Tunnel(Zero Trust 操作说明)
1. 创建 Tunnel
- 登录 Cloudflare Zero Trust Dashboard
- 左侧导航:Networks → Tunnels(或 Connectors → Cloudflare Tunnels)
- 点击 Create a tunnel
- 选择 Cloudflared 作为 Connector 类型
- 输入 Tunnel 名称(如
k3s-lab),点击 Save tunnel
2. 复制 Tunnel Token
- 在 Tunnel 创建成功后,会进入 Install connector 页面
- 选择操作系统(如 Linux)
- 在安装命令中,找到形如
cloudflared tunnel run --token <长串 Token>的 Token - 复制整个 Token(点击复制图标,或手动选中),妥善保存
- 该 Token 将用于下方 K3s 中
cloudflared部署
若已关闭页面:在 Tunnels 列表中点击该 Tunnel → Configure → Install connector,可重新查看/生成 Token。
3. 部署 cloudflared 到 K3s
- 从 唯一真源 复制清单:
ansible/files/cloudflare-tunnel/cloudflared.yaml - 将
TUNNEL_TOKEN占位符替换为前述 Zero Trust 中复制的 Token - 应用并等待 Pod 就绪(按实际 manifests 路径选择其一):
# 默认路径
kubectl apply -f /var/lib/rancher/k3s/server/manifests/cloudflared.yaml
kubectl -n kube-system rollout status deploy/cloudflared
# 自定义 data-dir(如 /storage)
kubectl apply -f /storage/server/manifests/cloudflared.yaml
kubectl -n kube-system rollout status deploy/cloudflared
- 将
cloudflared.yaml放入上述 manifests 目录后,K3s 重启时会自动加载。
建议要点:
- 使用官方
cloudflared镜像 - Secret 不写死在明文 YAML
cloudflared放在kube-system或专用 namespace- Tunnel 指向的 URL 在 Zero Trust 中配置为 Traefik Service,无需在
cloudflared.yaml内指定
集群内 Traefik 地址(Public Hostname 的 URL 填什么)
Tunnel 后端应指向 集群内的 Traefik 入口,常用写法:
| 写法 | 说明 |
|---|---|
traefik.kube-system.svc.cluster.local:80 |
见下「与哪份 YAML / 哪些字段对应」。不要手写 http://,Zero Trust 里选 HTTP 后只填主机与端口。 |
192.168.2.61 |
节点 IP(与 Traefik Service EXTERNAL-IP 之一、端口 80 等价)。Public Hostname 的 URL 只填到 IP/主机,path 在浏览器访问时带上(见步骤 6)。 |
和仓库里哪份 YAML 的关系
- 本仓库的
cloudflared.yaml只 定义cloudflared的 Deployment/Secret,不包含 Traefik Service;Tunnel 后端地址写的是 集群里已存在的 Traefik Service,不是cloudflared.yaml里的某一行。 - Traefik 的 Service 由 K3s 内置 Traefik(HelmChart)安装时创建,资源名一般为
traefik,命名空间kube-system。若你改过 chart 或 Service 名,以下 FQDN 与端口要以 实际kubectl get svc输出 为准。
与 kubectl get svc traefik -o yaml 里哪些字段对应
集群 DNS 完整名规则:<metadata.name>.<metadata.namespace>.svc.cluster.local:<spec.ports 中 web 的 port>。
| 你填的片段 | 对应 YAML 路径(kubectl -n kube-system get svc traefik -o yaml) |
|---|---|
traefik |
metadata.name |
kube-system |
metadata.namespace |
:80 |
spec.ports 里 name 常为 web 的 port: 80(HTTP 入口;若你环境 port 不是 80,Tunnel URL 里端口改成一致) |
示例(节选,以你集群为准):
metadata:
name: traefik # → FQDN 第一段
namespace: kube-system # → FQDN 第二段
spec:
ports:
- name: web
port: 80 # → Tunnel URL 里冒号后的端口
# ...
type: LoadBalancer # EXTERNAL-IP 为节点 IP 列表时,也可用 IP:80 代替集群 DNS
怎么用 kubectl 查(建议逐条执行)
# 1) 表格式:确认 NAME / PORT(S) / 集群 IP
kubectl -n kube-system get svc traefik -o wide
# 2) 打印集群 DNS 主机名(无端口)
kubectl -n kube-system get svc traefik -o jsonpath='{.metadata.name}.{.metadata.namespace}.svc.cluster.local'
echo
# 2b) 各端口名与端口(核对 HTTP 一般为 name=web、port=80)
kubectl -n kube-system get svc traefik -o jsonpath='{range .spec.ports[*]}{.name}={.port}{"\n"}{end}'
# 3) 导出完整 YAML,人工对照 metadata / spec.ports
kubectl -n kube-system get svc traefik -o yaml
HTTP 入口一般为 name=web 的 port: 80;若你环境端口名不是 web,以第 1、2、3 条里 实际 port 数字 为准,Tunnel URL 中冒号后改为该数字。
cloudflared 与 Traefik 同集群时,优先用 traefik.kube-system.svc.cluster.local:80,不依赖某台节点 IP 是否变更。
临时验证(集群内 curl)
官方 cloudflared 镜像多为 distroless、无 sh,不要用 kubectl exec deploy/cloudflared -- sh。
在 kube-system 起临时 Pod 探测 Traefik(与 Tunnel 后端同源):
# 根路径(常见 404,无默认路由时正常)
kubectl run curl-test --rm -n kube-system --restart=Never \
--image=curlimages/curl:latest -- \
curl -sS -o /dev/null -w "HTTP %{http_code}\n" \
http://traefik.kube-system.svc.cluster.local:80/
# Dashboard(已按 03-01/03-03 部署时期望 200)
kubectl run curl-test --rm -n kube-system --restart=Never \
--image=curlimages/curl:latest -- \
curl -sS -o /dev/null -w "HTTP %{http_code}\n" \
http://traefik.kube-system.svc.cluster.local:80/dashboard/
/→ 404:多数环境正常(未配置根路径路由)。/dashboard/→ 200:说明集群 DNS 与 Traefik 可达,Public Hostname 可填上述集群内地址。
4. 验证连接
kubectl -n kube-system get pods | grep cloudflared
kubectl -n kube-system logs deploy/cloudflared --tail=100
确认 Pod 为 Running,日志中可见 tunnel connected。只有 Connector 已连接后,才能进行下一步域名配置。
5. 配置域名映射(Public Hostnames / Route tunnel)
Zero Trust 向导顺序为:选择类型 → 命名 → 安装并运行 Connector → 路由流量。需等 Pod 跑起并显示已连接后,再配置 Public Hostnames。
- 在 Tunnel 配置页,切换到 Public Hostnames(已发布应用程序)标签,点击 Add a public hostname
- 配置如下:
| 字段 | 填写说明 |
|---|---|
| Subdomain | 子域名(如 k3s、git、home),或留空表示根域 |
| Domain | 下拉选择已托管在 Cloudflare 的域名(如 jackadam.top) |
| Path | 留空表示全路径;或填正则如 ^/blog 做路径匹配 |
| Service type | 选择 HTTP(集群内 Traefik 为 HTTP,勿选 HTTPS) |
| URL | 仅填 traefik.kube-system.svc.cluster.local:80,不要加 http://(含义与核对见上文「集群内 Traefik 地址」) |
重要:URL 输入框会根据 Service type 自动加协议前缀。选 HTTP 时只需填
traefik.kube-system.svc.cluster.local:80;若手写http://会变成http://http://...,导致「服务 URL 无效」。
- 点击 Save hostname,按需重复添加其他子域,均指向同一内部地址。
示例:Subdomain k3s + Domain jackadam.top → 公网 k3s.jackadam.top 访问 Traefik;不同子域由 Traefik 的 IngressRoute 按 Host 分发。
6. 快速验证:以 Dashboard 为例
若已按 03-01 或 03-03 部署 Traefik Dashboard,按上述步骤 5 添加一条 Public Hostname。Traefik 无需修改。
Public Hostname 的 URL 只能写到「主机 + 端口」,不能写成
192.168.2.61/dashboard这类带 path 的地址;控制台也不支持在 URL 里做 path patch/转发。路径由浏览器访问时带上,由 Traefik 按路由匹配。
Dashboard 专用子域(示例)
| 字段 | 填写值 |
|---|---|
| Subdomain | dashboard |
| Domain | jackadam.top(或你的域名) |
| Path | 留空 |
| Service type | HTTP |
| URL | traefik.kube-system.svc.cluster.local:80 或 192.168.2.61(仅主机或集群 DNS,勿在 URL 里写 /dashboard) |
将 192.168.2.61 换成你的 Traefik 入口节点 IP(与 kubectl get svc traefik 中 EXTERNAL-IP 之一一致即可)。
访问时在域名后带上 path:浏览器打开 https://dashboard.jackadam.top/dashboard/(路径 /dashboard/ 由 Traefik 的 Dashboard IngressRoute 处理)。
其他用法:单域名 k3s.jackadam.top(URL 同样只填到 traefik...:80 或节点 IP),访问时带路径,如 https://k3s.jackadam.top/dashboard/;或为每个应用单独配子域。
架构说明
- 流量路径:公网 → Cloudflare Edge → Tunnel →
cloudflaredPod → Traefik Service → 各 IngressRoute 后端 - 配置要点:Public Hostname 的 URL 为
traefik.kube-system.svc.cluster.local:80(Service type 选 HTTP),cloudflared与 Traefik 同集群,可直接通过 Service 访问。
预期
- Pod 为
Running,日志中可见tunnel connected - 配置域名后,访问公网域名可到达 Traefik 路由
注意事项
- 没有 token/凭据:回到 Zero Trust 页面重新生成
- 顺序:先跑起 Pod 并确认连接,再配置 Public Hostnames;否则「路由流量」步骤无法生效
- URL 填写错误:Service type 选 HTTP,URL 只填
traefik.kube-system.svc.cluster.local:80,勿加http://
失败排查
- 域名解析正常但访问超时:先看 Tunnel 状态与
cloudflared日志 - 返回
404:通常是 Traefik 路由未命中 - 返回
502:优先排查后端链路(06-01-k3s-networkpolicy-故障排查.md)
下一步
- 其他应用(GitLab、Homer 等):在集群内创建 IngressRoute/Ingress 指定 Host 与后端,再在 Zero Trust 中添加对应子域的 Public Hostname 即可
05-03-k3s-安装gitlab-含runner.md05-01-k3s-部署homer首页面板.md