27 Kubernetes API 服务器前面的 MetalLB #
本指南将演示如何在具有三个控制平面节点的 HA 群集上,使用 MetalLB 服务将 RKE2/K3s API
向外部公开。要实现此目的,需要手动创建类型为 LoadBalancer 的 Kubernetes
服务。系统随后会自动创建 EndpointSlices 对象,该对象会保留群集中所有可用控制平面节点的
IP。为确保 EndpointSlices 能与群集中发生的事件(添加/去除节点或节点下线)保持实时同步,需部署 Endpoint Copier
Operator(第 20 章 “Endpoint Copier Operator”)。该操作器会监控默认
kubernetes EndpointSlices 中的事件,并自动更新受管理的
EndpointSlices,以使两者保持同步。由于受管理的服务类型为 LoadBalancer,MetalLB
会为其分配静态 ExternalIP。此 ExternalIP 将用于与
API 服务器通信。
27.1 先决条件 #
要在其上部署 RKE2/K3s 的三台主机。
请确保这些主机的主机名不同。
对于测试目的,这些主机可以是虚拟机
网络中至少有 2 个可用 IP(一个用于 Traefik/Nginx,另一个用于受管服务)。
Helm
27.2 安装 RKE2/K3s #
如果您不想使用新群集,而要使用现有群集,请跳过此步骤并执行下一步。
首先,必须在网络中预留一个可用 IP,该 IP 稍后将用作受管服务的 ExternalIP。
通过 SSH 连接到第一台主机并以群集模式安装所需的发行版。
对于 RKE2,使用以下命令:
# Export the free IP mentioned above
export VIP_SERVICE_IP=<ip>
curl -sfL https://get.rke2.io | INSTALL_RKE2_EXEC="server \
--write-kubeconfig-mode=644 --tls-san=${VIP_SERVICE_IP} \
--tls-san=https://${VIP_SERVICE_IP}.sslip.io" sh -
systemctl enable rke2-server.service
systemctl start rke2-server.service
# Fetch the cluster token:
RKE2_TOKEN=$(tr -d '\n' < /var/lib/rancher/rke2/server/node-token)对于 K3s,使用以下命令:
# Export the free IP mentioned above
export VIP_SERVICE_IP=<ip>
export INSTALL_K3S_SKIP_START=false
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server --cluster-init \
--disable=servicelb --write-kubeconfig-mode=644 --tls-san=${VIP_SERVICE_IP} \
--tls-san=https://${VIP_SERVICE_IP}.sslip.io" K3S_TOKEN=foobar sh -确保在 k3s server 命令中提供
--disable=servicelb 标志。
从现在开始,应在本地计算机上运行命令。
要从外部访问 API 服务器,需使用 RKE2/K3s VM 的 IP。
# Replace <node-ip> with the actual IP of the machine
export NODE_IP=<node-ip>
export KUBE_DISTRIBUTION=<k3s/rke2>
scp ${NODE_IP}:/etc/rancher/${KUBE_DISTRIBUTION}/${KUBE_DISTRIBUTION}.yaml ~/.kube/config && sed \
-i '' "s/127.0.0.1/${NODE_IP}/g" ~/.kube/config && chmod 600 ~/.kube/config27.3 配置现有群集 #
仅当您要使用现有的 RKE2/K3s 群集时,此步骤才有效。
要使用现有群集,应修改 tls-san 标志,此外还应针对 K3s 禁用
servicelb LB。
要更改 RKE2 或 K3s 服务器的标志,需要修改群集所有 VM 上的
/etc/systemd/system/rke2.service 或
/etc/systemd/system/k3s.service 文件,具体取决于发行版。
应在 ExecStart 中插入标志。例如:
对于 RKE2,使用以下命令:
# Replace the <vip-service-ip> with the actual ip
ExecStart=/usr/local/bin/rke2 \
server \
'--write-kubeconfig-mode=644' \
'--tls-san=<vip-service-ip>' \
'--tls-san=https://<vip-service-ip>.sslip.io' \对于 K3s,使用以下命令:
# Replace the <vip-service-ip> with the actual ip
ExecStart=/usr/local/bin/k3s \
server \
'--cluster-init' \
'--write-kubeconfig-mode=644' \
'--disable=servicelb' \
'--tls-san=<vip-service-ip>' \
'--tls-san=https://<vip-service-ip>.sslip.io' \然后应执行以下命令来加载新配置:
systemctl daemon-reload
systemctl restart ${KUBE_DISTRIBUTION}27.4 安装 MetalLB #
要部署 MetalLB,可以使用 K3s 上的 MetalLB(第 25 章 “K3s 上的 MetalLB(使用第 2 层模式)”)指南。
注意:请确保 VIP_SERVICE_IP
IP 地址与群集中现有的 IPAddressPools 不重叠。
创建单独的 IpAddressPool 和
L2Advertisement,仅用于受管理的服务。
注意:下面的 IPAddressPool 将分配给
default 命名空间中类型为 LoadBalancer
的服务。如果该命名空间中存在多个 LoadBalancer 服务,可能需要配置额外的 ServiceSelectors,以明确匹配此
VIP 服务。
# Export the VIP_SERVICE_IP on the local machine
# Replace with the actual IP
export VIP_SERVICE_IP=<ip>
cat <<-EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: kubernetes-vip-ip-pool
namespace: metallb-system
spec:
addresses:
- ${VIP_SERVICE_IP}/32
serviceAllocation:
priority: 100
namespaces:
- default
EOFcat <<-EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: kubernetes-vip-l2-adv
namespace: metallb-system
spec:
ipAddressPools:
- kubernetes-vip-ip-pool
EOF27.5 安装 Endpoint Copier Operator #
helm install \
endpoint-copier-operator oci://registry.suse.com/edge/charts/endpoint-copier-operator \
--namespace endpoint-copier-operator \
--create-namespace以上命令会部署包含两个复本的 endpoint-copier-operator
操作器部署。其中一个复本是领导者,另一个复本在需要时接管领导者角色。
现在应部署 kubernetes-vip 服务,这将由操作器来协调,另外需创建具有所配置端口和 IP 的
EndpointSlices。
对于 RKE2,使用以下命令:
cat <<-EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: kubernetes-vip
namespace: default
spec:
ports:
- name: rke2-api
port: 9345
protocol: TCP
targetPort: 9345
- name: k8s-api
port: 6443
protocol: TCP
targetPort: 6443
type: LoadBalancer
EOF对于 K3s,使用以下命令:
cat <<-EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: kubernetes-vip
namespace: default
spec:
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: https
port: 6443
protocol: TCP
targetPort: 6443
sessionAffinity: None
type: LoadBalancer
EOF校验 kubernetes-vip 服务是否使用正确的 IP 地址:
kubectl get service kubernetes-vip -n default \
-o=jsonpath='{.status.loadBalancer.ingress[0].ip}'确保 default 名称空间中的 kubernetes-vip 和
kubernetes EndpointSlices 资源指向相同的 IP。
kubectl get endpointslices | grep kubernetes如果所有设置正确,剩下的最后一项操作就是在 Kubeconfig 中使用
VIP_SERVICE_IP。
sed -i '' "s/${NODE_IP}/${VIP_SERVICE_IP}/g" ~/.kube/config从现在开始,所有 kubectl 命令都将通过 kubernetes-vip
服务运行。
27.6 添加控制平面节点 #
要监控整个过程,可以打开另外两个终端选项卡。
第一个终端:
watch kubectl get nodes第二个终端:
watch kubectl get endpointslices现在,在第二和第三个节点上执行以下命令。
对于 RKE2,使用以下命令:
# Export the VIP_SERVICE_IP in the VM
# Replace with the actual IP
export VIP_SERVICE_IP=<ip>
curl -sfL https://get.rke2.io | INSTALL_RKE2_TYPE="server" sh -
systemctl enable rke2-server.service
mkdir -p /etc/rancher/rke2/
cat <<EOF > /etc/rancher/rke2/config.yaml
server: https://${VIP_SERVICE_IP}:9345
token: ${RKE2_TOKEN}
EOF
systemctl start rke2-server.service对于 K3s,使用以下命令:
# Export the VIP_SERVICE_IP in the VM
# Replace with the actual IP
export VIP_SERVICE_IP=<ip>
export INSTALL_K3S_SKIP_START=false
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server \
--server https://${VIP_SERVICE_IP}:6443 --disable=servicelb \
--write-kubeconfig-mode=644" K3S_TOKEN=foobar sh -