documentation.suse.com / Documentação do SUSE Edge / Guias de procedimentos / MetalLB no K3s (usando o modo de camada 2)

25 MetalLB no K3s (usando o modo de camada 2)

O MetalLB é uma implementação de balanceador de carga para clusters Kubernetes bare metal, usando protocolos de roteamento padrão.

Neste guia, demonstramos como implantar o MetalLB no modo de camada 2 (L2).

25.1 Por que usar este método

O MetalLB é uma opção atrativa para balanceamento de carga em clusters Kubernetes bare metal por vários motivos:

  1. Integração nativa com o Kubernetes: o MetalLB se integra perfeitamente ao Kubernetes, o que facilita a implantação e o gerenciamento usando as ferramentas e práticas conhecidas do Kubernetes.

  2. Compatibilidade com bare metal: ao contrário dos balanceadores de carga com base na nuvem, o MetalLB foi especificamente projetado para implantações no local, em que os balanceadores de carga tradicionais podem não estar disponíveis ou ser viáveis.

  3. Compatível com vários protocolos: o MetalLB é compatível com os modos de camada 2 e BGP (Border Gateway Protocol), proporcionando flexibilidade de acordo com as diferentes arquiteturas e requisitos de rede.

  4. Alta disponibilidade: ao distribuir as responsabilidades de balanceamento de carga por vários nós, o MetalLB garante alta disponibilidade e confiabilidade aos seus serviços.

  5. Escalabilidade: o MetalLB processa implantações de grande escala, ajustando a escala no cluster Kubernetes para atender à crescente demanda.

No modo de camada 2, um nó assume a responsabilidade de anunciar um serviço para a rede local. Da perspectiva da rede, simplesmente parece que a máquina tem vários endereços IP atribuídos à interface de rede.

A maior vantagem do modo de camada 2 é a sua universalidade: ele funciona em qualquer rede Ethernet, sem a necessidade de hardware especial nem de roteadores sofisticados.

25.2 MetalLB no K3s (usando L2)

Neste início rápido, o modo L2 será usado. Isso significa que não precisamos de nenhum equipamento de rede especial, mas de três IPs livres no intervalo de rede.

25.3 Pré-requisitos

  • Um cluster K3s no qual o MetalLB será implantado.

Atenção
Atenção

O K3S vem com o próprio balanceador de carga de serviço chamado Klipper. Você precisa desabilitá-lo para executar o MetalLB. Para desabilitar o Klipper, o K3s precisa ser instalado com o sinalizador --disable=servicelb.

  • Helm

  • Três endereços IP livres dentro do intervalo de rede. Neste exemplo, 192.168.122.10-192.168.122.12

Importante
Importante

Garanta que esses endereços IP não estejam atribuídos. Em um ambiente DHCP, esses endereços não devem fazer parte do pool DHCP para evitar atribuições duplas.

25.4 Implantação

Vamos usar o gráfico Helm do MetalLB publicado como parte da solução SUSE Edge:

helm install \
  metallb oci://registry.suse.com/edge/charts/metallb \
  --namespace metallb-system \
  --create-namespace

while ! kubectl wait --for condition=ready -n metallb-system $(kubectl get\
 pods -n metallb-system -l app.kubernetes.io/component=controller -o name)\
 --timeout=10s; do
 sleep 2
done

25.5 Configuração

Neste ponto, a instalação foi concluída. Agora é hora de configurar usando nossos valores de exemplo:

cat <<-EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: ip-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.122.10/32
  - 192.168.122.11/32
  - 192.168.122.12/32
EOF
cat <<-EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: ip-pool-l2-adv
  namespace: metallb-system
spec:
  ipAddressPools:
  - ip-pool
EOF

Agora ele está pronto para uso. É possível personalizar vários componentes no modo L2, por exemplo:

E muito mais para BGP.

25.5.1 Traefik e MetalLB

O Traefik é implantado por padrão com o K3s (ele pode ser desabilitado com --disable=traefik) e exposto como LoadBalancer (para uso com o Klipper). No entanto, como o Klipper precisa ser desabilitado, o serviço Traefik para entrada ainda é um tipo de LoadBalancer. Sendo assim, no momento da implantação do MetalLB, o primeiro IP será automaticamente atribuído à entrada do Traefik.

# Before deploying MetalLB
kubectl get svc -n kube-system traefik
NAME      TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
traefik   LoadBalancer   10.43.44.113   <pending>     80:31093/TCP,443:32095/TCP   28s
# After deploying MetalLB
kubectl get svc -n kube-system traefik
NAME      TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)                      AGE
traefik   LoadBalancer   10.43.44.113   192.168.122.10   80:31093/TCP,443:32095/TCP   3m10s

Isso será aplicado mais adiante (Seção 25.6.1, “Ingress com MetalLB”) no processo.

25.6 Uso

Vamos criar uma implantação de exemplo:

cat <<- EOF | kubectl apply -f -
---
apiVersion: v1
kind: Namespace
metadata:
  name: hello-kubernetes
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: hello-kubernetes
  namespace: hello-kubernetes
  labels:
    app.kubernetes.io/name: hello-kubernetes
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kubernetes
  namespace: hello-kubernetes
  labels:
    app.kubernetes.io/name: hello-kubernetes
spec:
  replicas: 2
  selector:
    matchLabels:
      app.kubernetes.io/name: hello-kubernetes
  template:
    metadata:
      labels:
        app.kubernetes.io/name: hello-kubernetes
    spec:
      serviceAccountName: hello-kubernetes
      containers:
        - name: hello-kubernetes
          image: "paulbouwer/hello-kubernetes:1.10"
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          env:
          - name: HANDLER_PATH_PREFIX
            value: ""
          - name: RENDER_PATH_PREFIX
            value: ""
          - name: KUBERNETES_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
          - name: KUBERNETES_POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: KUBERNETES_NODE_NAME
            valueFrom:
              fieldRef:
                fieldPath: spec.nodeName
          - name: CONTAINER_IMAGE
            value: "paulbouwer/hello-kubernetes:1.10"
EOF

E, por fim, o serviço:

cat <<- EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: hello-kubernetes
  namespace: hello-kubernetes
  labels:
    app.kubernetes.io/name: hello-kubernetes
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: hello-kubernetes
EOF

Vamos vê-lo em ação:

kubectl get svc -n hello-kubernetes
NAME               TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
hello-kubernetes   LoadBalancer   10.43.127.75   192.168.122.11   80:31461/TCP   8s

curl http://192.168.122.11
<!DOCTYPE html>
<html>
<head>
    <title>Hello Kubernetes!</title>
    <link rel="stylesheet" type="text/css" href="/css/main.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:300" >
</head>
<body>

  <div class="main">
    <img src="/images/kubernetes.png"/>
    <div class="content">
      <div id="message">
  Hello world!
</div>
<div id="info">
  <table>
    <tr>
      <th>namespace:</th>
      <td>hello-kubernetes</td>
    </tr>
    <tr>
      <th>pod:</th>
      <td>hello-kubernetes-7c8575c848-2c6ps</td>
    </tr>
    <tr>
      <th>node:</th>
      <td>allinone (Linux 5.14.21-150400.24.46-default)</td>
    </tr>
  </table>
</div>
<div id="footer">
  paulbouwer/hello-kubernetes:1.10 (linux/amd64)
</div>
    </div>
  </div>

</body>
</html>

25.6.1 Ingress com MetalLB

Como o Traefik já atua como controlador de entrada, podemos expor o tráfego HTTP/HTTPS por um objeto Ingress, por exemplo:

IP=$(kubectl get svc -n kube-system traefik -o jsonpath="{.status.loadBalancer.ingress[0].ip}")
cat <<- EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-kubernetes-ingress
  namespace: hello-kubernetes
spec:
  rules:
  - host: hellok3s.${IP}.sslip.io
    http:
      paths:
        - path: "/"
          pathType: Prefix
          backend:
            service:
              name: hello-kubernetes
              port:
                name: http
EOF

E depois:

curl http://hellok3s.${IP}.sslip.io
<!DOCTYPE html>
<html>
<head>
    <title>Hello Kubernetes!</title>
    <link rel="stylesheet" type="text/css" href="/css/main.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:300" >
</head>
<body>

  <div class="main">
    <img src="/images/kubernetes.png"/>
    <div class="content">
      <div id="message">
  Hello world!
</div>
<div id="info">
  <table>
    <tr>
      <th>namespace:</th>
      <td>hello-kubernetes</td>
    </tr>
    <tr>
      <th>pod:</th>
      <td>hello-kubernetes-7c8575c848-fvqm2</td>
    </tr>
    <tr>
      <th>node:</th>
      <td>allinone (Linux 5.14.21-150400.24.46-default)</td>
    </tr>
  </table>
</div>
<div id="footer">
  paulbouwer/hello-kubernetes:1.10 (linux/amd64)
</div>
    </div>
  </div>

</body>
</html>

Verifique se o MetalLB funciona corretamente:

% arping hellok3s.${IP}.sslip.io

ARPING 192.168.64.210
60 bytes from 92:12:36:00:d3:58 (192.168.64.210): index=0 time=1.169 msec
60 bytes from 92:12:36:00:d3:58 (192.168.64.210): index=1 time=2.992 msec
60 bytes from 92:12:36:00:d3:58 (192.168.64.210): index=2 time=2.884 msec

No exemplo acima, o tráfego flui da seguinte maneira:

  1. hellok3s.${IP}.sslip.io é resolvido para o IP atual.

  2. Em seguida, o tráfego é processado pelo pod metallb-speaker.

  3. metallb-speaker redireciona o tráfego para o controlador traefik.

  4. Por fim, o Traefik encaminha a solicitação para o serviço hello-kubernetes.

Documentation survey