33.9. 将服务配置为使用 MetalLB

作为集群管理员,当添加类型为 LoadBalancer 的服务时,您可以控制 MetalLB 如何分配 IP 地址。

33.9.1. 请求特定 IP 地址

与其他一些负载均衡器实施一样,MetalLB 接受服务规格中的 spec.loadBalancerIP 字段。

如果请求的 IP 地址位于任何地址池中,MetalLB 会分配请求的 IP 地址。如果请求的 IP 地址不在任何范围内,MetalLB 会报告警告。

特定 IP 地址的服务 YAML 示例

apiVersion: v1
kind: Service
metadata:
  name: <service_name>
  annotations:
    metallb.universe.tf/address-pool: <address_pool_name>
spec:
  selector:
    <label_key>: <label_value>
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
  type: LoadBalancer
  loadBalancerIP: <ip_address>

如果 MetalLB 无法分配请求的 IP 地址,服务报告的 EXTERNAL-IP 会报告 <pending>,运行 oc describe service <service_name> 会包括一个类似以下示例的事件。

当 MetalLB 无法分配请求的 IP 地址时的示例

  ...
Events:
  Type     Reason            Age    From                Message
  ----     ------            ----   ----                -------
  Warning  AllocationFailed  3m16s  metallb-controller  Failed to allocate IP for "default/invalid-request": "4.3.2.1" is not allowed in config

33.9.2. 从特定池中请求 IP 地址

要从特定范围分配 IP 地址,但您不关注特定的 IP 地址,您可以使用 metallb.universe.tf/address-pool 注解从指定地址池中请求 IP 地址。

来自特定池的 IP 地址的服务 YAML 示例

apiVersion: v1
kind: Service
metadata:
  name: <service_name>
  annotations:
    metallb.universe.tf/address-pool: <address_pool_name>
spec:
  selector:
    <label_key>: <label_value>
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
  type: LoadBalancer

如果您为 <address_pool_name> 指定的地址池不存在,MetalLB 会尝试从允许自动分配的池中分配 IP 地址。

33.9.3. 接受任何 IP 地址

默认情况下,地址池配置为允许自动分配。MetalLB 从这些地址池中分配 IP 地址。

若要接受任何为自动分配配置的池的 IP 地址,不需要特殊注释或配置。

接受任何 IP 地址的服务 YAML 示例

apiVersion: v1
kind: Service
metadata:
  name: <service_name>
spec:
  selector:
    <label_key>: <label_value>
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
  type: LoadBalancer

33.9.4. 共享特定 IP 地址

默认情况下,服务不共享 IP 地址。但是,如果您需要在单个 IP 地址上并置服务,可以通过向服务添加 metallb.universe.tf/allow-shared-ip 注解来启用选择性 IP 共享。

apiVersion: v1
kind: Service
metadata:
  name: service-http
  annotations:
    metallb.universe.tf/address-pool: doc-example
    metallb.universe.tf/allow-shared-ip: "web-server-svc"  1
spec:
  ports:
    - name: http
      port: 80  2
      protocol: TCP
      targetPort: 8080
  selector:
    <label_key>: <label_value>  3
  type: LoadBalancer
  loadBalancerIP: 172.31.249.7  4
---
apiVersion: v1
kind: Service
metadata:
  name: service-https
  annotations:
    metallb.universe.tf/address-pool: doc-example
    metallb.universe.tf/allow-shared-ip: "web-server-svc"  5
spec:
  ports:
    - name: https
      port: 443  6
      protocol: TCP
      targetPort: 8080
  selector:
    <label_key>: <label_value>  7
  type: LoadBalancer
  loadBalancerIP: 172.31.249.7  8
1 5
metallb.universe.tf/allow-shared-ip 注解指定相同的值。这个值被称为 共享键
2 6
为服务指定不同的端口号。
3 7
如果您必须指定 externalTrafficPolicy: local,以便服务将流量发送到同一组 pod,则指定相同的 pod 选择器。如果您使用 cluster 外部流量策略,则 pod 选择器不需要相同。
4 8
可选:如果您指定了上述三个项目,MetalLB 可能会将服务在同一 IP 地址上并置。若要确保服务共享 IP 地址,请指定要共享的 IP 地址。

默认情况下,Kubernetes 不允许多协议负载均衡器服务。此限制通常会导致无法运行需要同时侦听 TCP 和 UDP 的服务(如 DNS)。要解决 Kubernetes 使用 MetalLB 的这一限制,请创建两个服务:

  • 对于一个服务,请为第二个服务指定 TCP 和 指定 UDP。
  • 在两个服务中,指定相同的 pod 选择器。
  • 指定相同的共享密钥和 spec.loadBalancerIP 值,以将 TCP 和 UDP 服务在同一 IP 地址上并置。

33.9.5. 使用 MetalLB 配置服务

您可以将负载平衡服务配置为使用地址池中的外部 IP 地址。

先决条件

  • 安装 OpenShift CLI (oc) 。
  • 安装 MetalLB Operator 并启动 MetalLB。
  • 至少配置一个地址池。
  • 配置网络,将流量从客户端路由到集群的主机网络。

流程

  1. 创建一个 <service_name>.yaml 文件。在文件中,确保将 spec.type 字段设置为 LoadBalancer

    有关如何请求 MetalLB 分配给服务的外部 IP 地址的信息,请参考示例。

  2. 创建服务:

    $ oc apply -f <service_name>.yaml

    输出示例

    service/<service_name> created

验证

  • 描述该服务:

    $ oc describe service <service_name>

    输出示例

    Name:                     <service_name>
    Namespace:                default
    Labels:                   <none>
    Annotations:              metallb.universe.tf/address-pool: doc-example  <.>
    Selector:                 app=service_name
    Type:                     LoadBalancer  <.>
    IP Family Policy:         SingleStack
    IP Families:              IPv4
    IP:                       10.105.237.254
    IPs:                      10.105.237.254
    LoadBalancer Ingress:     192.168.100.5  <.>
    Port:                     <unset>  80/TCP
    TargetPort:               8080/TCP
    NodePort:                 <unset>  30550/TCP
    Endpoints:                10.244.0.50:8080
    Session Affinity:         None
    External Traffic Policy:  Cluster
    Events:  <.>
      Type    Reason        Age                From             Message
      ----    ------        ----               ----             -------
      Normal  nodeAssigned  32m (x2 over 32m)  metallb-speaker  announcing from node "<node_name>"

    <.> 注解存在,如果您从特定池请求 IP 地址。<.> 服务类型必须指示 LoadBalancer。<.> 如果服务被正确分配,则 load-balancer ingress 字段指示外部 IP 地址。<.> events 字段表示分配给声明外部 IP 地址的节点名称。如果出现错误,Event 字段会指示错误的原因。