在k8s中使用Ingress进行服务访问和负载均衡

0 阅读

k8s中的Ingress实现了对外部负载均衡器的自动配置,是对NodePort的替代方案。

0. 搭建环境

0.1 搭建k8s集群

参考《在国内使用kubeadm搭建k8s集群》,搭建一个基于coreos的k8s集群。

集群信息如下:

  • master: k8s-master01 192.168.56.80
  • minion: k8s-minion01 192.168.56.81
  • minion: k8s-minion02 192.168.56.82

0.2 启动测试服务

以下使用echoserver作为测试服务。

# kubectl run echoserver --image=k8s.gcr.io/echoserver:1.4
# kubectl expose deploy echoserver --port=8080

如果镜像进行无法下载,可使用以下命令手动下载:

# cd ~
# git clone https://github.com/lprincewhn/googlecontainers.git
# bash googlecontainers/get_echoserver.sh

1. 安装负载均衡器

在裸机安装k8s的环境中,没有公有云提供的LoadBalance服务,因此需要自己创建一个LoadBalance作为前端的负载均衡器。

本文使用metallb作为这个负载均衡器,其相关介绍可参考官网: https://metallb.universe.tf/

# curl -o metallb.yaml -ssL https://raw.githubusercontent.com/google/metallb/v0.7.3/manifests/metallb.yaml
# kubectl apply -f metallb.yaml
# cat > metallb-config.yaml <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 192.168.56.90-192.168.56.99
EOF
# kubectl apply -f metallb-config.yaml

负载均衡器主要提供两个功能:

  1. 分配一个可供外部访问的IP给LoadBalancer类型的service。

    metallb该IP地址池使用ConfigMap中的data.config.address-pools.addresses参数定义,每创建一个LoadBalancer类型的service时都从该池中分配IP。该参数应为可访问k8s集群的外部IP。一般可设为和集群网络同网段的一段IP。

  2. 将外部请求转发到实际宿主机上。

    此时metallb是一个工作在二层的负载均衡器,通过ARP来对外部请求进行路由。如:当外部访问192.168.56.90这个地址的时候,metallb将会应答对192.168.56.90这个IP的ARP查询请求,返回优先级最高的宿主机的mac地址,从而使得后续的IP包被发到选中的宿主机上。然后由宿主机上的kube-proxy根据service定义转发到相应pod端口。

在公有云环境中,这两个功能均由的cloud-provider来实现。k8s官方文档中支持的的cloud-provider包括:

  • AWS
  • Azure
  • CloudStack
  • GCE
  • OpenStack
  • OVirt
  • Photon
  • VSphere
  • IBM Cloud Kubernetes Service

可见国内各大公有云厂商并不包含在内,因此如果要把自己的k8s集群部署到阿里云上,需要额外安装阿里云的cloud-provider,否则无法使用公有云提供的云磁盘,SLB等功能。

2. 创建IngressController

IngressController并不是k8s的资源类型,其本质是一个提供路由转发功能的前端或者边缘服务。其可以有不同的实现方式。以nginx的实现为例,nginx-ingress的核心实际是一个LoadBalancer类型侦听80和443端口的service和其关联实际进行转发功能的pod。

以下指令将安装并启动nginx-ingress:

# helm install stable/nginx-ingress --name ic01 --set rbac.create=true

启动后,可看到nginx-ingress实际上包括两个服务:

  • nginx-ingress-controller, 这是一个LoadBalancer类型的服务,其关联的pod负责根据用户创建的Ingress对象将请求转发到合适的后端服务。
  • nginx–default-backend, 这是一个默认的后端服务,当没有合适的Ingress匹配时,将有这个后端服务关联的pod进行处理。
# kubectl get svc
NAME                                  TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                      AGE
echoserver                            ClusterIP      10.100.16.226    <none>          8080/TCP                     3s
kubernetes                            ClusterIP      10.96.0.1        <none>          443/TCP                      8d
nginx-nginx-ingress-controller        LoadBalancer   10.110.150.173   192.168.56.90   80:31924/TCP,443:31021/TCP   1h
nginx-nginx-ingress-default-backend   ClusterIP      10.98.158.64     <none>          80/TCP                       1h

以上输出中的echoserver是实际的业务提供者,也是nginx-ingress-controller的后端服务,其类型一般是ClusterIP,但也可以为NodePort甚至LoadBalancer,这三种不同的类型该服务的访问方法如下:

  • ClusterIP,此时该服务无法直接被外部访问,必须创建合适的Ingress策略,通过路由转发服务nginx-ingress-controller中的pod进行转发。而nginx-ingress-controller因为本身是一个LoadBalancer的服务,也有三种访问方式:
    • ClusterIP: 在集群内部通过Cluster IP和实际端口,即http://10.110.150.173:8080
    • NodePort: 集群内部或外部均可通过宿主机IP和分配的主机端口访问,即http://192.168.56.81:31924或http://192.168.56.82:31924
    • LoadBalancer, 集群内部或外部均可通过负载均衡器分配的IP和其工作端口80访问,即http://192.168.56.90
  • NodePort,此时服务的端口被映射到宿主机的主机端口,除了以上方法外,还可以通过宿主机IP和分配的主机端口访问,如http://192.168.56.81:32063或http://192.168.56.82:32063
  • LoadBalancer,此时服务和nginx-ingress-controller一样被注册到负载均衡器,除了以上两种方法外,还可以通过负载均衡器分配的ip和服务本身的工作端口8080访问,如http://192.168.56.91:8080

后端服务设为NodePort或者LoadBalancer的情况只是为了说明原理,这样配置实际上是把后端服务暴露,在有外部负载均衡器的环境中一般不会这样使用。

更新于

本文遵守 CC-BY-NC-4.0 许可协议。

Creative Commons License

欢迎转载,转载需注明出处,且禁止用于商业目的。

上篇ssh的代理和端口转发机制介绍
下篇使用helm部署k8s应用