将Service暴露的方法中,有一种叫做LoadBalancer的Service,在Cloud Provider中创建一个对应的负载均衡服务
但是,为每一个Service服务维护一个负载均衡服务,浪费成本,作为用户,更希望看到Kubenretes有一个全局的负载均衡器,可以根据URL,转发给不同的Service后端,这种全局的,代理不同的Serivce的负载均衡服务,就是Kubernetes的Ingress服务,Ingress就是Service的Service
我们举个例子,我们将一个站点的不同的后缀分为不同的系统,比如请求 https://cafe.example.com.我们需要根据后一个来判断转发给不同的Deployment服务,比如https://cafe.example.com/coffee,对应的就是咖啡系统,https://cafe.example.com/tea,对应着就是茶水点餐系统.
那么现在,如何使用Kubernetes的Ingress来创建一个统一的负载均衡器,从而实现不同的Deployment的服务负责呢?
这样,我们就先通过Ingress来进行描述Service
apiVersion: extensions/v1beta1
kind: Ingress metadata: name: cafe-ingress spec: tls: – hosts: – cafe.example.com secretName: cafe-secret rules: – host: cafe.example.com http: paths: – path: /tea backend: serviceName: tea-svc servicePort: 80 – path: /coffee backend: serviceName: coffee-svc servicePort: 80 |
上面的yaml中,我们定义了一个type为Ingress的api对象,然后在rules字段中,定义了host地址,
这就是定义了这个Ingress的入口,然后在这个Ingress中,含有了更加详细的path字段的定义,分别对应的了两个Deployment的Service
Ingress对象,其实就是kubernetes项目对反向代理的抽象,这个代理服务对应的转发规则,就是IngressRule,具体的就是在每个IngressRule中,有一个host字段作为这条IngressRule的入口,然后有一系列path字段来声明具体的转发策略,其实跟Nginx,HAproxy等项目配置写法一致
有了这个Ingress这样的一个统一的抽象,Kubernetes的用户无须关心Ingress的具体细节了
而实现API对象的,是具体的Ingress Controller,这一点可以再社区中直接获取,这个Ingress Controller会根据定义的Ingress能力,提供代理能力,常见的代理项目,有Nginx HAProxy,Envoy,都有对应的Ingress Controller
接下来,就会以常用的Nginx Ingress Controller为例,在前面用kubeadm部署的Bare-metal环境中,实践一下Ingress机制
我们先获取一个Nginx Ingress Controller
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
在具体的yaml文件中,是Nginx维护的Ingress Controller的定义,内容如下
kind: ConfigMap
apiVersion: v1 metadata: name: nginx-configuration namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx — apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-ingress-controller namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx template: metadata: labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx annotations: … spec: serviceAccountName: nginx-ingress-serviceaccount containers: – name: nginx-ingress-controller image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.20.0 args: – /nginx-ingress-controller – –configmap=$(POD_NAMESPACE)/nginx-configuration – –publish-service=$(POD_NAMESPACE)/ingress-nginx – –annotations-prefix=nginx.ingress.kubernetes.io securityContext: capabilities: drop: – ALL add: – NET_BIND_SERVICE # www-data -> 33 runAsUser: 33 env: – name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name – name: POD_NAMESPACE – name: http valueFrom: fieldRef: fieldPath: metadata.namespace ports: – name: http containerPort: 80 – name: https containerPort: 443 |
我们使用了一个nginx-ingress-controller镜像的Pod,这个Pod启动命令需要拿到这个Namespace作为参数,这个通过Download API拿到的,就是Pod的env字段定义
这个Pod本身,就是监听Ingress对象的变化和后端Service的变化的控制器,一个新的Ingress对象交由用户创建后,nginx-ingress-controller就会根据Ingress对象中定义的内容,生成一个Nginx配置文件,并使用这个配置文件启动一个Nginx服务
一旦这个Ingress对象被更新,nginx-ingress-controller就会更新这个配置文件
而且,还可以通过kubernetes中的ConfigMap对象进行Nginx的定义,这个ConfigMap的名字,需要以参数的方式传递给nginx-ingress-controller,这个configmap的字段,会被合并到最后的Nginx配置文件中
一个Nginx Ingress Controller提供的服务,是一个可以根据Ingress对象和被代理的Service的变化,自动更新的Nginx负载均衡器
然后,我们将对应的Ningx进行暴露出去,这就需要创建一个Service进行Nginx服务的Pod进行代理
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml
具体的Service,是一个NodePort类型的Service
apiVersion: v1
kind: Service metadata: name: ingress-nginx namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: type: NodePort ports: – name: http port: 80 targetPort: 80 protocol: TCP – name: https port: 443 targetPort: 443 protocol: TCP selector: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx |
将ingress-nginx标签的Pod的80端口和433端口暴露出去的
这样之后,就能获取到这个Service的入口,就是宿主机的地址和NodePort的端口
$ kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx NodePort 10.105.72.96 <none> 80:30044/TCP,443:31453/TCP 3h |
那么,当Ingress Controller和对应的Service部署完成,就可以直接使用了
然后创建好对应的SSL证书和秘钥方便Secret对象使用
就可以创建对应的Ingress对象了
$ kubectl create -f cafe-ingress.yaml
对应的Ingress对象的信息如下
$ kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE cafe-ingress cafe.example.com 80, 443 2h $ kubectl describe ingress cafe-ingress Name: cafe-ingress Namespace: default Address: Default backend: default-http-backend:80 (<none>) TLS: cafe-secret terminates cafe.example.com Rules: Host Path Backends —- —- ——– cafe.example.com /tea tea-svc:80 (<none>) /coffee coffee-svc:80 (<none>) Annotations: Events: Type Reason Age From Message —- —— —- —- ——- Normal CREATE 4m nginx-ingress-controller Ingress default/cafe-ingress |
这个Ingress的核心部分,就是Rules字段,我们定义了Host是cafe.example.com.然后有两个转发规则,分别转发给tea-sva和coffee-svc
如果访问/coffee的时候,应该是coffee这个Deployment负责响应请求,这样就说明已经成功的转发给了对应的后端Service了,这就是Kubernetes中Ingress的设计思想和使用方法了
而且,为了避免没有匹配任何一条IngressRule,返回Nginx原生的404页面,可以通过Pod命令中-default-backend-service参数,设置一条默认的规则,让匹配失败的请求,转到一个特定的Service,然后在这个特定的Service中,返回自定义的404页面了
本章中,我们详细的讲解了Ingress这个概念这Kubernets的定义,其实就是反向代理的抽象,Ingress弥补了Service只能在四层工作的缺憾
而且有了Ingress抽象之后,就可以根据自己的需求来自由选择Ingress Controller,比如,应用对代理服务中断敏感,可以选择Traefik这样的热加载的Ingress Controller来实现
而且,支持自定义一个Ingress Controller,是开源项目的一个重要特点
那么课后题是,如果访问www.wysite.com 和 forums.mysite.com 时候,分别访问不同的Service,那么这个Ingress如何定义
apiVersion: extensions/v1beta1
kind: Ingress metadata: name: myIngress spec: – hosts: http: …. -hosts: – forums.mysite.com |
请问ingress里配置的域名访问地址,那么集群外部怎么根据域名访问到k8s的服务呢?
比如基于nginx的ingress controller部署在一个pod中,这个pod使用hostnetwork监听宿主机的端口80/443,这里需要配置域名解析到ingress controoler pod所部署的节点的ip,当client通过域名发起请求时,请求到达部署ingree controller的节点,由于请求已经到达k8s集群中,直接将请求转发到对应的pod ip即可。