理解Kubernetes中的NginxIngress
Ingress有什么作用?管理集群外部对集群内服务的访问,典型如HTTP请求。它可以提供负载均衡、SSL终结和基于域名的虚拟主机访问。我们发现这些功能都比较容易实现,将集群内的服务暴露到集群外部,可以使用NodePort类型的Service,负载均衡可以使用HAProxy来实现,SSL终结功能部署七层反向代理就可以,基于域名的虚拟主机访问也同样比较容易实现,那为什么Kubernetes要引入IngressAPI对象呢?
Ingress的潜力
Ingress的功能如开篇所述,可以使用其他技术实现,但是实际在操作过程中发现并没那么简单。在没有Ingress参与的情况下,将集群内服务暴露到集群外使用NodePort类型的Service,那需要给每个微服务都创建此类Service,当服务较多时,排障将非常复杂,协调主机端口使用也会让人抓狂。在集群外部署Nginx或Apache,SSL终结和基于域名的虚拟主机访问可以实现,但是服务发现和配置管理又是个挑战,集群外的Nginx和Apache感知不到集群中服务的增加和减少,需要人为配置,这对集群管理员来说,简直是个噩梦。幸好,Ingress来了。
安装
安装服务到Kubernetes一般都比较容易,使用kubectlapply后面跟上yaml文件即可。当然也可以使用Kubernetes的包管理工具Helm。nginxingress根据环境,可选有三种安装方法:使用helmkubectlapplyyamlfiles在minikube或MicroK8s中,插件方式安装
笔者使用这篇文章介绍的方法安装Kubernetes集群,这里选用第二种方式安装nginxingress,执行下面命令(因版本更新较快,实际部署请参考官网):kubectlapplyfhttps:raw。githubusercontent。comkubernetesingressnginxcontrollerv1。1。1deploystaticproviderbaremetaldeploy。yaml
安装会从k8s。gcr。io镜像仓拉取镜像,如果拉取失败可选择阿里云或其他。
查看增加的集群资源,〔rootmaster〕kubectlgetallningressnginxNAMEREADYSTATUSRESTARTSAGEpodingressnginxadmissioncreate7k9kt01Completed014dpodingressnginxadmissionpatch5bcmq01Completed114dpodingressnginxcontroller687578654bf92bq11Running3(42dago)14dNAMETYPECLUSTERIPEXTERNALIPPORT(S)AGEserviceingressnginxcontrollerNodePort10。1。70。249none80:30305TCP,443:31330TCP14dserviceingressnginxcontrolleradmissionClusterIP10。1。124。31none443TCP14dNAMEREADYUPTODATEAVAILABLEAGEdeployment。appsingressnginxcontroller111114dNAMEDESIREDCURRENTREADYAGEreplicaset。appsingressnginxcontroller687578654b11114dNAMECOMPLETIONSDURATIONAGEjob。batchingressnginxadmissioncreate115s14djob。batchingressnginxadmissionpatch117s14d
因为集群是自建的,ingressnginxcontroller服务类型为NodePort,后面访问服务需要使用这样的方式:NodeIP3030531330Path
使用
上步操作成功执行后,便可以创建Ingress类型的API对象了,笔者集群中提前部署一Web服务,Service信息如下:〔rootmaster〕kubectlgetsvcNAMETYPECLUSTERIPEXTERNALIPPORT(S)AGEnginxClusterIP10。1。133。186none80TCP14h
创建IngressAPI对象,12apiVersion:networking。k8s。iov13kind:Ingress4metadata:5name:selfnginx6namespace:test7annotations:8nginx。ingress。kubernetes。iorewritetarget:9spec:10ingressClassName:nginx11rules:12host:mynginx。example。com13http:14paths:15path:testpath16pathType:Prefix17backend:18service:19name:nginx20port:21number:80
如果没有将前面安装的nginxingress配置为默认的Ingress,需要加入第10行。否则即使ingress资源提交到APIServer,nginxingresscontroller也没有反应。获取ingressClassName的值,〔rootmaster〕kubectlgetingressclassNAMECONTROLLERPARAMETERSAGEnginxk8s。ioingressnginxnone14d
查看创建的Ingress,〔rootmaster〕kubectlgetingressNAMECLASSHOSTSADDRESSPORTSAGEselfnginxnginxmynginx。example。com192。168。52。13280125m
通过Ingress访问Web服务(如果域名没有解析,修改etchosts文件),〔rootmasternginx〕curlmynginx。example。com:30305testpathhellokubernetes!
原理
NginxIngress的部署和使用不难,最重要是熟悉它的工作原理,这样在遇到问题时才能迅速定位。ingressnginxcontrollerPod里面仅运行一个容器,但是这个容器里面却有多个守护进程,重要的有两个:controller和nginx。进入Pod执行ps命令查看:〔rootmaster〕kubectlexecitingressnginxcontroller687578654bf92bqningressnginxbinbashbash5。1psPIDUSERTIMECOMMAND1wwwdata0:00usrbindumbinitnginxingresscontrollerelectionidingresscontrollerleadercontrollerclassk8s。ioingressnginxconfig7wwwdata11:28nginxingresscontrollerelectionidingresscontrollerleadercontrollerclassk8s。ioingressnginxconfigmapingressnginxingr25wwwdata0:00nginx:masterprocessusrlocalnginxsbinnginxcetcnginxnginx。conf247wwwdata0:01nginx:workerprocess248wwwdata0:00nginx:cachemanagerprocess
Controller是管理者,实现服务发现和自动配置功能,见下图(下载自官网),
nginxingress工作原理
这幅图看起来很复杂,其实用一句话就可以概括:IngressController(即图中的IC)相当于系统管理员,需求者提交Ingress资源到APIServer,IC从APIServer获取Ingress资源,因为IC既了解Ingress资源又了解Nginx,它完成Ingress的翻译,随即更新Nginx的配置文件,并执行reload操作,核心逻辑就是这样。
上面我们给nginxService创建了Ingress资源,访问路径配置为testpath,现在进入ingressnginxcontrollerPod看下Nginx的配置文件:etcnginxnginx。conf。
关于虚拟主机mynginx。example。com的配置有200多行,删掉无关的,startservermynginx。example。comserver{servernamemynginx。example。com;listen80;listen443sslhttp2;setproxyupstreamname;sslcertificatebyluablock{certificate。call()}locationtestpath{setnamespacetest;setingressnameselfnginx;setservicenamenginx;setserviceport80;setlocationpathtestpath;setglobalratelimitexceedingn;。。。。。。setbalancerewmascore1;setproxyupstreamnametestnginx80;setproxyhostproxyupstreamname;setpassaccessschemescheme;。。。。。。rewrite(?i)testpathbreak;proxypasshttp:upstreambalancer;proxyredirectoff;}location{setnamespacetest;setingressnameselfnginx;setservicename;setserviceport;setlocationpath;setglobalratelimitexceedingn;。。。。。。proxypasshttp:upstreambalancer;proxyredirectoff;}}endservermynginx。example。com
从配置文件中可以看到发往testpath的请求完成一次跳转后最终发送给upstreambalancer,其在Nginx配置文件中的定义如下,upstreamupstreambalancer{Attention!!!Wenolongercreateupstreamsectionforeverybackend。BackendsarehandleddynamicallyusingLua。Ifyouwouldliketodebugandseewhatbackendsingressnginxhasinitsmemoryyoucaninstallourkubectlpluginhttps:kubernetes。github。ioingressnginxkubectlplugin。Onceyouhavethepluginyoucanusekubectlingressnginxbackendscommandtoinspectcurrentbackends。server0。0。0。1;placeholderbalancerbyluablock{balancer。balance()}keepalive320;keepalivetimeout60s;keepaliverequests10000;}
因Nginx配置文件严重依赖Lua,这里看到的信息不直观。为了看到后端服务,按照注释,为kubectl安装ingressnginx插件。在前面Nginx配置文件有下面一行:
setproxyupstreamnametestnginx80;
指出域名mynginx。example。com的backend名为testnginx80。查看Ingress的backends(省略无关行)。〔rootmaster〕kubectlingressnginxbackendsningressnginx〔{name:testnginx80,service:{metadata:{creationTimestamp:null},spec:{ports:〔{name:http,protocol:TCP,port:80,targetPort:80}〕,selector:{app:nginx},clusterIP:10。1。133。186,clusterIPs:〔10。1。133。186〕,type:ClusterIP,sessionAffinity:None,ipFamilies:〔IPv4〕,ipFamilyPolicy:SingleStack,internalTrafficPolicy:Cluster},status:{loadBalancer:{}}},port:80,sslPassthrough:false,endpoints:〔{address:10。244。1。26,port:80}〕,sessionAffinityConfig:{name:,mode:,cookieSessionAffinity:{name:}},upstreamHashByConfig:{upstreamhashbysubsetsize:3},noServer:false,trafficShapingPolicy:{weight:0,weightTotal:0,header:,headerValue:,headerPattern:,cookie:}},。。。。。。〕
从输出中可以看到后端其实就是名为nginx的Service对应的Endpoints,它的IP是10。244。1。26,〔rootmaster〕kbgetendpointsNAMEENDPOINTSAGEnginx10。244。1。26:8019h
这里需要强调一点,NginxIngress并不将流量转发给nginxservice,而是直接转发到后端的Pods,转发策略也完全由IngressController来决定。这样不仅减少了一次DNAT,也能实现更丰富的负载均衡策略。Ingress资源中出现的Service对象只是为了选择后端的Endpoints。
总结
文章对NginxIngress做了介绍,Kubernetes中可以选择的Ingress有很多,读者可以根据需要选择。
希望这篇文章能帮到正在努力的你,欢迎点赞、评论!