# k3s traefik 反向代理到 ssh * 他可以代理 http 以外的同訊協定,像是 ssh 22、mysql 3306 等通訊協定 ## PreRequest - [x] 已完成安裝 k3s - [x] 已完成安裝 traefik - [x] 已部屬 ssh server pod,可以[參考](https://hackmd.io/@7vxmAdNPTmmlYGSRMuvbmw/BJ_bLunja) ## 設定 traefik * 更新 `HelmChartConfig` 新增對外 ssh 22100 port ``` $ cat <<EOF | kubectl apply -f - apiVersion: helm.cattle.io/v1 kind: HelmChartConfig metadata: name: traefik namespace: kube-system spec: valuesContent: |- ports: ssh: port: 22100 expose: true exposedPort: 22100 EOF ``` * 在 traefik svc 已額外新增 22100 port ``` $ kubectl -n kube-system get svc traefik NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE traefik LoadBalancer 10.43.202.115 192.168.11.83 22100:30589/TCP,80:30100/TCP,443:31652/TCP 20h ``` * 檢查 traefik deployment ``` $ kubectl -n kube-system get deploy traefik -o yaml ...... containers: - args: - --global.checknewversion - --global.sendanonymoususage - --entrypoints.metrics.address=:9100/tcp - --entrypoints.ssh.address=:22100/tcp ...... ports: - containerPort: 22100 name: ssh protocol: TCP ``` ## 檢查 ssh server pod ``` $ kubectl -n kube-system get po,svc NAME READY STATUS RESTARTS AGE pod/coredns-86cddbbd47-tndg8 1/1 Running 0 71m pod/jedi-7ff66999f7-m97fs 2/2 Running 0 103s pod/local-path-provisioner-67cd85979f-jdn8t 1/1 Running 0 71m pod/metrics-server-68cc98598d-ks8b7 1/1 Running 0 71m pod/svclb-traefik-8c03f295-zwbg8 3/3 Running 0 6m44s pod/traefik-b67f5b995-rmrxb 1/1 Running 0 6m44s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/jedi ClusterIP 10.43.0.11 <none> 5000/TCP,22100/TCP 103s service/kube-dns ClusterIP 10.43.0.10 <none> 53/UDP,53/TCP,9153/TCP 71m service/metrics-server ClusterIP 10.43.199.254 <none> 443/TCP 71m service/traefik LoadBalancer 10.43.166.141 192.168.11.83 22100:31321/TCP,80:31272/TCP,443:30170/TCP 70m ``` * 測試在叢集內使用 clusterIP login ``` # 帳號密碼皆是 bigred $ ssh bigred@10.43.0.11 -p 22100 Welcome to KAdmin Console ...... ``` ## 建立 IngressRouteTCP * 透過 `IngressRouteTCP` Traefik 會來管理 TCP 流量路由,並將 TCP 流量從一個入口點轉發到一個後端服務。 ``` # SNI 目的是通過在 TLS 握手過程中傳遞客戶端希望連接的主機名,使伺服器能夠選擇適當的證書來完成加密連接。 # 由於 SSH 沒有 HOST 的概念,因此需定義 HostSNI(`*`),任何的 SNI 都會被接受 。 $ echo 'apiVersion: traefik.io/v1alpha1 kind: IngressRouteTCP metadata: name: ssh namespace: kube-system spec: entryPoints: - ssh # 路由會監聽名為 ssh 的入口點。 routes: - match: HostSNI(`*`) # 表示匹配所有 SNI services: - namespace: kube-system # 服務所在 namespace name: jedi # 服務名稱以及服務開的 port port: 22100' | kubectl apply -f - ``` ``` $ kubectl -n kube-system get ingressroutetcps.traefik.io NAME AGE ssh 12s ``` ``` $ kubectl -n kube-system describe ingressroutetcps.traefik.io ssh Name: ssh Namespace: kube-system Labels: <none> Annotations: <none> API Version: traefik.io/v1alpha1 Kind: IngressRouteTCP Metadata: Creation Timestamp: 2024-07-15T05:33:06Z Generation: 1 Resource Version: 18175 UID: 8fb76813-6e7f-46fd-b004-63fac800e9cd Spec: Entry Points: ssh Routes: Match: HostSNI(`*`) Services: Name: jedi Namespace: kube-system Port: 22100 Events: <none> ``` ## 在外部機器使用 ssh 連到 pod ``` # 帳號密碼皆是 bigred $ ssh bigred@192.168.11.83 -p 22100 bigred@192.168.11.83's password: Welcome to KAdmin Console ...... ``` ## 參考文件 https://stackoverflow.com/questions/78261779/configuring-k3s-and-traefik-ingress-to-expose-tcp-port-for-ssh https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/