4. 基于k8s的ingress实战
到现在为止我们的服务都是跑在集群内部的,为了让集群外部也能访问,那么我们需要让服务外化,但是因为minikube在mac上是网络不通的,所以我们我们直接就在minikube环境中测试(minikube ssh
进入即可)。
1. 创建Pod的service
创建pod的service,类型是NodePort
,我们看下svc.yaml:
apiVersion: v1 kind: Service metadata: name: k8sdemo-svc # service的服务名称 spec: ports: - name: k8sdemo-svc port: 8000 # service的端口 targetPort: 60001 # 容器服务的端口 selector: app: k8sdemo # 关联pod type: NodePort # 对外暴露
创建完成之后,我们可以kubectl get svc
查看是否创建成功
通过上图可以知道service是创建成功的,接下来看下架构图:
随便拿一台机器的公网IP+NodePort就可以访问了,我们这里可以在minikube中验证下:http://$(minikube ip):NodePort
docker@minikube:~$ curl -X POST http://192.168.49.2:30143/hello -d '{"name": "fromGW"}' {"message":"Hello fromGW from 172.17.0.16:50009"}
可以看到是没有问题的。我们从图中可以看出service是pod的更高一层抽象,负责服务发现和负载均衡,当某个Pod挂掉的时候,service会发现这个问题然后把请求打到别的Pod上。同样当在创建一个带有相同标签的Pod的时候,它会自动加入到service中,然后service会把流量按照某种负载均衡算法分发到各个Pod中。
2. 创建ingress
先安装ingress-nginx,我们先把ingress-nginx下载到本地,然后把镜像地址替换下,防止下载速度慢。
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.0/deploy/static/provider/baremetal/deploy.yaml sed -i 's@k8s.gcr.io/ingress-nginx/controller:v1.0.0\(.*\)@cnsre/ingress-nginx-controller:v1.0.0@' deploy.yaml sed -i 's@k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0\(.*\)$@cnsre/ingress-nginx-kube-webhook-certgen:v1.0@' deploy.yaml
通过kubectl apply -f deploy.yaml
安装。
可以看下是否安装成功:
目前来看是安装成功的。
接下来创建我们自己的ingress,这个ingress实现的功能就是路径匹配,重写以及限流,这个yam文件内容如下,ingress.yaml:
apiVersion: networking.k8s.io/v1 kind: Ingress # ingress对象 metadata: name: k8sdemo-ingress-prefix # 验证前缀匹配的 annotations: kubernetes.io/ingress.class: "nginx" spec: rules: - host: hi.k8sdemo.com # 域名 http: paths: - path: "/hello" # 前缀匹配 pathType: Prefix backend: service: name: k8sdemo-svc port: number: 8000 # service的端口 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: k8sdemo-ingress-rewrite # 这个ingress是关于验证重写的 annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/rewrite-target: /$2 # 重写注解 spec: rules: - host: hello.k8sdemo.com http: paths: - pathType: Prefix path: "/api(/|$)(.*)" # 把请求会转给下面的服务,下面的服务一定要能处理这个路径,不能处理就是404 backend: service: name: k8sdemo-svc # 如果是/api/hello 去掉前缀api 用/hello访问服务 网关一般这么搞 port: number: 8000 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: k8sdemo-ingress-limit-rate annotations: nginx.ingress.kubernetes.io/limit-rps: "1" # rps:每秒多少请求 超过之后就报错 https status: 503 spec: ingressClassName: nginx rules: - host: hi.k8sdemo.com http: paths: - pathType: Exact # 精确匹配 path: "/hello" # 针对这个路径限流 backend: service: name: k8sdemo-svc port: number: 8000
通过kubectl apply -f deploy.yaml
创建。可以查看下是否创建成功:
可以看到这三个ingress绑定了两个host,接下来申请域名绑定ingress的ip地址,即上图中的192.168.49.2。但因为我们是minikube本地测试,所以绑定hosts就可以了。修改/etc/hosts
:
192.168.49.2 hello.k8sdemo.com 192.168.49.2 hi.k8sdemo.com
保存之后我们就可以验证测试了。大致架构图就是:
3. 验证ingress
我们再次看下ingress的svc对外暴露的端口是:
可以看到是31721,接下来我们通过域名+端口来访问后端服务。
- 首先验证通过正常路径匹配访问
docker@minikube:~$ curl -X POST http://hi.k8sdemo.com:31721/hello -d '{"name": "fromGW"}' {"message":"Hello fromGW from 172.17.0.16:50009"}
发现是成功的。
- 验证路径重写
docker@minikube:~$ curl -X POST http://hello.k8sdemo.com:31721/api/hello -d '{"name": "fromGW"}' {"message":"Hello fromGW from 172.17.0.16:50009"}
发现是成功的。
4. ingress限流
docker@minikube:~$ curl -X POST http://hi.k8sdemo.com:31721/hello -d '{"name": "fromGW"}' <html> <head><title>503 Service Temporarily Unavailable</title></head> <body> <center><h1>503 Service Temporarily Unavailable</h1></center> <hr><center>nginx</center> </body> </html>
当我们一秒请求的/hello
次数大于1的时候报错,nginx返回503,这样就验证了我们的ingress的限流功能。
5. 总结
本小节算是重点,我们要了解ingress如何暴露服务,如何重写路径以及如何限流等。路径重写很重要,比如接口地址是:http://example.gateway.com/user-center/userinfo
和http://example.gateway.com/user-center/userprofile
,网关地址是http://example.gateway.com
,路由到后端服务是userinfo
,那么在网关层为了区分我们的服务,会统一加一层user-center
,这样就可以区分不同业务了,但是user-center
不是我们想要的,我们用它只是区分业务,所以需要在ingress层做下路径重写,这样到后端的服务就没有了user-center
了。
还有基于ingress的限流功能也非常简单,大家可以尝试用起来。
参考: