在k8s中使用Ingress进行服务访问和负载均衡
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
负载均衡器主要提供两个功能:
-
分配一个可供外部访问的IP给LoadBalancer类型的service。
metallb该IP地址池使用ConfigMap中的data.config.address-pools.addresses参数定义,每创建一个LoadBalancer类型的service时都从该池中分配IP。该参数应为可访问k8s集群的外部IP。一般可设为和集群网络同网段的一段IP。
-
将外部请求转发到实际宿主机上。
此时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的情况只是为了说明原理,这样配置实际上是把后端服务暴露,在有外部负载均衡器的环境中一般不会这样使用。