k8s ingress概念和实践
什么是Ingress
Ingress 是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP/HTTPS
该特性从1.19版本开始作为stable状态进行发布
Ingress 公开从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。
如下图将所有流量都发送到同一 Service 的简单 Ingress 示例:
Ingress 不会公开任意端口或协议。 将 HTTP 和 HTTPS 以外的服务公开到 Internet 时,通常使用 Service.Type=NodePort或 Service.Type=LoadBalancer类型的 Service或者直接共享主机网络。
Ingress控制器
为了让 Ingress 资源工作,集群必须有一个正在运行的 Ingress 控制器。Ingress 控制器 通常负责通过负载均衡器来实现 Ingress,与作为 kube-controller-manager
可执行文件的一部分运行的其他类型的控制器不同, Ingress 控制器不是随集群自动启动的。Kubernetes官方目前支持和维护 AWS、 GCE 和 Nginx Ingress 控制器。
应用场景
金丝雀发布:是一种基于流量比例的发布策略,部署一个或者一小批新版本的服务,将少量(比如1%)的请求引流到新版本,逐步调大流量比重,直到所有用户流量都被切换新版本为止。由于这种模式不是非黑即白,所以又称为灰度发布。
那么这里就有一个问题,就是如何把生产流量进行一个转发?
通常呢,开发者会在接口请求的流量上做一个标记,如某些主机接收到应用流量后,对Header进行一个新增标记,来说明这个流量是用于新版本处理的。当这个流量进入k8s集群时,那么会被ingress定义的规则进行处理,将流量转发到新版本的业务的service,再由service转发到pod上面去。
金丝雀(灰度)发布实践
环境准备
nginx-controller安装
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.5.1/deploy/static/provider/cloud/deploy.yaml
启用deployment中的ingress-nginx-controller的容器为共享主机网络,即设置hostNetwork为true
deployments.spec.template.spec.hostNetwork
查看nginx-controller所在的主机
$ kubectl get pod -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-admission-create-s4wn5 0/1 Completed 0 3d14h 10.244.1.104 k8s-node1-ubantu <none> <none>
ingress-nginx-admission-patch-v5vh6 0/1 Completed 1 3d14h 10.244.1.105 k8s-node1-ubantu <none> <none>
ingress-nginx-controller-54cdc69c44-5tr2m 1/1 Running 0 2d14h 192.168.31.42 k8s-node2-ubantu <none> <none>
创建测试工作空间
为了方便演示和测试,避免干扰其他命名空间的资源,我们创建一个ingress-test的命名空间来进行测试,并且切换kubectl config的默认操作命名空间
kubectl create ns ingress-test
kubectl config set-context --current --namespace=ingress-test
实践步骤
-
创建两个应用,模拟新老应用版本
kubectl create deployment old-app --image=nginx:1.19.0 kubectl create deployment new-app --image=nginx
通过pod network来验证两个app的访问
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES new-app-69d99d595-vq7lf 1/1 Running 0 54s 10.244.2.72 k8s-node2-ubantu <none> <none> old-app-788c89d6c7-q2qnp 1/1 Running 0 61s 10.244.2.71 k8s-node2-ubantu <none> <none> $ curl 10.244.2.71/version <html> <head><title>404 Not Found</title></head> <body> <center><h1>404 Not Found</h1></center> <hr><center>nginx/1.19.0</center> </body> </html> $ curl 10.244.2.72/version <html> <head><title>404 Not Found</title></head> <body> <center><h1>404 Not Found</h1></center> <hr><center>nginx/1.23.3</center> </body> </html>
可以看到两个新老应用的nginx版本是不一致的,新版本为1.23.3,而老的版本为1.19.0
-
创建两个service,来访问新老应用
kubectl expose deployment old-app --port=80 --target-port=80 kubectl expose deployment new-app --port=80 --target-port=80
通过service网路来验证两个app的访问
kubectl get svc -o wide
$ kubectl get svc -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR new-app ClusterIP 10.99.150.77 <none> 80/TCP 70s app=new-app old-app ClusterIP 10.96.98.15 <none> 80/TCP 79s app=old-app $ curl 10.96.98.15/version <html> <head><title>404 Not Found</title></head> <body> <center><h1>404 Not Found</h1></center> <hr><center>nginx/1.19.0</center> </body> </html> $ curl 10.99.150.77/version <html> <head><title>404 Not Found</title></head> <body> <center><h1>404 Not Found</h1></center> <hr><center>nginx/1.23.3</center> </body> </html>
-
创建ingress,设定流量转发规则
kubectl create ingress old-app --rule=k8s-node2-ubantu/*=old-app:80 --class=nginx kubectl create ingress new-app --rule=k8s-node2-ubantu/*=new-app:80 --annotation=nginx.ingress.kubernetes.io/canary="true" --annotation=nginx.ingress.kubernetes.io/canary-by-header="app" --annotation=nginx.ingress.kubernetes.io/canary-by-header-value="new" --class=nginx
-
验证访问
正常流量访问
$ curl http://k8s-node2-ubantu/version <html> <head><title>404 Not Found</title></head> <body> <center><h1>404 Not Found</h1></center> <hr><center>nginx/1.19.0</center> </body> </html>
新版本流量访问,即在http请求头加入app=new,那么这部分的流量就会到new-app的应用上进行处理
$ curl -H 'app:new' http://k8s-node2-ubantu/version <html> <head><title>404 Not Found</title></head> <body> <center><h1>404 Not Found</h1></center> <hr><center>nginx/1.23.3</center> </body> </html>
nginx-controller原理
nginx-controller通过监听k8s集群ingress对象的创建/修改情况,同步更新内部的nginx的配置文件,来达到负载均衡/虚拟主机的能力,我们可以通过查看ingress-nginx-controller的容器日志来诊断流量分发的相关问题
kubectl logs -n ingress-nginx ingress-nginx-controller-54cdc69c44-5tr2m
日志示例
I0115 04:06:37.459568 6 admission.go:149] processed ingress via admission controller {testedIngressLength:4 testedIngressTime:0.023s renderingIngressLength:4 renderingIngressTime:0s admissionTime:40.9kBs testedConfigurationSize:0.023} I0115 04:06:37.459591 6 main.go:100] "successfully validated configuration, accepting" ingress="ingress-test/old-app" I0115 04:06:37.462976 6 store.go:430] "Found valid IngressClass" ingress="ingress-test/old-app" ingressclass="nginx" I0115 04:06:37.463137 6 event.go:285] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"ingress-test", Name:"old-app", UID:"1a3a9c15-a7a9-4914-b4ac-d0821486df11", APIVersion:"networking.k8s.io/v1", ResourceVersion:"1935618", FieldPath:""}): type: 'Normal' reason: 'Sync' Scheduled for sync I0115 04:06:37.463244 6 controller.go:168] "Configuration changes detected, backend reload required" I0115 04:06:37.512904 6 controller.go:185] "Backend successfully reloaded"
查看nginx-controller的nginx配置文件
kubectl exec -n ingress-nginx ingress-nginx-controller-54cdc69c44-5tr2m -- cat nginx.conf