目录
1、Deployment+LoadBalancer模式的service
2、Deployment+NodePort模式的service
3、DaemonSet+HostNetwork(+nodeSelector)
????????当你在Kubernetes集群中运行多个应用程序时,每个应用程序都有自己的服务。为了让外部用户访问这些应用程序,就好像他们访问网站一样,我们需要一种方法来管理流量的分配和路由。这就是Ingress的作用。想象一下,您的Kubernetes集群就像一个大型的公寓楼,每个公寓是一个应用程序。而Ingress就是大楼的大门,允许外部人员进入。大门上有一个保安,他会检查来访者的目的地,并根据他们的要求告诉他们去哪里。Ingress就是这个保安,他知道应该将来自某个网址的请求引导到特定的应用程序。这可以通过不同的规则来实现,就像保安知道哪个公寓对应哪个房间号一样。这样,当人们访问不同的网址时,保安就会将他们引导到正确的应用程序。要使保安工作,您需要在大门口放置一个标志,告诉保安如何引导来访者。在Kubernetes中,这个标志就是Ingress对象。而控制这个保安的是Ingress Controller,它就像是保安的老板,负责确保保安按照标志上的规则来引导人们。总而言之,Ingress就是一种管理外部流量的方式,它允许您告诉集群如何将请求引导到正确的应用程序,就像大门保安将人们引导到正确的公寓一样。这使得外部用户能够方便地访问您在Kubernetes中运行的不同应用程序。
前言:K8S暴露服务的方式目前有三种:LoadBlancer Service、NodePort Service、Ingress.
简单说,就是一个代理,可以根据配置转发请求到指定的服务器上。
????????由于k8s集群拥有强大的副本控制能力,Pod随时可能从一个节点上呗驱逐到另一个节点上,或者直接销毁再来一个新的,然后伴随着Pod的销毁和重生,Pod的IP等信息不断地在改变,此时使用k8s提供的Service机制可以解决这一问题,Service通过标签选定指定的Pod作为后端服务,并监听这些Pod的变化。在对外暴露服务时,使用Service的NodePort是一个方法
问题1:端口如何管理
????????当需要对外暴露端口的服务量比较多的时候,端口管理的问题就会暴露出来,此时的一个处理方案是使用代理服务,(例如Nginx)根据请求信息将请求转发到不通的服务器上
问题2:如何管理转发配置
????????每当有新服务加入,都需要对该服务的配置进行修改,升级,在服务数量逐渐增多后,该配置项目会变得越来越大,手工修改的风险也会逐渐增高,就需要一个工具来简化这一过程,希望可以通过简单的配置动态的生成代理中复杂的配置,最好还可以顺手重新加载配置文件,k8s就提供了这个资源
????????ingress的定义为管理对外服务到集群内服务之间规则的集合,通俗点说就是它定义规则来允许进入集群的请求被转发到集群中对应的服务上,用于实现用域名的方式访问k8s集群内部的应用,ingress能把集群内Service配置成外网能够访问的URL,流量负载均衡,终止SSL,提供基于域名访问的虚拟主机。
那么问题来了,集群内服务想要暴露出去面临着几个问题:
????????众所周知,kubernetes具有强大的副本控制能力,能保证在任意副本(Pod)挂掉时自动从其他机器启动一个新的,还可以动态扩缩容,总之,这个Pod可能在任何时刻出现在任何节点上,也有可能在任何时刻死在任何节点上;那么自然随着Pod的创建和销毁,Pod IP肯定也会动态变化;那如何把这个动态IP暴露出去?这里借助于kubernetes的Service机制,Service可以以标签的形式选定一组带有指定标签的Pod,并监控和自动负载他们的PodIP,那我们只向外暴露Service IP 就行了,这就是NodePort模式,即在每个节点开启一个端口,然后转发到内部的Pod上;如下图
????????采用NodePort的方式暴露服务面临一个坑爹的问题,服务一旦多起来,NodePort在每个节点上开启的端口会及其庞大,而且难以维护;这时候引出的思考问题是 “能不能使用 Nginx 啥的只监听一个端口,比如 80,然后按照域名向后转发?” 这思路很好,简单的实现就是使用 DaemonSet 在每个 node 上监听 80,然后写好规则,因为 Nginx 外面绑定了宿主机 80 端口(就像 NodePort),本身又在集群内,那么向后直接转发到相应 Service IP 就行了,如下图所示
????????从上面的思路,采用 Nginx 似乎已经解决了问题,但是其实这里面有一个很大缺陷:每次有新服务加入怎么改 Nginx 配置?总不能手动改或者来个 Rolling Update 前端 Nginx Pod 吧?这时候 “伟大而又正直勇敢的” Ingress 登场,如果不算上面的 Nginx,Ingress 只有两大组件:Ingress Controller 和 Ingress
????????Ingress 这个玩意,简单的理解就是 你原来要改 Nginx 配置,然后配置各种域名对应哪个 Service,现在把这个动作抽象出来,变成一个 Ingress 对象,你可以用 yml 创建,每次不要去改 Nginx 了,直接改 yml 然后创建/更新就行了;那么问题来了:”Nginx 咋整?”
????????Ingress Controller 这东西就是解决 “Nginx 咋整” 的;Ingress Controoler 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取他,按照他自己模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下,工作流程如下图
1、ingress-controller通过和kubernetes APIServer交互,动态的去感知集群中ingress的规则变化
2、然后读取他,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置
3、再写到nginx-ingress-controller的pod里,这个ingress-controller的pod里运行这一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中
4、然后reload一下 使配置生效。
????????ingress 也是k8s api的标准资源类型之一,它其实就是一组基于DNS名称,或者URL路径把请求转发到指定的service资源的规则,用于将集群外部的请求流量转发到集群内部完成的服务发布。
????????如果要把ingress部署在公有云,那用这种方式比较合适。用Deployment部署igress-controller,创建一个type为LoadBalancer的service关联这组pod。大部分公有云,都会为LoadBalancer的service自动创建一个负载均衡器,通常还绑定了公网地址。只要把域名解析指向改地址,就实现了集群服务的对外暴露。
????????同样用deployment模式部署ingress-controller,并创建对应的服务,但是type为NodePort。这样,ingress就会暴露在集群节点ip的特定端口上。由于nodeport暴露的端口是随机端口,一般会在前面再搭建一套负载均衡器来转发请求。该方式一般用于宿主机是相对固定的环境ip地址不变的场景。
NodePort方式暴露ingress虽然简单方便,但是NodePort多了一层NAT,在请求量级很大时可能对性能会有一定的影响
????????用DaemonSet 结合nodeselector来部署ingress-controller到特定的Node上,然后使用HostNetwork直接把该pod与宿主机node的网络打通,直接使用宿主机的80/443端口就能访问服务。这时,ingress-controller所在的node机器就很类似传统架构的边缘节点,比如机房的入口nginx服务器。该方式整个请求链路最简单,性能相对nodeport模式更好。缺点是由于直接利用宿主机节点的网络和端口,一个node只能部署一个ingress-controller pod。比较适合大并发的生产环境使用。
1、下载 需要的版本,需要考虑兼容性
wget https://get.helm.sh/helm-v3.5.4-linux-amd64.tar.gz
2、解压(tar -zxvf helm-v3.5.4-linux-amd64.tar.gz)
3、在解压目录中找到helm程序,移动到需要的目录中(mv linux-amd64/helm /usr/local/bin/helm)
4、执行完,通过 helm version 查看是否成功
[root@k8s-node-1 bin]# helm version
version.BuildInfo{Version:"v3.12.0", GitCommit:"c9f554d75773799f72ceef38c51210f1842a1dea", GitTreeState:"clean", GoVersion:"go1.20.3"}
二、helm下载ingress
1、添加helm的ingress仓库
[root@k8s-node-1 bin]#
[root@k8s-node-1 bin]# helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
"ingress-nginx" has been added to your repositories
删除仓库镜像
[root@k8s-master-1 ingress-nginx]# helm repo remove ingress-nginx
"ingress-nginx" has been removed from your repositories
[root@k8s-node-1 bin]#
查看已经有的仓库
[root@k8s-node-1 bin]# helm repo list
NAME URL
ingress-nginx https://kubernetes.github.io/ingress-nginx
[root@k8s-node-1 bin]#
使用search 看下ingress包
[root@k8s-node-1 bin]# helm search repo ingress-nginx
NAME CHART VERSION APP VERSION DESCRIPTION
ingress-nginx/ingress-nginx 4.6.1 1.7.1 Ingress controller for Kubernetes using NGINX a...
下载ingress-nginx包,会在当前目录下载一个包,并解压
[root@k8s-master-1 helm]# helm pull ingress-nginx/ingress-nginx
[root@k8s-master-1 helm]# ls
ingress-nginx-4.6.1.tgz
[root@k8s-master-1 helm]#
#因为我用的是k8s1.19.0版本的,用最新的ingress-nginx 报错版本必须高于1.20.0,所以下载指定版本的ingress-nginx,如下:
[root@k8s-master-1 ingress-nginx]# helm fetch ingress-nginx/ingress-nginx --version 3.6.0
解压完 values.yaml文件需要修改
2、修改成阿里云景镜像仓库
registry: registry.cn-beijing.aliyuncs.com
image: dotbalo/controller
或者:docker.io/willdockerhub/ingress-nginx-controller
注释掉digest
dnsPolicy: ClusterFirstWithHostNet #如果hostNetwork 为true 则使用这个DNS的策略
hostNetwork: true
kind: DaemonSet
nodeSelector:
kubernetes.io/os: linux
ingress: "true" #添加一个标签
type: ClusterIP
还有一个registry也需要修改成阿里云的地址
3、使用helm安装ingress-nginx
helm install ingress-nginx -f values.yaml -n ingress-nginx .
[root@k8s-master-1 ingress-nginx]# kubectl get pod -n ingress-nginx -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-controller-c7n4v 1/1 Running 0 18m 192.168.134.137 k8s-node-1 <none> <none>
[root@k8s-master-1 ingress-nginx]#
------------------------------------扩缩容---------------------------
#扩容,在node-02上添加标签即可。DaemonSet会一直监听节点的状态,如果发现有个节点有这个标签了,符合配置规则了,就会把pod部署到指定的节点上,
如果节点上没有指定的标签,这个pod就会被删掉
[root@k8s-master-1 ingress-nginx]# kubectl label node k8s-node-2 ingress=true
node/k8s-node-2 labeled
[root@k8s-master-1 ingress-nginx]#
[root@k8s-master-1 ingress-nginx]# kubectl get pod -n ingress-nginx -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-controller-c7n4v 1/1 Running 0 22m 192.168.134.137 k8s-node-1 <none> <none>
ingress-nginx-controller-cbvmw 1/1 Running 0 50s 192.168.134.138 k8s-node-2 <none> <none>
[root@k8s-master-1 ingress-nginx]#
缩容
[root@k8s-master-1 ingress-nginx]# kubectl label node k8s-node-1 ingress-
删完就可以看到ingress-nginx在节点1上已经被删除
????????为了实现灵活的路由转发策略,Ingress策略可以按多种方式进行配置。
配置文件详解:
1、pathType:对于每条规则(rule),都必须设置一个相应的路径类型,目前支持3种,
????????1、ImplementationSpecific:默认
????????2、Exact:精确匹配URL路径,区分大小写
????????3、Prefix:匹配URL路径的前缀区分大小写
2、host 通配符设置 “*”
????????精确匹配要求HTTP请求头中host参数的值必须与ingress host设置的值完全一致,例如“*.bar.com”
1、转发到单个后端服务:这个无需定义rule,只需要设置一个默认的后端服务就行
[root@k8s-master-1 ingressTest]# vim ingress2.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
spec:
defaultBackend:
service:
name: webapp
port:
number: 8080
2、将同一域名的不同URL路径转发到不同的服务
[root@k8s-master-1 ingressTest]# vim ingress2.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: simple-fanout-example
spec:
rules:
- host: mywebsite.com
http:
paths:
- path: /web
pathType: ImplementationSpecific
backend:
service:
name: web-service
port:
number: 8080
- path: /api
pathType: ImplementationSpecific
backend:
service:
name: api-service
port:
number: 8081
3、将不同的域名转发到不通的服务
apiVersion: networking.k8s.io/v1 #在1.19以后建议使用networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
name: exaple
spec:
rules: #固定写法,一个ingress可以配置多个rules
- host: foo.bar.com #域名配置,可以不写,匹配*
http:
paths: #相当于nginx的location配置,同一个host可以配置多个path
- path: /
pathType: Prefix #必须指定pathType
backend:
service:
name: nginx-svc # 代理到哪个svc
port:
number: 80 # svc的端口
------------------多域名配置的话就多复制这一段-----------
- host: foo1.bar.com #域名配置,可以不写,匹配*
http:
paths: #相当于nginx的location配置,同一个host可以配置多个path
- path: /
pathType: Prefix #必须指定pathType
backend:
service:
name: nginx-svc # 代理到哪个svc
port:
number: 80 # svc的端口
[root@k8s-master-1 ingressTest]# kubectl apply -f ingress.yaml
ingress.networking.k8s.io/exaple created
[root@k8s-master-1 ingressTest]# kubectl get ingress
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
exaple <none> foo.bar.com 80 4s
创建完成之后 在windows访问的话,需要配置域名修改在windows系统中 C:\Windows\System32\drivers\etc
修改hosts文件,添加ingress所在节点的IP 域名 比如192.168.134.137 foo.bar.com
然后在浏览器访问即可
foo.bar.com:30009