自己搭建的k8s集群,怎么做负载均衡?

如果把K8S搞在公有云上,可以跟云厂商买它的负载均衡服务,就用这个负载均衡服务提供的公网IP,把你的域名映射到这个公网IP上,然后配置这个云厂商提供的负载均衡服务,让它往后端的ECS主机上转发

但是呢,如果是自己的物理服务器,并不是假设在公有云上的K8S集群,那么很显然是没有云厂商预先提供的负载均衡公网IP地址的,此时怎么办呢?

在K8S里面,如果把Service暴露到集群外,可以供客户端访问的话,那么要通过NodePort、LoadBalancer或者Ingress这三种方式才可以的,具体是啥意思呢?

  • NodePort,就是在每台K8S的worker节点上都通过kube-proxy进行端口映射,打个比方Service对外的端口是8080,那么通过NodePort方式就要求在每台物理主机上都要通过kube-proxy进程进行数据转发,而且要让kube-proxy监听某个特定的端口比如33000,客户端访问的时候是访问NodeIp:33000的方式。

    kube-proxy进程在33000端口收到TCP报文后,就会转发给这个Service背后对应的Pod,它会查询kube-apiserver,看看这个Service背后的Pod当前都部署在哪些物理主机上,然后往这些Pod进行转发。

    因为kube-proxy进程和这些pod容器都是在集群内的,所以kube-proxy进程是可以访问到这些Pod在集群内的IP地址的,换句话说,kube-proxy进程直接向Pod的IP地址发起请求,在IP层模式通的
     
  • LoadBalancer,这个是让阿里云、华为云的SLB提供IP地址,这个简单,直接配置即可,但是要求k8s集群部署在公有云上,这个也有点扯,并不是每次都是部署在公有云上的
     
  • Ingress,是七层代理,一般是http代理,可以基于url做转发,比kube-proxy的TCP四层代理更高层,k8s的Ingress实际上是包装了nginx,基于nginx做了一个Pod,当在K8S上面部署一个Ingress资源的时候,实际上是启动了一个nginx的Pod,然后把nginx的nginx.conf文件做了修改,这样就可以让nginx做http转发了。

    在使用k8s里面的Ingress资源对象的时候,k8s本质上是把Ingress资源对象的yaml文件转换为nginx.conf文件,然后让Pod里面的Nginx容器中的Nginx进程reload一下配置文件,就是执行nginx -s reload,这样就实现了转发规则的动态调整,比如下面的rules部分,其实就是会被转换为nginx.conf文件
     
    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: example-ingress
    spec:
      rules:
       # 指定主机
      - host: example.ctnrs.com
        http:
          paths:
          # 指定路径
          - path: /
            backend:
              # 通过kubectl get svc查询到的servicename 
              serviceName: web
              # 通过kubectl get svc查询到的前面的端口
              servicePort: 80

我研究了一下https://porterlb.io/zh/,它应对的场景是自己搭建的K8S集群,比如给你10台物理主机你去搞一个k8s集群,然后怎么对外暴露你的Service呢?

这个porterlb是KubeSphere提供的LB,说是支持BGP路由方式,我一直觉得很奇怪,怎么会和BGP路由扯上关系?BGP是用于AS之间高效路由的路由协议啊,比如支持BGP的数据中心,你去租赁一条线路,可以避免南北访问的速度问题,而这里说的是K8S的Service对外提供服务的问题,怎么会和BGP扯上关系?

K8S的Service虽然有IP地址,但是说到底,这个IP地址并不是网管员分配的IP地址,也不是运营商分配的公网IP,用户是无法访问的,这个Service的IP地址是在k8s集群内的私有IP地址,根本不对外公开的,所以如果没有一定的机制,是无法让客户端访问到这个对外暴露的Service的。

比如应用部署在K8S上,客户可以通过app、小程序、pc网站访问,那你的Service必须得有一个公网IP,你直接给它一个Service的IP地址,客户端是无法路由的,路由不可达!

PorterLB产品支持2种对外暴露Service的机制,L2和BGP,先来看看L2模式,核心是让Service的IP地址必须和路由器的IP地址在同一个网段内,这样的话,路由器192.168.0.5才能和192.168.0.91互通

porterlb的L2模式

porter-layer-2-topology

怎么样才能让客户端的访问请求均衡到Pod1和Pod2呢?这玩意是这样玩的:

  1. 首先porterlb,它确确实实是一个进程,它就是用golang写的一个程序,假设你的k8s集群有10台物理机组成,找台物理机安装一下porterlb即可
  2. 现在按照老样子,先创建一个k8s的Service,搞个yaml就可以创建一个k8s的service资源对象,背后有2个pod组成,分别在2台物理机上,如上图在Worker1和Worker2上
  3. 然后我们肯定想要让client的数据流量均衡到达这2个物理机,怎么搞呢?
  4. 核心在这个中间的路由器,你想,Service是有一个IP地址的,客户端访问这个IP地址,只要路由器能够把IP报文路由出去,不就OK了吗,在这里Service的IP是0.91,但是现在并没有哪一台物理主机的IP地址是0.91,所以路由器肯定是不知道怎么把数据报文路由出去的!
  5. 此时魔法开始出现,我们一旦创建了一个k8s的服务后,就让这个porter进程去和路由器通信,所以写porter的人要懂怎么和路由器通信,我们让porterlb进程发一个ARP报文给路由器,意思是,唉,兄弟,告诉你,你不是不知道0.91这个IP对应的MAC地址吗,我告诉你啊,IP地址是192.168.0.91的机器,它对应的MAC地址是52:54:22:3a:e6:64,也就是Worker1节点
  6. 这样一搞的话,本来Worker1的IP地址是192.168.0.3,结果现在它又莫名其妙多了一个IP地址192.168.0.91,路由器后续就知道了,它一旦收到客户端发给0.91的报文,就会直接发给Worker1机器,因为路由器已经通过porterlb进程主动发给它的ARP报文知道了0.91对应的MAC地址
  7. 然后呢,Worker1机器上不是跑着kube-proxy进程嘛,它就是一个类似nginx的反向代理,数据报文达到Worker1上的kube-proxy进程后,它会转发给Pod1或者Pod2
  8. 如果Worker1服务器挂了的话,porterlb进程又开始谎报军情,它由主动给路由器发了一个ARP报文说:IP地址是192.168.0.91的机器,现在变了啊,它对应的MAC地址是52:54:22:37:6c:7b,这样路由器再收到客户端发给0.91的数据,就会转发给worker2这台机器了。

通过这种方式,相当于是多了一跳,先从路由器发给Worker1,然后由Worker1上的kube-proxy再发给Worker1上的Pod1或者Worker2上的Pod2,多了一跳,同时也有缺点,任何时候,从路由器过来的数据报文流量都只能发给Worker1或者Worker2,不能同时发给它们,这就导致Worker1的网卡成为流量瓶颈,本来如果效果更好的话,让路由器同时发给Worker1和Worker2,带宽不就翻倍了嘛,这完全就是一个谎报军情的L2模式嘛,呵呵

Porterlb的BGP模式

这个BGP模式也很有意思,竟然让Porter进程给BGP路由器进行tcp通信,发送BGP路由报文,搞这个要懂BGP路由的协议格式。安装在Kubernetes群集中的PorterLB进程与BGP路由器建立BGP连接(这是一个TCP连接),构造一条路由规则发给BGP路由器,什么规则呢,如图右上角,发往172.22.0.2的报文,下一跳的地址是0.3、0.4,这样就实现了负载均衡,牛逼!

这种方式,BGP路由器会把流量均衡的发给0.3、0.4这2台物理机,比上面的L2模式好,與此同時也就意味着,如果Pod1发生销毁重建,那么PorterLB必须得到通知,假设Pod1现在漂移到了192.168.0.10上面,那么PorterLB必须重新给BGP路由器发新的路由报文,否则BGP路由器还把报文发给0.3,这就不对了。

所以开发PorterLB这个产品,需要对BGP路由比较懂,同时还要知道怎么给路由器发ARP报文,同时还要懂K8S相关的源码级别的API才好做二次开发。

这种BGP模式,不需要Service的IP地址和路由器在同一个网段内,比如上面Service的IP是172.22.0.2,但是路由器的IP是192.168.0.5,根本不是一个网段。

这种方式下,客户端可以直接请求Service的IP地址172.22.0.0,此时会达到BGP路由器,BGP路由器会发给Worker1和Worker2,BGP路由器为啥会发给它俩?因为Porterlb进程给它发了BGP路由规则,所以它才知道。

看这个:https://github.com/osrg/gobgp  github上真的是可供参考的资料太多了,竟然还有直接和BGP路由器在TCP层面直接交换数据的库,porterlb就是用这个库和BGP路由器直接通信,让BGP路由器知道如何路由。

再来一个这个:https://github.com/mdlayher/arp

这玩意实现了arp协议,可以用来发arp报文,golang写的,PorterLB是用它来给路由器发ARP报文的,可以看到porterlb依赖的第三方库。

 https://github.com/coreos/go-iptables,还用到了这个第三方库,直接操作linux上的iptables,go-iptables wraps invocation of iptables utility with functions to append and delete rules; create, clear and delete chains.

https://github.com/mdlayher/ethernet,这个,Package ethernet implements marshaling and unmarshaling of IEEE 802.3 Ethernet II frames and IEEE 802.1Q VLAN tags. MIT Licensed,可以对带VLAN的以太网数据报文进行解析。

apiVersion: v1
kind: Namespace
metadata:
  name: porter-system
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    controller-gen.kubebuilder.io/version: v0.4.0
  creationTimestamp: null
  name: bgpconfs.network.kubesphere.io
spec:
  group: network.kubesphere.io
  names:
    kind: BgpConf
    listKind: BgpConfList
    plural: bgpconfs
    singular: bgpconf
  scope: Cluster
  versions:
  - name: v1alpha1
    schema:
      openAPIV3Schema:
        description: BgpConf is the Schema for the bgpconfs API
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this f
<think>嗯,用户想了解Kubernetes集群的使用方法和介绍,特别是教程和功能。首先,我得理清Kubernetes的基本概念,确保自己理解正确。Kubernetes是一个容器编排平台,用于自动化部署、扩展和管理容器化应用,对吧?用户可能已经知道一些基础,但需要系统的指导。 接下来,用户提到了教程和功能介绍,可能需要分步骤的搭建指南以及主要功能模块的说明。我需要参考提供的引用内容,特别是引用[2]和[3]里的步骤。例如,准备环境、配置主节点、添加工作节点、安装网络插件等步骤,这些都是搭建集群的关键。 然后,功能方面,用户可能想知道Kubernetes能做什么,比如自动扩缩容、服务发现、负载均衡、滚动更新、存储编排等。需要将这些功能用简洁明了的语言解释清楚,可能还要结合实例,比如如何通过kubectl部署应用。 另外,用户提供的引用中有一些具体命令,比如kubeadm init和join,这些需要正确呈现,确保用户能够复制粘贴使用。同时,注意代码块的格式,使用正确的语法高亮,比如shell或bash。 还要考虑用户可能遇到的问题,比如节点状态NotReady,这可能是网络插件未安装导致的,引用[4]中提到的情况。这时候需要提醒用户检查网络配置,比如Calico插件的安装情况。 然后,生成相关问题。根据用户的需求,可能涉及集群维护、权限管理、监控、存储卷的使用,以及升级集群的方法。这些问题需要覆盖用户可能进一步探索的方向,帮助他们深入学习。 最后,检查回答是否符合系统级指令,比如数学公式是否正确使用$符号,独立公式是否用$$,中文回答,引用标识是否正确添加。同时,确保LaTeX语法正确,例如命令中的变量是否用$包裹,但看起来这里可能不需要数学公式,主要是在代码和步骤说明上。 总结一下,回答的结构应该是先介绍Kubernetes的基本概念,然后分步骤搭建集群,接着讲解核心功能,再给出常用命令示例,最后生成相关问题。需要确保引用正确,每个引用对应到具体的步骤或问题,比如引用[3]对应搭建步骤,引用[4]对应节点状态检查。</think>### Kubernetes 集群使用教程与功能介绍 #### 一、Kubernetes 集群简介 Kubernetes(简称 K8s)是用于自动化容器化应用部署、扩展和管理的开源平台。其核心功能包括服务发现、负载均衡、自动扩缩容、滚动更新等[^2]。 --- #### 二、Kubernetes 集群搭建教程 ##### 1. **环境准备** - 至少准备 3 台服务器(1 主节点 + 2 工作节点) - 关闭防火墙、SELinux 和 Swap 分区[^3] - 安装 Docker 和 Kubernetes 工具(如 `kubeadm`, `kubectl`, `kubelet`) ##### 2. **主节点初始化** ```shell kubeadm init --apiserver-advertise-address=<主节点IP> --pod-network-cidr=192.168.0.0/16 ``` 初始化后按提示执行: ```shell mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config ``` ##### 3. **工作节点加入集群** 在每个工作节点运行 `kubeadm join` 命令(初始化后生成)[^3]: ```shell kubeadm join <主节点IP>:6443 --token <token> --discovery-token-ca-cert-hash <hash> ``` ##### 4. **安装网络插件** ```shell kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml ``` 验证节点状态: ```shell kubectl get nodes # 所有节点应显示 "Ready"[^4] ``` --- #### 三、核心功能与使用场景 1. **服务部署** 通过 YAML 文件定义部署: ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ``` 应用配置: ```shell kubectl apply -f nginx-deployment.yaml ``` 2. **服务暴露与负载均衡** 创建 Service 对象对外暴露服务: ```shell kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer ``` 3. **自动扩缩容** 根据 CPU 使用率自动扩展副本: ```shell kubectl autoscale deployment nginx-deployment --cpu-percent=50 --min=1 --max=10 ``` 4. **滚动更新与回滚** 更新镜像版本并监控状态: ```shell kubectl set image deployment/nginx-deployment nginx=nginx:1.20 kubectl rollout status deployment/nginx-deployment ``` --- #### 四、常用命令速查 | 功能 | 命令示例 | |---------------------|-----------------------------------| | 查看节点状态 | `kubectl get nodes`[^4] | | 查看 Pod 列表 | `kubectl get pods -A` | | 查看服务详情 | `kubectl describe service <name>`| | 查看日志 | `kubectl logs <pod-name>` | | 进入容器终端 | `kubectl exec -it <pod-name> -- /bin/bash` | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值