有新的冒险伙伴加入!

MetalLB

(在这一部分,我会尝试用较为“官方”的措辞来总结;而在正文部分,我还是会用大白话说)
MetalLB是一个控制平面组件,它可以在BareMetal环境下,为ServiceLoadBalancer语义提供一个实现
它可以通过ARP(IPv4)/NDP(IPv6)协议(在L2模式下)或者BGP协议(在BGP模式下)来宣告VIP(Virtual IP)
从而使入口端流量流向leader(在L2模式下)或者进行路由层面的负载均衡(在BGP模式下)

这家伙在说些什么呢……(自我批判)
总之,k8s本身并不提供LoadBalancer语义的具体实现。通常情况下,云厂商售卖的云服务器中提供了它的实现,而我们的本地裸机如果想要使用type: LoadBalancer,就需要自己安装一个了,MetalLB就是其中一种。简单点来讲,安装了MetalLB,集群就可以“假装自己在云上”。
需要注意的是,MetalLB本身并不负责流量转发,它只负责“将流量引入集群”,实际的转发工作由kube-proxy和CNI这类组件负责
它也只控制入口流量的流向,如上文所述,kube-proxy等等这些组件会负责后续的转发,确保(至少如果我没配置错的话)流量送到正确的地方
在L2模式下,入口的所有流量首先会被送到Leader,尽管这听起来配不上它的“LoadBalancer”的名头,但它仍然属于负载均衡的一部分;在BGP模式下,这玩意就能充分发挥优势,真正地在路由层面进行分流了
在L2模式下,它会选出一个leader节点,如果这个leader节点挂掉,它就会选出下一个……这就是“漂移”,一定程度上减轻了单点故障的影响,为集群带来了一点稳定性

“可恶,集群阵!”
“就一个节点也能叫「集群」吗?”
——《东方K8S》

在学习初期,我曾经使用NodePort来暴露Service,并且当时的我认为使用NodePort和使用LoadBalancer和MetalLB是没有区别的。彳亍吧,使用NodePort在单节点的集群用来暴露服务或者用来测试确实是可行的,但是这么做的缺点会很快暴露出来:

  • 无法暴露低位端口(80/443),因为NodePort有限制 (当然很有可能是设计上就不打算让我们这么做)
  • 在Service越来越多时,NodePort的管理将会变得异常困难
  • 最致命的一点……NodePort暴露出来的服务是 节点相关 而非 集群相关 的,这意味着我们需要访问 节点 来访问暴露的服务……嘶……

Ingress

好吧,其实如果单独讲“Ingress”的话,可能会引起歧义……它可以指“被ingress-controller读取并执行的一种资源”,也可以指“Kubernetes Ingress这一套东西” 当然这节的节标题指的是后者
Ingress(体系)提供了第七层的路由抽象,所以可以提供第七层负载均衡,ingress资源当然本身不负责转发流量,而是影响ingress-controller的行为 废话 ;从某种意义上来说ingress-controller自身不负责转发流量(?),但是奈何它与更加底层的实现(例如nginx,这些实现最终提供了流量转发)紧紧耦合了起来,所以其实ingress-controller自身确实承担了转发流量的工作

概念补齐

控制平面与数据平面

曾经,我以为,控制平面和数据平面的划分是以节点为单位的

但是实际上大错特错,控制平面应当是负责调控节点运行状态的“组件集合”,例如kube-apiserveretcd,诸如此类,它们互相协作,就好像一个”平面“。由于以上原因,”平面”的划分并不是以节点为单位的,这些组件甚至可以分布在不同的节点上(通常以Pod形式)。综上,”平面“的分类是以逻辑而非物理位置方面来划分的。控制平面负责决策,而数据平面负责执行实际工作。
不过要注意,master节点和worker节点并不等同于控制平面和数据平面,根据上文,很容易知道这两对东西甚至不在同一个级别上。但是话又说回来了,让worker跑控制平面的组件似乎有些反直觉……?

果然还是要来点干货啊

MetalLB

下面是MetalLB资源的配置文件(假设metallb命名空间存在 废话

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default-pool
namespace: metallb
spec:
addresses:
- 192.168.1.50-192.168.1.100
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default-l2
namespace: metallb
spec:
ipAddressPools:
- default-pool

Ingress-nginx

由于我们配置了MetalLB,所以我们现在可以使用LoadBalancer来暴露我们的Ingress服务了!但是等等昂,我们需要让Ingress知道这一点……我们先创建一个文件,ingress_value.yaml

1
2
3
controller:
service:
type: LoadBalancer

然后使用下面的命令,将我们的配置应用到Ingress,让Ingress见识一下我们新提的LoadBalancer语义实现:

1
helm upgrade ingress-app ingress-nginx/ingress-nginx -n=the-namespace -f ingress_value.yaml

下面贴出了我将/dashboard的path代理到my-headlamp服务的Ingress配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cirno-ingress-config-redirect
namespace: kube-system
spec:
ingressClassName: nginx
rules:
- http:
paths:
- pathType: Exact
backend:
service:
name: my-headlamp # 假设服务名是这样
port:
number: 80
path: /dashboard/
---
# 由于headlamp的不明问题,访问“/dashboard”时服务会爆404,而“/dashboard/”却没有问题,所以下面再加一条
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cirno-ingress-config-redirect-slash
namespace: kube-system
annotations:
nginx.ingress.kubernetes.io/permanent-redirect: /dashboard/
spec:
ingressClassName: nginx
rules:
- http:
paths:
- pathType: Exact
backend:
service:
name: my-headlamp
port:
number: 80
path: /dashboard

(哦对了,别忘了更改headlamp的baseURL):

1
2
config:
baseURL: "/dashboard"
1
helm upgrade headlamp headlamp/headlamp -n=the-namespace -f headlamp_patch.yaml