ingress与metallb 结合使用

ingress与metallb 结合使用

裸机(Bare Metal)Kubernetes 环境中,Ingress 需要 Ingress Controller(如 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)。

创建 metallb-config.yaml

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: first-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.1.100-192.168.1.110  # 这里改为你的可用 IP 段,注意,当ingress绑定一个IP后此IP不能再给其他ingress使用
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: first-advert
  namespace: metallb-system

应用配置:

kubectl apply -f metallb-config.yaml

2. 安装 Ingress Controller

(1) 使用 Helm 安装 Nginx Ingress

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install nginx-ingress ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespace

(2) 配置 Ingress Controller 使用 LoadBalancer

默认情况下,ingress-nginx 部署的 ServiceNodePort 类型,我们需要手动修改为 LoadBalancer 类型,让 Metallb 分配外部 IP。

kubectl patch svc ingress-nginx-controller -n ingress-nginx -p '{"spec":{"type":"LoadBalancer"}}'

然后检查 Ingress Controller Service 是否获得了 Metallb 分配的 IP:

kubectl get svc -n ingress-nginx

示例输出:

NAME                                         TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)
nginx-ingress-ingress-nginx-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. 部署应用 Service

创建 nginx-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: ClusterIP

应用该 YAML 文件

kubectl apply -f nginx-deployment.yaml

4. 创建 Ingress 规则

创建 nginx-ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: myapp.local # 这里按照子域名可以配置多个规则
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            # namespace: ns-app1  #目标命名空间,并根据namespace+svc的方式转发到不同的namespace中的service端口,此方法适用k8s的1.19之前的版本
            port:
              number: 80

应用该 YAML 文件

kubectl apply -f nginx-ingress.yaml

k8s 1.19之后的版本中要实现一个ingress通用可以使用如下方法

✅ 方法 1:使用 ExternalName Service

由于 Ingress 不能直接跨 Namespace 访问 Service,可以在 default 命名空间中 创建一个 ExternalName 类型的 Service,指向目标命名空间的 Service

步骤 1:在 default 命名空间创建 ExternalName Service

apiVersion: v1
kind: Service
metadata:
  name: app1-service
  namespace: default
spec:
  type: ExternalName
  externalName: app1-service.ns-app1.svc.cluster.local
  • 这里 externalName: app1-service.ns-app1.svc.cluster.local 让它指向 ns-app1 命名空间中的 app1-service

步骤 2:在 Ingress 中使用 default 里的 Service

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: subdomain-routing
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  ingressClassName: nginx
  rules:
    - host: "app1.example.com"
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app1-service  # 指向 default 里的 ExternalName Service
                port:
                  number: 80  # 原始服务的端口而不是ExternalName,在 Kubernetes ExternalName Service 的情况下,Service 本身不提供端口映射,而是直接解析为外部主机名

💡 这样 app1.example.com 访问时,会通过 ExternalName 方式路由到 ns-app1 里的 app1-service

✅ 方法 2:使用 NGINX server-snippet(实验性)

如果你使用的是 NGINX Ingress Controller,可以利用 nginx.ingress.kubernetes.io/server-snippet 注解,手动定义 NGINX 代理规则。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: subdomain-routing
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/server-snippet: |
      location / {
        proxy_pass http://app1-service.ns-app1.svc.cluster.local;
      }
spec:
  ingressClassName: nginx
  rules:
    - host: "app1.example.com"
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: dummy-service  # 需要一个 dummy service,否则 YAML 解析会报错
                port:
                  number: 80

⚠️ 注意

  • server-snippet 让 NGINX 直接代理流量到 app1-service.ns-app1.svc.cluster.local,绕过 Ingress 限制。
  • dummy-service 只是为了让 Ingress 资源能被 Kubernetes 解析,并不会实际生效。

总结

Ingress 不能 直接跨 Namespace 访问 Service不能使用 backend.service.namespace
方法 1(推荐):使用 ExternalName 类型的 Service 进行 跨命名空间代理
方法 2(实验性):使用 nginx.ingress.kubernetes.io/server-snippetIngress 直接代理请求


5. 测试访问

(1) 确保 Ingress 规则生效

kubectl get ingress

示例输出:

NAME            CLASS   HOSTS          ADDRESS        PORTS   AGE
nginx-ingress   nginx   myapp.local    192.168.1.100  80      10m
  • ADDRESS 应该是 Metallb 分配的 IP(如 192.168.1.100)。

(2) 修改 /etc/hosts

由于 Ingress 依赖 host 规则,浏览器访问时需要解析 myapp.local 到 Ingress 的 EXTERNAL-IP

sudo echo "192.168.1.100 myapp.local" >> /etc/hosts

(3) 访问应用

在浏览器访问:

http://myapp.local

应该能看到 Nginx 欢迎页面 🎉。


6. (可选) 启用 HTTPS

如果需要 HTTPS + TLS 证书,可以使用 cert-manager 自动签发证书,或者手动创建 TLS 证书:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - myapp.local
    secretName: myapp-tls
  rules:
  - host: myapp.local # 这里按照子域名可以配置多个规则
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            # namespace: ns-app1  #目标命名空间,并根据namespace+svc的方式转发到不同的namespace中的service端口,此方法适用k8s的1.19之前的版本
            port:
              number: 80

然后创建 myapp-tls 证书 Secret。

7.Ingress Annotations 介绍

在 Kubernetes v1.12.0Ingress 资源中,Annotations(注解)用于配置 Ingress Controller 的额外行为。
不同 Ingress Controller(如 NGINX、Traefik、HAProxy 等)支持的 Annotations 可能有所不同,这里主要介绍 NGINX Ingress Controller v1.12.0annotations 及其作用。

1. NGINX Ingress Controller v1.12.0 常用 Annotations

以下是 Ingress常用 Annotations 及其功能:

1.1 基本路由配置

Annotation 作用
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/fooexample.com/

1.2 负载均衡 & 代理设置

Annotation 作用
nginx.ingress.kubernetes.io/load-balance 负载均衡策略(round_robinleast_connip_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 认证 & 安全

Annotation 作用
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 配置

Annotation 作用
nginx.ingress.kubernetes.io/ssl-redirect 启用 HTTPS (true/false)
nginx.ingress.kubernetes.io/ssl-passthrough 直接透传 TLS,适用于 gRPCTLS 终结
nginx.ingress.kubernetes.io/backend-protocol 后端协议(HTTPHTTPSGRPCGRPCS
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 连接 & 限流

Annotation 作用
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. 如何查看所有支持的 Annotations?

可以运行以下命令,检查 nginx-ingress-controller 的默认 Annotations:

kubectl describe pod -n ingress-nginx | grep ANNOTATION

或者查看 NGINX Ingress Controller 官方文档:

  • 最新 NGINX Annotations

3. 总结

nginx.ingress.kubernetes.io/rewrite-targetURL 重写
nginx.ingress.kubernetes.io/proxy-body-size请求体大小限制
nginx.ingress.kubernetes.io/auth-typeBasic 认证
nginx.ingress.kubernetes.io/ssl-redirect强制 HTTPS
nginx.ingress.kubernetes.io/whitelist-source-rangeIP 访问控制
nginx.ingress.kubernetes.io/limit-rps限流

这些 Annotations 可以帮助你灵活控制 Ingress 行为,让 Kubernetes 反向代理更安全高效! 🚀


总结

  1. 安装 Metallb,提供外部 LoadBalancer IP。
  2. 安装 Ingress Controller(如 Nginx Ingress)。
  3. 确保 Ingress Controller 使用 LoadBalancer 类型,让 Metallb 分配 IP。
  4. 部署应用 Service,确保应用可以被 Ingress 访问。
  5. 创建 Ingress 规则,使用 host 规则管理 HTTP 流量。
  6. 测试 Ingress 访问,通过 Metallb 分配的 IP 访问服务。

最终效果

  • http://myapp.local 会被 Ingress 解析,并转发到 nginx-service
  • Metallb 分配的 192.168.1.100 作为对外的 Ingress 入口。
posted @ 2025-03-10 10:18  蒲公英PGY  阅读(364)  评论(0)    收藏  举报