在私有网络中部署k8s,没有公网云中统一的GW,所以需要规范使用统一网关来进行业务发布。
整体架构
内网客户端 → MetalLB 分配固定内网 LBIP → Traefik 网关 → 业务 ClusterIP Service → Pod 业务全程只使用 ClusterIP,无 NodePort 暴露。
前置条件
- 裸机 / 虚拟机自建 K8s(无云厂商 LB)
- 一段内网空闲 IP 段(如
192.168.3.200-192.168.3.220,和集群同网段、未被 DHCP 占用) - 集群内核转发开启、防火墙放开 80/443 端口
- kubectl 正常连通集群
一、部署 MetalLB v0.15(L2 二层模式,内网首选)
步骤 1:
修改 kube-proxy 开启 strictARP(必做,否则 MetalLB ARP 异常)
kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e "s/strictARP: false/strictARP: true/" | kubectl apply -f -
# 重启kube-proxy生效
kubectl rollout restart daemonset kube-proxy -n kube-system
kubectl get daemonset kube-proxy -n kube-system
步骤 2:
一键部署 MetalLB 官方原生 yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.2/config/manifests/metallb-native.yaml
等待 Pod 全部 Running:
kubectl get pods -n metallb-system -w
预期 2 类 Pod:
- controller:1 个 Deployment
- speaker:每个节点 1 个 DaemonSet
步骤 3:
配置 IP 地址池 + L2 二层通告
新建文件 metallb-config.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: lan-lb-pool
namespace: metallb-system
spec:
addresses:
# 替换为你内网空闲IP段,不要和网关/服务器DHCP冲突
- 192.168.3.200-192.168.3.220
autoAssign: true
avoidBuggyIPs: true
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: lan-l2-advertise
namespace: metallb-system
spec:
ipAddressPools:
- lan-lb-pool
应用配置:
kubectl apply -f metallb-config.yaml
# 查看地址池
kubectl get IPAddressPool -n metallb-system
二、部署 Traefik v2.11(完整 RBAC+CRD+LoadBalancer Service)
步骤 1:
创建 traefik 命名空间
kubectl create ns traefik
步骤 2:
完整 Traefik 部署 yaml traefik-full.yaml
包含:ServiceAccount、ClusterRole、ClusterRoleBinding、Deployment、Service (LoadBalancer)、IngressRoute CRD
# 1. ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik
namespace: traefik
---
# 2. ClusterRole 权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: traefik-ingress-controller
rules:
- apiGroups: [""]
resources: ["services", "endpoints", "secrets"]
verbs: ["get", "list", "watch"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses", "ingressclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses/status"]
verbs: ["update"]
- apiGroups: ["traefik.containo.us"]
resources: ["ingressroutes", "ingressroutetcps", "middlewares", "tlsoptions"]
verbs: ["*"]
---
# 3. 绑定权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: traefik-ingress-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-ingress-controller
subjects:
- kind: ServiceAccount
name: traefik
namespace: traefik
---
# 4. Traefik Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: traefik
namespace: traefik
spec:
replicas: 2 # 高可用部署2副本
selector:
matchLabels:
app: traefik
template:
metadata:
labels:
app: traefik
spec:
serviceAccountName: traefik
containers:
- name: traefik
image: traefik:v2.11
args:
# 开启API面板
- --api.insecure=true
# 监听k8s标准Ingress
- --providers.kubernetesingress
# 监听Traefik自定义IngressRoute CRD
- --providers.kubernetescrd
# HTTP入口
- --entrypoints.web.address=:80
# HTTPS入口
- --entrypoints.websecure.address=:443
ports:
- name: web
containerPort: 80
- name: websecure
containerPort: 443
- name: dashboard
containerPort: 8080
---
# 5. 关键:LoadBalancer Service,由MetalLB分配内网固定IP
apiVersion: v1
kind: Service
metadata:
name: traefik-lb
namespace: traefik
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
name: web
- port: 443
targetPort: 443
name: websecure
selector:
app: traefik
步骤 3:应用 Traefik 全部资源
kubectl apply -f traefik-full.yaml
# 等待Pod就绪
kubectl get pods -n traefik -w
步骤 4:查看 Traefik 分配的内网 LB 固定 IP
kubectl get svc traefik-lb -n traefik
输出示例:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
traefik-lb LoadBalancer 10.100.120.100 192.168.3.200 80:30000/TCP,443:30001/TCP 2m
EXTERNAL-IP=192.168.3.200 就是内网统一网关入口 IP,全程不用 NodePort 访问业务。
三、配置 Traefik Dashboard(内网可视化面板)
新建 traefik-dashboard.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard
namespace: traefik
spec:
entryPoints:
- web
routes:
- match: Host(`traefik.lan`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))
kind: Rule
services:
- name: api@internal
kind: TraefikService
应用:
kubectl apply -f traefik-dashboard.yaml -n traefik
内网客户端配置 hosts:
192.168.3.200 traefik.lan
浏览器访问 http://traefik.lan/dashboard 打开 Traefik 管理面板。
四、部署测试业务(仅 ClusterIP,无 NodePort)
1. 业务 yaml demo-whoami.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami
spec:
replicas: 2
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: traefik/whoami
ports:
- containerPort: 80
---
# 仅ClusterIP,不使用NodePort
apiVersion: v1
kind: Service
metadata:
name: whoami-svc
spec:
selector:
app: whoami
ports:
- port: 80
targetPort: 80
type: ClusterIP
kubectl apply -f demo-whoami.yaml
2. Traefik 路由 IngressRoute
新建 whoami-route.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: whoami-web
namespace: default
spec:
entryPoints:
- web
routes:
- match: Host(`demo.lan`)
kind: Rule
services:
- name: whoami-svc
port: 80
kubectl apply -f whoami-route.yaml
五、内网客户端访问测试
- 客户端 hosts 添加解析(小规模内网方案)
192.168.3.200 demo.lan traefik.lan
- curl / 浏览器访问
curl http://demo.lan
流量路径:客户端 → MetalLB 固定 IP → Traefik 网关 → ClusterIP Service → Pod,无任何 NodePort 暴露业务。
六、常用排错命令
MetalLB 排查
# 查看地址池分配情况
kubectl describe IPAddressPool -n metallb-system lan-lb-pool
# 查看speaker日志(ARP分配IP日志)
kubectl logs -f daemonset/speaker -n metallb-system
# 查看controller日志
kubectl logs -f deployment/controller -n metallb-system
Traefik 排查
# Traefik容器日志
kubectl logs -f deployment/traefik -n traefik
# 查看IngressRoute路由规则
kubectl get IngressRoute
# 查看Traefik LB IP
kubectl get svc traefik-lb -n traefik
# 检查业务service是否正常
kubectl get svc whoami-svc
七、关键注意事项
- IP 段规划:MetalLB 地址池不能和 DHCP、服务器静态 IP 重叠,否则 IP 冲突;
- strictARP 必须开启,否则多节点 ARP 转发异常,访问时断时续;
- 业务 Service 统一
type: ClusterIP,禁止 NodePort; - 大规模内网:搭建内网 CoreDNS 统一解析域名,不用手动改 hosts;
- 高可用:Traefik 副本≥2,pod 反亲和分散到不同节点;
- 防火墙放开节点 80、443、7946(MetalLB speaker 通信端口)。
八、可选:Helm 一键安装 Traefik
如果你习惯 helm,替代上面 yaml 部署 Traefik:
helm repo add traefik https://traefik.github.io/charts
helm repo update
helm install traefik traefik/traefik -n traefik --create-namespace \
--set service.type=LoadBalancer \
--set ports.web.port=80 \
--set ports.websecure.port=443 \
--set dashboard.enabled=true \
--set dashboard.insecure=true
安装后同样通过kubectl get svc traefik -n traefik获取 MetalLB 分配的内网 LB IP。