前言
环境:centos7.9 docker-ce-20.10.9 kubernetes-version v1.22.6
本篇来讲解k8s中ingress资源。
什么是ingress资源,为什么需要ingress资源
在 Kubernetes
中,为了使外部的应用能够访问集群内的service
,最为常用的是使用 NodePort
和 LoadBalancer
两种类型的service
,但它们在使用上还是有一些限制:如,对外提供访问时,NodePort
类型需要在外部搭建额外的负载均衡,比如F5或nginx反向代理,NodePort方式最大的缺点是会占用很多集群机器的端口
;而 LoadBalancer
要求 Kubernetes
必须跑在支持的 Cloud Provider
上,由云厂商提供公网IP地址,同时当存在多个LoadBalancer
的类型service
时,就会占用大量公网ip地址,而ingress
正是为解决以上这种问题而存在的。
NodePort的缺点
这种方式的service要求集群中部分节点有被外网访问的能力。Kubernetes
为每一个NodePort
类型的服务在集群中的每一个节点上分配至少一个主端口号。客户经过能被外网访问的节点IP加上节点端口的方式访问服务。大多数状况下不会经过这种方式向集群外暴露服务,缘由有四:
1、大多状况下,为了安全起见,集群中的节点位于完全封闭的内网环境中,不该有被外网直接访问的能力。通常外网访问集群中的节点都是经过边界服务器如网关、跳板等,而这种边界服务器须要经过各类方式进行层层安全加固;
2、若是集群内节点能够被外网直接访问的话,将会使集群内节点地址、服务名称、端口号等信息直接暴露在外,很不安全;
3、服务端口号通常由系统自动分配,并不是固定,而服务名称也可能发生变动,此时外部客户端须要跟踪变动并修改,属于重试耦合;
4、NodePort
这种类型的service
,每一个服务都会在node
节点起一个端口号,当创建的service很多时会占用很多集群节点机器的端口。
LoadBalancer 的缺点
LoadBalancer
通常由云服务供应商提供或者用户自定义,运行在集群以外。在建立service时为其配置LoadBalancer
相关参数,当从外网访问集群内servcie
时,用户直接链接到LoadBalancer
服务器,LoadBalancer
服务器再将流量转发到集群内service。Loadbalancer配置及使用方法与各云服务供应商有关,本文不详细描述。
ingress资源(简写ing)
除了使用NodePort
和LoadBalancer
来暴露service,k8s还支持使用ingress资源来暴露service,想要使用ingress,首先必须先创建ingress -controller
,即ingress控制器
,ingress控制器有很多种,目前k8s官方的ingress控制器是ingress-nginx-controller
,由此可见ingress其实也是使用了nginx的7层反向代理来实现的。
ingress的简写为ing,ingress可以实现暴露多个service,即当外部客户端向一个ingress发送连接请求时,ingress会根据请求的主机和路径来决定将请求转发给对应的service。
Ingress包含的组件
Ingress Controller
:Ingress控制器
,具体实现反向代理即负载均衡的程序,实现七层转发的Edge Router
,通过调用k8s的api动态感知集群中Pod的变化而动态更新配置文件并重载, Controller需要部署在k8s集群中以实现和集群中的pod通信,通常以DaemonSets
或Deployments
的形式部署,并对外暴露80和443端口,对于DaemonSets
来说,一般是以hostNetwork
或者hostPort
的形式暴露,Deployments
则以NodePort
的方式暴露,Ingress控制器
的多个节点则借助外部负载均衡ExternalLB
以实现统一接入;
Ingress资源对象
:配置规则,即定义如何转发到service的规则;
ingress(以nginx为例)的工作原理
1、用户编写ingress规则,说明哪个域名对应kubernetes集群中的哪个service;
2、ingress控制器动态感知ingress服务的规则的变化,然后生成一段对应的nginx配置;
3、ingress控制器会将生成的nginx配置写入到一个运行着的nginx服务中,并动态更新;
4、到此为止,其实真正工作的就是一个nginx了,内部配置了用户定义的请求转发规则;
方法一、安装ingress-nginx-controller
根据官网的yaml文件来部署即可,不过yaml文件使用的k8s官网的镜像,可能下载不到。
https://kubernetes.github.io/ingress-nginx/deploy
这种部署方式其实是使用DaemonSets 来部署的,同时配置了 ingress-nginx Pod
使用它们运行的主机的网络,而不是专用的网络命名空间。 这种方法的好处是 NGINX Ingress
控制器可以将端口 80 和 443 直接绑定到 Kubernetes
节点的宿主机网络接口,而无需 NodePort
服务强加的额外网络转换。
# 从官网下载下俩的yaml文件,需要修改下面这两点:
dnsPolicy: ClusterFirstWithHostNet #默认是ClusterFirst,如果hostNetwork: true则必须改为ClusterFirstWithHostNet
hostNetwork: true #使用宿主机网络,表示直接将端口绑定到主机上
[root@master ingress-nginx]# kubectl get ds -n ingress-nginx
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
ingress-nginx-controller 2 2 2 2 2 kubernetes.io/os=linux 15h
[root@master ingress-nginx]#
[root@master ingress-nginx]# kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-lv5m8 1/1 Running 1 (5h19m ago) 15h
ingress-nginx-controller-qcjsr 1/1 Running 1 (5h18m ago) 15h
[root@master ingress-nginx]#
方法二、安装ingress-nginx-controller(新版本可参考这种方式安装ingress-nginx-controller)
新版的ingress-nginx-controller居然是使用deployment部署的,而且其副本数是一个pod:
#官网
https://kubernetes.github.io/ingress-nginx/deploy/
#注意不同的k8s版本对应不同的ingress-nginx版本,我这里属于测试环境,直接部署最新的版本
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.5.1/deploy/static/provider/cloud/deploy.yaml
#编辑文件,我们需要修改一些文件
vim deploy.yml
dnsPolicy: ClusterFirstWithHostNet #默认是ClusterFirst,改为ClusterFirstWithHostNet
#方法一、在deployment下添加deployment.spec.template.spec.hostNetwork,表示将deployment的容器端口号绑定到宿主机上
#但是这样会有一个问题,那就是pod副本数只能是一个,不然多个pod在同一个宿主机上岂不是端口冲突了,除非你做pod反亲和性;这里官方的yaml文件pod副本数也是一个;
#方法二、修改service的类型为NodePort类型,默认是公有云上的LoadBalancer;同时,绑定nodePort端口,这里我指定了http的30080和https的30443这两个nodePort端口
#以上两者,我选择了方法二
#注意,当创建完成ingress-nginx-controller之后,只有ingress-nginx-controller-74696c6dbc-zlffh 这种pod跑在哪个节点上,从外部节点访问该节点时才能访问的通,如,假设ingress-nginx-controller-74696c6dbc-zlffh pod 位于master节点,则页面访问http://masterIP:30080 才能正常,这一点有点想不通,30080是service的nodeport端口,按理说该端口会在每个节点上的呀,怎么只有ingress-nginx-controller-74696c6dbc-zlffh pod的端口才能正常访问?不过,基于这一点,我们可以指定master节点为ingress的特定流量入口节点,即只需要将deployment配置节点选择器即可。
kubectl apply -f deploy.yml #创建资源
方法三、helm 安装ingress-nginx-controller
#添加仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
#由于kubernetes.github.io网站是国外的,所以访问很慢
#可以去https://www.ipaddress.com/site/kubernetes.github.io上搜索对应的ID做/etc/hosts域名解析
#搜索ingress-nginx的chart包
[root@master ~]# helm search repo ingress-nginx
NAME CHART VERSION APP VERSION DESCRIPTION
ingress-nginx/ingress-nginx 4.6.0 1.7.0 Ingress controller for Kubernetes using NGINX a...
#拉去chart包
helm pull ingress-nginx/ingress-nginx --version=4.6.0
#解压chart包
tar xf ingress-nginx-4.6.0.tgz
cd ingress-nginx/
vim values.yaml
工具内容修改
(待完善)
kubectl create namespace ingress-nginx
helm install ingress-nginx xx/
创建ingress资源对象
确保已经存在运行的ingress-nginx-controller
了,下面来创建一个ingress对象。
[root@master ingress-nginx]# vim ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress #创建一个ingress资源
metadata:
name: my-ingress #资源名称叫my-ingress
spec:
rules: #定义访问规则,-横杠表示下面可以是多个数组
- host: www.lsp.com #主机域名
http: #网络协议类型
paths:
- path: /lsp #将访问/lsp的请求转发到lsp服务的80端口
pathType: Exact
backend:
service:
name: lsp #service的名称
port:
number: 80 #service的端口
#以上就创建一个单一规则的ingress
查看ingress
[root@master ingress-nginx]# kubectl get ing #ingress的简写为ing
NAME CLASS HOSTS ADDRESS PORTS AGE
my-ingress <none> www.lsp.com 192.168.118.132,192.168.118.133 80 24m
[root@master ingress-nginx]#
#这样,windows进行www.lsp.com域名进行解析到192.168.118.132,然后浏览器就能进行www.lsp.com+端口+访问路径进行访问了
同一个主机的不同路径,映射到不同的service
创建一个ingress,将不同的service映射到相同主机的不同路径,如下:
[root@master ingress-nginx]# vim ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress #创建一个ingress资源
metadata:
name: my-ingress #资源名称叫my-ingress
spec:
rules: #定义访问规则,-横杠表示下面可以是多个数组
- host: www.lsp.com #主机域名,下面是将同一个主机的不同访问路径映射到不同的service中去
http: #网络协议类型
paths:
- path: /lsp #将访问www.lsp.com/lsp的请求转发到lsp服务的80端口
pathType: Exact
backend:
service:
name: lsp #service的名称
port:
number: 80 #service的端口
- path: /dossier #将访问路径www.lsp.com/dossier的请求转发到Tomcat服务的8080端口
pathType: Exact
backend:
service:
name: dossier #service的名称
port:
number: 8080 #service的端口
#以上,根据请求的URL中的路径,请求将发送到2个不同的服务,因此,客户端可以通过一个IP地址(ingress控制器的ip地址)访问2个不同的服务。
不同的主机,映射到不同的service
同理,也可以在一个ingress中定义不同的主机,来映射到不同的service,如下所示:
[root@master ingress-nginx]# vim ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress #创建一个ingress资源
metadata:
name: my-ingress #资源名称叫my-ingress
spec:
rules: #定义访问规则,-横杠表示下面可以是多个数组
- host: www.lsp.com #第一个主机域名
http: #网络协议类型
paths:
- path: /lsp #将访问www.lsp.com/lsp的请求转发到lsp服务的80端口
pathType: Exact
backend:
service:
name: lsp #service的名称
port:
number: 80 #service的端口
- host: www.dossier.com #第二个主机域名
http:
paths:
- path: /dossier #将访问路径www.dossier.com/dossier的请求转发到Tomcat服务的8080端口
pathType: Exact
backend:
service:
name: dossier #service的名称
port:
number: 8080 #service的端口
#以上,根据请求中的host头,请求将被分发到对应的主机的service中去,因此,客户端可以通过一个IP地址(ingress控制器的ip地址)访问多个主机/域名中的service。
更改ingress的默认80端口
前面我们在ingress的yaml文件中定义了访问域名,如www.lsp.com
,然后在浏览器就能指定路径访问了,如:http://www.lsp.com/lsp
,但是细心的人会发现,我们访问的时候并没有指定端口,这时http协议默认就是80端口,如果客户不给使用80端口,或者80端口已经被占用了,那这么办?这时就需要修改ingress的默认端口了,我们知道ingress使用的是nginx(官网推荐就是nginx),所以80端口其实就是ingress的默认端口,我们如果有需求要改变该端口,可以在ingress控制器中做修改,如下:
然后kubectl apply -f ingress-nginx-controller-deployment.yaml
,pod就会被重新创建,然后页面访问就需要指定端口访问了,如:http://www.lsp.com:8012/lsp
配置ingress处理TLS传输(https)
https是需要秘钥和证书的,所以首先需要创建秘钥和证书,如下:
#创建证书
[root@master ingress-nginx]# openssl genrsa -out tls.key 2048
[root@master ingress-nginx]# openssl req -new -x509 -key tls.key -out tls.cert -days 365 -subj /CN=www.lsp.com
#创建秘钥
[root@master ingress-nginx]# kubectl create secret tls tls-secret --cert=tls.cert --key=tls.key
secret/tls-secret created
#创建一个使用https协议链接的ingress资源
[root@master ingress-nginx]# cat my-ingress-tls.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
tls: #定义tls参数
- hosts:
- www.lsp.com #指定访问的主机
secretName: tls-secret #指定使用的秘钥
rules: #下面这些和之前的保持不变
- host: www.lsp.com
http:
paths:
- path: /
pathType: Exact
backend:
service:
name: svc-nginx-clusterip-ingress2
port:
number: 8099
[root@master ingress-nginx]#
此时,网页访问:https://www.lsp.com/
就能正常访问了,https默认端口是443。
使用负载均衡器将流量负载到到多个ingress节点
ingress上定义了域名,那么客户端浏览器必须使用域名进行访问,生产中可以需要多个ingress节点接收流量,所以整个流程是这样的:
1、用户访问http://www.fuyu.com域名
2、LB解析了www.fuyu.com域名,所以请求到达LB服务器上,LB服务器可以是nginx或F5等软硬件;
3、LB服务器上根据域名配置了对多个node节点80端口进行请求转发;
4、80端口是ingress绑定的,所以ingress接收流量,并根据定义的规则转发给对应的service;
5、service将流量转发到后端的pod。