kubernetes核心概念 service(二)

service类型

  • ClusterIP(可在集群内部访问)
  • NodePort(可通过节点ip访问)
  • LoadBalancer
  • ExternalName

注意:

  1. Service类型决定了客户访问Service代理的方法
  2. Kube-proxy工作模式是service实现代理时的底层实现方式(ipvs)

  • service类型-LoadBalancer

使用MetalLB/OpenELB实现LoadBalancer

  1. 概述:  

MetalLB可以为kubernetes集群中的Service提供网络负载均衡功能。

MetalLB两大功能为:

  1. 地址分配,类似于DHCP,此地址是对外发布的虚拟的群集ip
  2. 通过群集ip访问的流量,将被负载均衡的调度到k8s群集的各个节点的service。

注:

当使用云平台(阿里云、腾讯云、AWS等)的容器服务时,我们可以通过配置service为LoadBalancer模式来绑定云平台的负载均衡器,从而实现外网的访问。

对于自建kubernetes集群我们一般使用MetalLB来实现外部流量的访问。

  1. 工作原理:

IMG_256

Metallb包含两个组件,Controller(Deployment方式部署)和Speaker(daemonset方式部署)。

具体的工作原理:

  1. Controller负责监听service变化,当service配置为LoadBalancer模式时,从IP池中分配相应的IP。
  2. Speaker则依据Service的变化,将外部流量引流到kubernetes集群node节点。
  3. 当业务流量通过到达指定的Node时,由Node上面运行的Kube-Proxy依据转发模式(iptables或ipvs)将流量转发到pod中。

小结:

  1. MetaLB负责从主机维度实现负载均衡,而pod副本间的负载均衡是通过kube-proxy实现。
  2. 跟NodePort模式相比较,MetalLB使群集有了客户访问的统一入口,即群集ip
  3. NodePort:客户访问任意节点ip,都可以访问到service,kube-proxy再通过ipvs实现pod间的调度
  4. MetalLB:客户通过访问的群集IP,客户请求被负载均衡的调度到任一节点service,kube-proxy再通过ipvs实现pod间的调度

  1. 修改kube-proxy代理模式

[root@master01 ~]# kubectl get configmap -n kube-system

NAME                      DATA   AGE

......

kube-proxy                2      35h

[root@master01 ~]# kubectl edit configmap kube-proxy -n kube-system

   ipvs:

      excludeCIDRs: null

      minSyncPeriod: 0s

      scheduler: ""

      strictARP: true #严格arp,由原来的flase修改为true,原理同LVS中的DR模式关闭到群集地址的arp响应

      syncPeriod: 0s

      tcpFinTimeout: 0s

      tcpTimeout: 0s

      udpTimeout: 0s

    kind: KubeProxyConfiguration

    logging:

      flushFrequency: 0

      options:

        json:

          infoBufferSize: "0"

      verbosity: 0

    metricsBindAddress: ""

mode: "ipvs"       #默认为空,添加ipvs

[root@master01 ~]# kubectl rollout restart daemonset kube-proxy -n kube-system

  1. metallb部署

官网安装步骤

https://metallb.universe.tf/installation/

[root@master01 ~]# kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml

服务器连接不了时,可在vpn连接后,浏览器中访问https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml,看到内容后复制创建文件,再kubectl apply -f metallb-native.yaml部署应用

也可以使用离线下载后的文件部署

[root@xxx ~]# docker load -i metallb-controller.tar          #所有节点

[root@xxx ~]# docker load -i metallb_speaker.tar         #所有节点

[root@master01 ~]# kubectl apply -f metallb-native.yaml

[root@master01 ~]# kubectl -n metallb-system get pod

NAME                          READY   STATUS    RESTARTS   AGE

controller-6b9fd67ff4-rzvg2   1/1     Running   0          9m33s

speaker-8sbmc                 1/1     Running   0          9m33s

speaker-9rhng                 1/1     Running   0          9m33s

speaker-sfdtl                 1/1     Running   0          9m33s

等待一会,可通过查看描述信息跟踪pod的运行状态,如果vpn连接时,长时间无法完成下载时,各节点重启docker

  1. IP地址池准备

[root@master01 ~]# vim ippool.yaml

apiVersion: metallb.io/v1beta1

kind: IPAddressPool

metadata:

  name: ippool

  namespace: metallb-system

spec:

  addresses:

  - 192.168.10.240-192.168.10.250

[root@master01 ~]# kubectl apply -f ippool.yaml

如果出现错误提示:等上面pod运行起来以后再部署,若故障依旧,重启docker

Error from server (InternalError): error when creating "ippool.yaml": Internal error occurred: failed calling webhook "ipaddresspoolvalidationwebhook.metallb.io": failed to call webhook: Post "https://metallb-webhook-service.metallb-system.svc:443/validate-metallb-io-v1beta1-ipaddresspool?timeout=10s": dial tcp 10.100.143.2:443: connect: connection refused

查看地址池信息:

[root@master01 ~]# kubectl -n metallb-system get ipaddresspool

NAME     AUTO ASSIGN   AVOID BUGGY IPS   ADDRESSES

ippool   true          false             ["192.168.10.240-192.168.10.250"]

  1. 开启二层通告

[root@master01 ~]# vim L2.yaml

apiVersion: metallb.io/v1beta1

kind: L2Advertisement

metadata:

  name: example

  namespace: metallb-system

[root@master01 ~]# kubectl apply -f L2.yaml

  1. 发布Service类型为LoadBalancer的应用

创建Deployment控制器类型应用nginx-metallb及service,service类型为LoadBalancer

[root@master01 ~]# vim nginx-metallb.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

  name: nginx-metallb

spec:

  selector:

    matchLabels:

      app: nginx

  template:

    metadata:

      labels:

        app: nginx

    spec:

      containers:

      - name: nginx-metallb1

        image: nginx:1.20

        imagePullPolicy: IfNotPresent

        ports:

        - containerPort: 80

---

apiVersion: v1

kind: Service

metadata:

  name: nginx-metallb

spec:

  ports:

  - port: 8090

    protocol: TCP

    targetPort: 80

  selector:

    app: nginx

  type: LoadBalancer

 

[root@master01 ~]# kubectl apply -f nginx-metallb.yaml

[root@master01 ~]# kubectl get svc

NAME               TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)          AGE

headless-service   ClusterIP      None             <none>           80/TCP           168m

kubernetes         ClusterIP      10.96.0.1        <none>           443/TCP          170m

nginx-metallb      LoadBalancer   10.99.125.229    192.168.10.240   8090:32276/TCP   8m10s

nginx-nodeport     NodePort       10.107.199.151   <none>           8060:30001/TCP   152m

在各节点上查看群集ip

[root@master01 ~]# ip a | grep 192.168.10.240

inet 192.168.10.240/32 scope global kube-ipvs0

[root@worker01 ~]# ip a | grep 192.168.10.240

    inet 192.168.10.240/32 scope global kube-ipvs0

[root@worker02 ~]# ip a | grep 192.168.10.240

    inet 192.168.10.240/32 scope global kube-ipvs0

[root@master01 ~]# curl http://192.168.10.240:8090

可以显示网页

Windows浏览器访问:http://192.168.10.240:8090

可以显示网页

仍然可以通过nodeIP访问服务:curl http://192.168.10.11:32276

可以显示网页

  1. ExternalName作用

  • 把集群外部的服务引入到集群内部,实现了集群内部pod和集群外部的服务进行通信
  • ExternalName 类型的服务适用于外部服务使用域名的方式,缺点是不能指定端口
  • 集群内的Pod会继承Node上的DNS解析规则,只要Node可以访问的服务,Pod中也可以访问到, 这就实现了集群内服务访问集群外服务

  1. 将公网域名引入
    1. 编写YAML文件

[root@master01 ~]# vim externalname.yml

apiVersion: v1

kind: Service

metadata:

  name: my-externalname

  namespace: default

spec:

  type: ExternalName

  externalName: www.baidu.com                  # 对应的外部域名为www.baidu.com

    1. 应用YAML文件

[root@master01 ~]# kubectl apply -f externalname.yml

    1. 查看service

[root@master01 ~]# kubectl get svc

NAME               TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)          AGE

my-externalname    ExternalName   <none>           www.baidu.com    <none>           18m

    1. 查看my-service的dns解析

[root@master01 ~]# kubectl -n kube-system get svc

NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE

kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   2d

[root@master01 ~]# dig -t A my-externalname.default.svc.cluster.local. @10.96.0.10

;; QUESTION SECTION:

;my-externalname.default.svc.cluster.local. IN A

;; ANSWER SECTION:

my-externalname.default.svc.cluster.local. 5 IN CNAME www.baidu.com.

www.baidu.com.          5       IN      A       110.242.68.3

www.baidu.com.          5       IN      A       110.242.68.4

[root@master01 ~]# kubectl run  -it --image busybox -- sh

/ # nslookup www.baidu.com

Server:         10.96.0.10

Address:        10.96.0.10:53

Non-authoritative answer:

Name:   www.baidu.com

Address: 39.156.70.46

Name:   www.baidu.com

Address: 39.156.70.239

/ # nslookup my-externalname.default.svc.cluster.local.

Server:         10.96.0.10

Address:        10.96.0.10:53

my-externalname.default.svc.cluster.local       canonical name = www.baidu.com

Name:   www.baidu.com

Address: 110.242.68.3

Name:   www.baidu.com

Address: 110.242.68.4

  • sessionAffinity会话保持(会话粘滞)
  1. Session Affinity简介

会话保持(Session Affinity),有时又称粘滞会话(Sticky Sessions), 是负载均衡领域设计需要着力解决的重要问题之一,也是一个相对比较复杂的问题。

会话保持是指在负载均衡器上的一种机制,在完成负载均衡任务的同时,还负责一系列相关的访问请求会分配到一台服务器上。

会话保持的作用:确保把来自同一客户的一个完整会话的请求转发至后台同一台服务器进行处理。

  1. 什么时候需要会话保持?

举个大家每天都会遇到的例子,大家在淘宝或者京东上购物时,从完成用户身份认证到浏览店铺,选择心仪商品加入购物车,一直到最后下单完成支付,需要经过很多次和服务器的交互过程才能完成整个交易。由于这几次交互过程从顺序上和逻辑上是密切相关的,服务器在进行这些交互过程的某一个交互步骤时需要一个上下文(Context),即上一次交互过程的输出,因此要求这些相关的交互过程都由一台服务器完成。

在这种情况下,假设负载均衡器仍然把这些相关交互session分散到不同的服务器实例上,就会带来很糟糕的用户体验,比如客户在浏览器上每点击一次,都会弹出登录页面。或者即使用户输入了正确的验证码,却仍然提示验证码错误。由于服务器处理实例不一样,也有可能造成客户放入购物车的物品丢失。

设置sessionAffinity为Clientip (类似nginx的ip_hash算法,lvs的sh算法)

  1. 创建测试用deployment、service

[root@nginx ~]# cat sessionAffinity.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

  name: nginx-server1

spec:

  replicas: 2

  selector:

    matchLabels:

      app: nginx

  template:

     metadata:

       labels:

         app: nginx

     spec:

       containers:

       - name: c1

         image: nginx:1.20

         imagePullPolicy: IfNotPresent

         ports:

         - containerPort: 80

---

apiVersion: v1

kind: Service

metadata:

  name: nginx-svc

spec:

  type: ClusterIP

  ports:

  - protocol: TCP

    port: 80

    targetPort: 80

  selector:

    app: nginx

[root@master01 ~]# kubectl apply -f sessionAffinity.yaml

[root@master01 ~]# kubectl get pods

NAME                             READY   STATUS    RESTARTS   AGE

nginx-server1-58845f75f4-9zlnw   1/1     Running   0          2m11s

nginx-server1-58845f75f4-ffqdt   1/1     Running   0          2m11s

进入pod,创建网页

[root@master01 ~]# kubectl exec -it nginx-server1-58845f75f4-9zlnw -- bash

root@nginx-server1-58845f75f4-9zlnw:/# echo web1 > /usr/share/nginx/html/index.html

root@nginx-server1-58845f75f4-9zlnw:/# exit

进入pod,创建网页

[root@master01 ~]# kubectl exec -it nginx-server1-58845f75f4-ffqdt -- bash

root@nginx-server1-58845f75f4-ffqdt:/# echo web2 > /usr/share/nginx/html/index.html

root@nginx-server1-58845f75f4-ffqdt:/# exit

[root@master01 ~]# kubectl get svc

NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE

kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   8m53s

nginx-svc    ClusterIP   10.108.138.24   <none>        80/TCP    8m11s

[root@master01 ~]# curl 10.108.138.24

web1

[root@master01 ~]# curl 10.108.138.24

web2

  1. 给服务打补丁,增加会话粘滞

打补丁前查看:

[root@master01 ~]# kubectl describe service nginx-svc

...

Endpoints:         10.244.30.71:80,10.244.5.10:80

Session Affinity:  None

Events:            <none>

打补丁前查看:

[root@master01 ~]# kubectl patch svc nginx-svc -p '{"spec":{"sessionAffinity":"ClientIP"}}'

[root@master01 ~]# kubectl describe service nginx-svc

...

Endpoints:         10.244.30.71:80,10.244.5.10:80

Session Affinity:  ClientIP

Events:            <none>

客户端测试:

[root@master01 ~]# curl 10.108.138.24

web1

[root@master01 ~]# curl 10.108.138.24

web1

设置回sessionAffinity为None

[root@master01 ~]# kubectl patch svc nginx-svc -p '{"spec":{"sessionAffinity":"None"}}'

[root@master01 ~]# kubectl describe service nginx-svc

...

Endpoints:         10.244.30.71:80,10.244.5.10:80

Session Affinity:  None

Events:            <none>

测试

[root@master01 ~]# curl 10.108.138.24

web2

[root@master01 ~]# curl 10.108.138.24

web1

更多推荐