将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:

www.wysite.com

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即可。

发表评论

邮箱地址不会被公开。 必填项已用*标注