Kubernetes裸机环境中Ingress与MetalLB集成实践
在裸机Kubernetes集群中集成Ingress与MetalLB
对于**裸机Kubernetes环境**,`Ingress` 组件需要配合 **Ingress控制器**(例如 `nginx-ingress`)工作。然而,裸机环境缺少云提供商的 `LoadBalancer` 支持,因此 **MetalLB** 能够为Ingress组件提供外部IP地址,实现外部网络访问能力。下面详细介绍 **Ingress与MetalLB集成** 的完整实施流程。
1. MetalLB部署配置
(1) MetalLB组件部署
采用官方发布的YAML资源文件进行部署:
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/main/config/manifests/metallb-native.yaml
监控MetalLB相关Pod的运行状态:
kubectl get pods -n metallb-system
(2) IP地址池配置
MetalLB需要预先定义**IP地址池**来分配外部IP(确保所选IP在当前网络环境中可达,比如 `192.168.1.100-192.168.1.200`)。
创建 `metal-lb-config.yaml` 配置文件:
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: primary-pool
namespace: metallb-system
spec:
addresses:
- 192.168.1.100-192.168.1.110 # 替换为实际可用的IP范围,注意Ingress绑定IP后该IP不可重复使用
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: primary-advertisement
namespace: metallb-system
应用配置资源:
kubectl apply -f metal-lb-config.yaml
2. Ingress控制器部署
(1) 采用Helm部署Nginx Ingress
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-controller ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespace
(2) 配置Ingress控制器使用LoadBalancer模式
默认情况下,`ingress-nginx` 部署的 `Service` 为 `NodePort` 类型,需手动调整为 `LoadBalancer` 类型,以便MetalLB分配外部IP。
kubectl patch svc ingress-controller -n ingress-nginx -p '{"spec":{"type":"LoadBalancer"}}'
检查Ingress控制器 `Service` 是否获取到MetalLB分配的IP地址:
kubectl get svc -n ingress-nginx
预期输出结果:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
ingress-controller LoadBalancer 10.100.200.1 192.168.1.100 80:30678/TCP,443:30679/TCP
- `EXTERNAL-IP` = `192.168.1.100` 表明MetalLB成功完成IP分配。
3. 应用服务部署
创建 `web-server-deployment.yaml`:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
labels:
app: web-app
spec:
replicas: 2
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-container
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: web-server-svc
spec:
selector:
app: web-app
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
应用资源配置
kubectl apply -f web-server-deployment.yaml
4. Ingress路由规则创建
创建 `web-server-ingress.yaml`:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-server-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: demo.app.local # 可基于子域名配置多条路由规则
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-server-svc
# namespace: target-ns # 目标命名空间,基于namespace+svc转发至不同命名空间的服务端口,适用于k8s 1.19以前版本
port:
number: 80
应用Ingress配置
kubectl apply -f web-server-ingress.yaml
在**k8s 1.19**以上版本中,若需实现Ingress通用访问,可采用以下方案
方案一:利用ExternalName Service
由于 `Ingress` 无法直接跨命名空间访问服务,可在 `default` 命名空间中 创建 `ExternalName` 类型的服务,指向目标命名空间的 `服务`。
步骤1:在 `default` 命名空间创建ExternalName服务
apiVersion: v1
kind: Service
metadata:
name: target-service
namespace: default
spec:
type: ExternalName
externalName: target-service.target-ns.svc.cluster.local
- 此处 `externalName: target-service.target-ns.svc.cluster.local` 指向 `target-ns` 命名空间中的 `target-service`。
步骤2:在 `Ingress` 中引用 `default` 命名空间的服务
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: domain-routing
namespace: default
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
ingressClassName: nginx
rules:
- host: "service1.example.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: target-service # 指向default命名空间的ExternalName服务
port:
number: 80 # 原始服务端口而非ExternalName端口,Kubernetes ExternalName服务不提供端口映射,直接解析为外部主机名
如此配置下,`service1.example.com` 访问将通过 `ExternalName` 方式路由至 `target-ns` 命名空间的 `target-service`!
方案二:使用NGINX `server-snippet`(实验特性)
若使用 **NGINX Ingress控制器**,可通过 `nginx.ingress.kubernetes.io/server-snippet` 注解,手动定义NGINX代理规则。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: domain-routing
namespace: default
annotations:
nginx.ingress.kubernetes.io/server-snippet: |
location / {
proxy_pass http://target-service.target-ns.svc.cluster.local;
}
spec:
ingressClassName: nginx
rules:
- host: "service1.example.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: placeholder-service # 需要占位服务,避免YAML解析错误
port:
number: 80
⚠️ 注意事项:
- `server-snippet` 让NGINX直接代理流量至 `target-service.target-ns.svc.cluster.local`,绕过 `Ingress` 限制。
- `placeholder-service` 仅为使 `Ingress` 资源被Kubernetes正确解析而存在,实际不起作用。
总结
- `Ingress` 无法 直接跨命名空间访问 `服务`,不可使用 `backend.service.namespace`
- ✅ 方案一(推荐):使用 `ExternalName` 类型的 `服务` 实现 跨命名空间代理
- ✅ 方案二(实验性):使用 `nginx.ingress.kubernetes.io/server-snippet` 让 `Ingress` 直接代理请求
5. 访问验证
(1) 确认Ingress规则生效
kubectl get ingress
预期输出:
NAME CLASS HOSTS ADDRESS PORTS AGE
web-server-ingress nginx demo.app.local 192.168.1.100 80 10m
- `ADDRESS` 应显示MetalLB分配的IP(如 `192.168.1.100`)。
(2) 修改 `/etc/hosts` 文件
由于Ingress依赖 `host` 规则,浏览器访问需将 `demo.app.local` 解析至Ingress的 `EXTERNAL-IP`:
sudo echo "192.168.1.100 demo.app.local" >> /etc/hosts
(3) 应用访问测试
在浏览器中访问:
http://demo.app.local
应能正常显示Nginx欢迎页面 🎉。
6. (可选) 启用HTTPS支持
若需 **HTTPS + TLS证书** 支持,可使用 `cert-manager` 自动颁发证书,或手动创建TLS证书:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-server-ingress
spec:
ingressClassName: nginx
tls:
- hosts:
- demo.app.local
secretName: demo-app-tls
rules:
- host: demo.app.local # 可按子域名配置多条规则
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-server-svc
# namespace: target-ns # 目标命名空间,基于namespace+svc转发至不同命名空间的服务端口,适用于k8s 1.19以前版本
port:
number: 80
随后创建 `demo-app-tls` 证书Secret。
7. Ingress注解功能详解
在Kubernetes **v1.12.0** 的 `Ingress` 资源中,注解(Annotations)用于配置 `Ingress控制器` 的扩展功能。
不同Ingress控制器(如NGINX、Traefik、HAProxy等)支持的注解可能有所差异,这里主要介绍 **NGINX Ingress控制器v1.12.0** 的 `注解` 及其功能。
1. NGINX Ingress控制器v1.12.0常用注解
以下是 `Ingress` 的 常用注解 及其功能说明:
1.1 基础路由配置
| 注解 | 功能说明 |
|---|---|
| `nginx.ingress.kubernetes.io/rewrite-target` | 重新定义请求路径(例如,将 `/foo` 重写为 `/`) |
| `nginx.ingress.kubernetes.io/use-regex` | 是否启用正则表达式路径匹配 (`true/false`) |
| `nginx.ingress.kubernetes.io/force-ssl-redirect` | 强制HTTP请求重定向至HTTPS (`true/false`) |
| `nginx.ingress.kubernetes.io/app-root` | 访问 `/` 时重定向至指定路径 |
| `nginx.ingress.kubernetes.io/configuration-snippet` | 允许插入自定义 `nginx.conf` 配置代码段 |
示例:URL路径重写
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
- `example.com/foo` → `example.com/`
1.2 负载均衡 & 代理配置
| 注解 | 功能说明 |
|---|---|
| `nginx.ingress.kubernetes.io/load-balance` | 负载均衡策略(`round_robin`、`least_conn`、`ip_hash`) |
| `nginx.ingress.kubernetes.io/proxy-body-size` | 设置 `client_max_body_size`,限制请求体大小(默认 `1m`) |
| `nginx.ingress.kubernetes.io/proxy-connect-timeout` | 代理连接超时时间(默认 `5s`) |
| `nginx.ingress.kubernetes.io/proxy-read-timeout` | 代理读取超时时间(默认 `60s`) |
| `nginx.ingress.kubernetes.io/proxy-send-timeout` | 代理发送超时时间(默认 `60s`) |
| `nginx.ingress.kubernetes.io/proxy-buffer-size` | 定义 `proxy_buffer_size` 大小,减少响应数据分片 |
| `nginx.ingress.kubernetes.io/proxy-buffering` | 启用/禁用 `proxy_buffering` (`on/off`) |
示例:限制请求大小
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
- 限制单个请求体大小为 10MB
1.3 认证 & 安全配置
| 注解 | 功能说明 |
|---|---|
| `nginx.ingress.kubernetes.io/auth-type` | 认证类型(`basic` / `digest`) |
| `nginx.ingress.kubernetes.io/auth-secret` | 存储认证信息的Secret名称 |
| `nginx.ingress.kubernetes.io/auth-realm` | 认证提示信息 |
| `nginx.ingress.kubernetes.io/enable-modsecurity` | 启用 `ModSecurity` (`true/false`) |
| `nginx.ingress.kubernetes.io/modsecurity-snippet` | 自定义 `ModSecurity` 规则 |
| `nginx.ingress.kubernetes.io/enable-owasp-modsecurity-crs` | 启用OWASP `ModSecurity` CRS规则 |
示例:启用 `Basic Auth`
annotations:
nginx.ingress.kubernetes.io/auth-type: "basic"
nginx.ingress.kubernetes.io/auth-secret: "auth-secret"
nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"
- 认证信息存储在 `auth-secret` 中
1.4 HTTPS & TLS配置
| 注解 | 功能说明 |
|---|---|
| `nginx.ingress.kubernetes.io/ssl-redirect` | 启用HTTPS (`true/false`) |
| `nginx.ingress.kubernetes.io/ssl-passthrough` | 直接透传TLS,适用于 `gRPC` 或 `TLS` 终结 |
| `nginx.ingress.kubernetes.io/backend-protocol` | 后端协议(`HTTP`、`HTTPS`、`GRPC`、`GRPCS`) |
| `nginx.ingress.kubernetes.io/hsts` | 启用 `HSTS` (`true/false`) |
| `nginx.ingress.kubernetes.io/hsts-max-age` | `HSTS` 最大生存周期(秒) |
| `nginx.ingress.kubernetes.io/hsts-include-subdomains` | `HSTS` 适用于子域名 (`true/false`) |
| `nginx.ingress.kubernetes.io/hsts-preload` | 启用 `HSTS Preload` (`true/false`) |
示例:强制HTTPS + 启用HSTS
annotations:
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/hsts: "true"
nginx.ingress.kubernetes.io/hsts-max-age: "31536000"
nginx.ingress.kubernetes.io/hsts-include-subdomains: "true"
nginx.ingress.kubernetes.io/hsts-preload: "true"
- 所有HTTP请求均 自动跳转至HTTPS
- 启用 HSTS,浏览器强制HTTPS访问
1.5 连接 & 限流配置
| 注解 | 功能说明 |
|---|---|
| `nginx.ingress.kubernetes.io/limit-rps` | 限制 每秒请求数 |
| `nginx.ingress.kubernetes.io/limit-burst` | 限制 突发请求数 |
| `nginx.ingress.kubernetes.io/limit-connections` | 限制 最大并发连接数 |
| `nginx.ingress.kubernetes.io/whitelist-source-range` | 允许访问的IP白名单(CIDR格式) |
示例:限流 & 仅允许特定IP访问
annotations:
nginx.ingress.kubernetes.io/limit-rps: "5"
nginx.ingress.kubernetes.io/whitelist-source-range: "192.168.1.0/24,10.0.0.0/8"
- 限制每个客户端 每秒最多5个请求
- 仅 192.168.1.0/24 和 10.0.0.0/8 网段 允许访问
2. 如何查看所有支持的注解?
可执行以下命令,检查 `nginx-ingress-controller` 的默认注解配置:
kubectl describe pod -n ingress-nginx | grep ANNOTATION
或查阅NGINX Ingress控制器官方文档:
- 最新NGINX注解文档
3. 总结
- `nginx.ingress.kubernetes.io/rewrite-target` → URL路径重写
- `nginx.ingress.kubernetes.io/proxy-body-size` → 请求体大小限制
- `nginx.ingress.kubernetes.io/auth-type` → 基础认证
- `nginx.ingress.kubernetes.io/ssl-redirect` → 强制HTTPS
- `nginx.ingress.kubernetes.io/whitelist-source-range` → IP访问控制
- `nginx.ingress.kubernetes.io/limit-rps` → 请求限流
这些注解 能够帮助您灵活控制 `Ingress` 行为,使Kubernetes反向代理更加安全高效!🚀
总结
- 部署MetalLB,提供外部LoadBalancer IP支持。
- 部署Ingress控制器(如Nginx Ingress)。
- 确保Ingress控制器使用 `LoadBalancer` 类型,使MetalLB能够分配IP。
- 部署应用服务,确保应用可被Ingress访问。
- 创建Ingress规则,使用 `host` 规则管理HTTP流量。
- 测试Ingress访问,通过MetalLB分配的IP访问服务。
最终效果
- `http://demo.app.local` 将被Ingress解析,并转发至 `web-server-svc`。
- MetalLB分配的 `192.168.1.100` 作为对外Ingress入口点。