k8s集群使用pod来执行任务和提供服务,但是直接使用pod用作服务提供者有以下缺点:
1、pod数量太多且同类pod存在多个副本时,无法做到负载均衡,需要额外的负载均衡器。
2、pod可能会由于种种原因销毁或者重启,pod的ip一般由cni插件动态分配,每次销毁重建都会从podCIDR中(kubectl describe node可以查看当前集群中为pod分配的ip段)分配一个新的ip。
综上,需要为backend pod提供一种服务代理来解决以上问题。
这时就不得不提下service资源,service的特性完美的解决了pod提供服务时的两个缺点。service是一种虚拟的k8s资源对象,这里虚拟指的是service实例不占用cpu和内存资源。service通过label来绑定需要代理的backend pod,并提供虚拟的ip和端口(其实质是通过kube-proxy创建的iptables nat链路来实现的,可通过kube-proxy特性了解详情)作为pod副本流量入口。
此时又出现新的问题,service的虚拟ip(clusterIP)只能提供给使用,无法对外提供服务,nodeport可以通过nodeip暴露外界访问,但如果service数量增多,需要占用node的多个端口资源(service存在clusterIP(默认),nodePort、externalName、loadbalance四种模式,externalName和loadbalance需要引入额外的服务和负载均衡器,不在本次讨论范围内。)。如何解决对外暴露服务问题,这需要今天的主角:ingress,ingress 是k8s的扩展资源(不提供controller实现,需要手动安装)。
下面开始ingress controller的安装。
坑1(版本匹配问题):安装ingress congtroller时,先确定k8s集群的版本(kubectl version确定版本),因为k8s v1.19版本中Ingress资源规范从v1beta1版本升级至稳定的v1版本,apigroup也从extensions更新到networking.k8s.io中,如果版本不匹配,会造成controller watch不到ingress 变化,造成controller中nginx 规则无法更新。
可以从页面:https://github.com/kubernetes/ingress-nginx 下载ingress-nginx,里边由详细的k8s和controller的版本支持信息。
坑2(hostNetwork 配置问题):安装ingress-nginx-admission-patch和ingress-nginx-admission-create时失败:报"msg":“error getting secret”,需要在job的spec.template.spec下配置hostNetwork:true,然后重新安装。(暂未找到什么原因)
坑3(backend 服务 service和pod namespace必须一致):ingress 的backend service,service和代理的pod必须在同一个namespace下,不然网络不通(endpoint controller在生成service对应endpoint时,需要获取label绑定的pod来生成endpoint的subset,此时watch的service所在namespace的pod,跨namespace下,endpoint对应的subnet为空)
坑4(访问ingress入口报404):如果通过ingress controller暴露的service对负载服务进行访问,总是报404,此时ingress service、ingress controller、backend service 、backend pod统统正常且网络可达,可以查看下controller中nginx.conf中是否产生了ingress 定义的规则,如果不存在,则表示ingress规则未生效,ingress定义规则有问题。如果存在,则表示ingress已生效。如果使用curl指令验证,切记在请求头中设置Host对象,Host对象为nginx.conf中ingress规则生成的配置server{
server_name : aaa.com
}中的server_name
例:curl -H “Host:aaa.com” …
坑5 (ingress rules中path 会带到backend):ingress中定义的rules,默认情况下是访问ingress service定义的path,但经ingress-controller转发后会带到backend,即访问backend中的url也带path,如果需要避免这种情况,需要在metadata中配置:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: ${new_path}
这样,controller转发后的url会使用${new_path}。
ingress controller镜像问题,可以使用registry.lank8s.cn替换registry.k8s.io,其他不用改动。