k8s之service与ingress

Service是Kubernetes的核心概念,通过创建Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上

Service用于为一组提供服务的Pod抽象一个稳定的网络访问地址,是Kubernetes实现微服务的核心概念。通过Service的定义设置的访问地址是DNS域名格式的服务名称,对于客户端应用来说,网络访问方式并没有改变(DNS域名的作用等价于主机名、互联网域名或IP地址)。Service还提供了负载均衡器功能,将客户端请求负载分发到后端提供具体服务的各个Pod上,Service实现的是微服务架构中的几个核心功能:全自动服务注册,服务发现,服务负载均衡

YAML格式的Service定义文件的完整内容如下:

一、 Service的基本用法:

1、在命名空间update上创建2个副本的nginx应用,如图:

可根据容器标签查看容器的PodIP,如图:

集群内部直接通过两个podIP即可访问服务,如图:

上图中直接通过Pod的IP地址和端口号可以访问到容器应用内的服务,但是Pod的IP地址是不可靠的,例如当Pod所在的Node发生故障时,Pod将被Kubernetes重新调度到另一个Node,Pod的IP地址将发生变化。更重要的是,如果容器应用本身是分布式的部署方式,通过多个实例共同提供服务,就需要在这些实例的前端设置一个负载均衡器来实现请求的分发。Kubernetes中的Service就是用于解决这些问题的核心组件

2、创建service:

编辑service的yaml文件,内容如下:

注:上图中8081表示service的端口,targetPort表示容器内部端口,如果不设置targetPort,默认的targetPort端口与service端口相同

创建该service并查看该service的IP地址,如图:

接下来通过service的IP和端口在任意节点即可访问服务,如图:

上图中通过service的IP和端口访问会被自动负载分发到后面的两个pod上, 目前Kubernetes 提供了两种负载分发策略:RoundRobin和SessionAffinity,具体说明如下:

  • RoundRobin:轮询模式,即轮询将请求转发到后端的各个Pod 上。
  • SessionAffinity:基于客户端IP地址进行会话保持的模式,即第 1次将某个客户端发起的请求转发到后端的某个Pod上,之后从相同的客户端发起的请求都将被转发到后端相同的Pod上。

在默认情况下,Kubernetes采用RoundRobin模式对客户端请求进行负载分发,但我们也可以通过设置service.spec.sessionAffinity=ClientIP来启用SessionAffinity策略。这样,同一个客户端IP发来的请求就会被转发到后端固定的某个Pod上了。

通过Service的定义,Kubernetes实现了一种分布式应用统一入口的定义和负载均衡机制。Service还可以进行其他类型的设置,例如设置多个端口号、直接设置为集群外部服务,或实现为Headless Service(无头 服务)模式

一个Service对应的“后端”由Pod的IP和容器端口号组成,即一个完整的“IP:Port”访问地址,这在Kubernetes系统中叫作Endpoint,通过kubectl describe svc service-nginx -n update可以查看后端服务列表

3、 多端口Service :

有时一个容器应用也可能提供多个端口的服务,那么在Service的定 义中也可以相应地设置为将多个端口对应到多个应用服务。在下面的例子中,Service设置了两个端口号,并且为每个端口号都进行了命名:

还有一种情况是同一个端口对应不同的协议,例如53端口,即可对应TCP,也可以对应UDP

4、service通过名称访问目标端口

(1)、定义pod文件,将nginx端口改为8030,定义端口名为nginx-port,如图:

(2)、查看pod的IP地址,如图:

(3)、通过IP和端口访问,如图:

(4)、定义service文件,并在targetPort中指定目标端口名,如图:

(5)、查看service的IP以及端口,如图:

(6)、通过service的IP和端口进行访问,如图:

注:通过端口名的方式访问pod的好处是,无论pod的端口如何变化,都不需要重新定义service,只要端口名不变即可

二、Service的负载均衡机制

当一个Service对象在Kubernetes集群中被定义出来时,集群内的客户端应用就可以通过服务IP访问到具体的Pod容器提供的服务了。从服务IP到后端Pod的负载均衡机制,则是由每个Node上的kube-proxy负责实现的(iptables/ipvs规则),如图:

本节对kube-proxy的代理模式、会话保持机制和流量策略进行说明。

1、kube-proxy的代理模式

目前kube-proxy提供了以下代理模式(通过启动参数–proxy-mode设置)

(1)、iptables模式(适用于Linux系统)

iptables模式下,kube-proxy通过设置Linux Kernel的iptables规则实现从service到后端pod的负载分发规则,由于使用Netfilter机制,流量转发效率很高,很稳定,但是iptables规则不具备后端健康检查功能,如果后端pod故障,请求就会失败,因此后端pod需要自行做健康检查,kubernetes会保证只有处于Ready状态的pod才会添加到后端列表中,每次新建service或者后端Pod发生变化,kube-proxy都会重新刷新iptables规则,如果大规模集群,会降低性能,可通过kube-proxy的配置资源对象kubeproxyconfiguration中配置如下参数调整iptables规则同步行为:

  • minSyncPeriod:同步iptables规则的最短时间间隔,默认为1,如果配置0表示立即同步
  • syncPeriod:同步时间间隔,用于与service和endpoint变化无关的iptables规则同步

(2)、IPVS模式(适用Linux系统)

在ipvs模式下,kube-proxy通过Linux 内核的netlink接口设置ipvs规则,ipvs使用了散列表作为底层数据结构,并且工作在内核空间,因此ipvs比iptables转发性能更高,延迟更低,同步service和endpoint规则的效率更高,支持更高的网络吞吐量,ipvs模式需要在在Linux Kernel开启IPVS内核模块,如果检测为没有开启会自动切换到iptables模块

ipvs模式支持更多的负载均衡策略,如下所述:

  • rr:round-robin,轮询。
  • wrr:加权轮询
  • lc:least connection,最小连接数。
  • wlc:加权最小连接数
  • dh:destination hashing,目的地址哈希。
  • sh:source hashing,源地址哈希
  • sed:shortest expected delay,最短期望延时
  • nq:never queue,永不排队
  • lblc:基于地域的最小连接数
  • lblcr:带副本的基于地域的最小连接数

(3)、kernelspace模式(适用于windows系统)

2、会话保持:

Service资源还支持Session affinity(粘性会话)机制,可以将来自同一个客户端的请求始终转发至同一个后端的Pod对象,这意味着它会影响调度算法的流量分发功用,进而降低其负载均衡的效果。因此,当客户端访问Pod中的应用程序时,如果有基于客户端身份保存某些私有信息,并基于这些私有信息追踪用户的活动等一类的需求时,那么应该启用session affinity机制。

Service affinity的效果仅仅在一段时间内生效,默认值为10800秒(3个小时),超出时长,客户端再次访问会重新调度。该机制仅能基于客户端IP地址识别客户端身份,它会将经由同一个NAT服务器进行原地址转换的所有客户端识别为同一个客户端,由此可知,其调度的效果并不理想

service通过 sessionAffinity 字段来实现pod会话保持, 支持ClientIP和None 两种方式,默认是None(随机调度) ClientIP是来自于同一个客户端的请求调度到同一个pod中 ,如图:

三、 从集群外部访问Pod或Service:

由于Pod和Service都是Kubernetes集群范围内的虚拟概念,所以集群外的客户端系统无法通过Pod的IP地址或者Service的虚拟IP地址和虚拟端口号访问它们。为了让外部客户端可以访问这些服务,可以将Pod或 Service的端口号映射到宿主机,以使客户端应用能够通过物理机访问容器应用。

1、 将容器应用的端口号映射到物理机:

在Pod资源定义文件中定义端口,如图:

创建pod,然后通过任意一个node节点的8088端口即可访问,如图:

还可以设置Pod级别的hostNetwork=true,该Pod中所有容器的端口号都将被直接映射到物理机上。在设置hostNetwork=true时需要注意,在容器的ports定义部分如果不指定hostPort,则默认hostPort等于 containerPort,如果指定了hostPort,则hostPort必须等于containerPort的 值,如图:

通过节点IP和80端口即可访问,如图:

2、 将Service的端口号映射到物理机:

通过设置nodePort映射到物理机,同时设置Service的类型为 NodePort,如图:

查看创建的service,如图:

此时在外部浏览器通过任意一个节点和端口都可以访问,如图:

同样,通过该Service的访问也将被负载分发到后端的多个Pod上

在默认情况下,Node的kube-proxy会在全部网卡(0.0.0.0)上绑定NodePort端口号。从Kubernetes 1.10版本开始,kube-proxy可以通过设置特定的IP地址将NodePort绑定到特定的网卡上,而无须绑定在全部网卡上,其设置方式为配置启动参数“–nodeport-addresses”,指定需要绑定的网卡IP地址,多个地址之间使用逗号分隔。例如仅在10.0.0.0和192.168.18.0对应的网卡上绑定NodePort端口号,对其他IP地址对应的网卡不会进行绑定,配置如下: –nodeport-addresses=10.0.0.0/8,192.168.18.0/24 (可通过kubect edit cm kube-proxy -n kube-system查看nodeport-addresses的配置地址)

NodePort 默认范围是 30000-32767,可以根据需要进行修改

四、将外部服务定义为Service(从集群访问外部的应用)

普通的Service通过Label Selector对后端Endpoint列表进行了一次抽象,如果后端的Endpoint不是由Pod副本集提供的,则Service还可以抽象定义任意其他服务,将一个Kubernetes集群外部的已知服务定义为Kubernetes内的一个Service,供集群内的其他应用访问,常见的应用场景包括:

  • 已部署的一个集群外服务,例如数据库服务、缓存服务等;
  • 其他Kubernetes集群的某个服务;
  • 迁移过程中对某个服务进行Kubernetes内的服务名访问机制的验证。

对于这种应用场景,用户在创建Service资源对象时不设置LabelSelector(后端Pod也不存在),同时再定义一个与Service关联的Endpoint资源对象,在Endpoint中设置外部服务的IP地址和端口号,下面例子表示通过service访问外部的后端服务

1、首先在服务器上安装Nginx服务(不是在K8S集群中),端口为8096,访问结果如图:

2、在命名空间gongguan中定义service,不指定labelselector,如图:

上图中定义的service,没有指定labelselector,目标端口为8096,由于这个service没有labelselector,因此不会创建相关的Endpoints对象,

3、手动定义后端服务,也就是Endpoints,名称与Service名称保持一致,目标地址和端口指向外部的应用,如图:

注意:同名的Service和Endpoint会自动建立链接

4、查看创建好的service和endpoint,如图:

5、通过service来访问外部后端服务,如图:

五、Kubernetes的服务发现机制

服务发现机制指客户端应用在一个Kubernetes集群中如何获知后端服务的访问地址。Kubernetes提供了两种机制供客户端应用以固定的方式获取后端服务的访问地址:环境变量方式和DNS方式。

1、环境变量方式

在一个Pod运行起来的时候,系统会自动为其容器运行环境注入所有集群中有效Service的信息。Service的相关信息包括服务IP、服务端 口 号 、 各 端 口 号 相 关 的 协 议 等 , 通 过{SVCNAME}SERVICE_HOST和{SVCNAME}_SERVICE_PORT格式 进行设置。其中,SVCNAME的命名规则为:将Service的name字符串 转换为全大写字母,将中横线“-”替换为下画线“”。

查看当前默认命名空间中的service信息,如图:

创建一个新的Pod并进入pod内部(客户端),可以看到系统自动设置的环境变量信息,如图:

此时在客户端(pod内部)可以根据service相关环境变量规则访问目标服务的地址,如图:

2、DNS方式

Service不仅具有标准网络协议的IP地址,同时还以DNS域名形式存在,Service的DNS域 名表示方法为<servicename>.<namespace>.svc.<clusterDomain>,其中 servicename为服务的名称,namespace为其所在namespace的名称, clusterdomain为Kubernetes集群设置的域名后缀(例如cluster.local), 服务名称的命名规则遵循RFC 1123规范的要求。

对于客户端应用来说,DNS域名格式的Service名称提供的是稳定 、 不 变 的 访 问 地 址 , 可 以 大 大 简 化 客 户 端 应 用 的 配 置 , 是Kubernetes集群中推荐的使用方式。

当Service以DNS域名形式进行访问时,就需要在Kubernetes集群中存在一个DNS服务器来完成域名到ClusterIP地址的解析工作了,经过多年的发展,目前由CoreDNS作为Kubernetes集群的默认DNS服务器提供域名解析服务。

六、Headless Service的概念和应用:

在某些应用场景中,客户端应用不需要通过Kubernetes内置Service实现的负载均衡功能,或者需要自行完成对服务后端各实例的服务发现机制,或者需要自行实现负载均衡功能,此时可以通过创建一种特殊的名为“Headless”的服务来实现。

Headless Service 的 概 念 是 这 种 服 务 没 有 入 口 访 问 地 址 ( 无ClusterIP地址),kube-proxy不会为其创建负载转发规则,而服务名(DNS域名)的解析机制取决于该Headless Service是否设置了LabelSelector。

1、Headless Service设置了Label Selector

如果Headless Service设置了Label Selector,Kubernetes则将根据Label Selector查询后端Pod列表,自动创建Endpoint列表,将服务名(DNS域名)的解析机制设置为:当客户端访问该服务名时,得到的是全部Endpoint列表(而不是一个确定的IP地址)。

(1)首先创建一个具有3个副本的运行Nginx容器的pod,标签为app:nginx1,如图:

(2)创建一个Headless Service,无ClusterIP,因此设置为None,根据标签查找后端pod,如图:

创建后,查看该service的详细信息,可以看到后端的Endpoint列表,如图:

通过nslookup工具对headless service名称进行解析,可以看到DNS系统返回全部的Endpoints的IP地址,如图:

headless-service.default.svc.cluster.local:全限定域名,格式:headless-service.<namespace>.svc.cluster.local

(3)修改Pod中的Nginx默认页面,增加Pod的IP地址,然后在客户端(可以是其他Pod),通过全限定域名或者DNS服务名(headless-service)访问3遍,观察结果,如图:

通过DNS服务名访问如下:

从上图中可以发现,每次访问都路由到不同的地址,请求不同的后端Pod

2、Headless Service没有设置Label Selector

如果Headless Service没有设置Label Selector,则Kubernetes将不会自动创建对应的Endpoint列表。DNS系统会根据下列条件尝试对该服务名设置DNS记录:

  • 如果Service的类型为ExternalName,则对服务名的访问将直接被DNS系统转换为Service设置的外部名称(externalName);
  • 如果系统中存在与Service同名的Endpoint定义,则服务名将被解析为Endpoint定义中的列表,适用于非ExternalName 类型的Service。

七、端点分片与服务拓扑:

Service的后端是一组Endpoint列表,为客户端应用提供了极大的便利。但是随着集群规模的扩大及Service数量的增加,特别是Service后端Endpoint数量的增加,kube-proxy需要维护的负载分发规则(例如iptables规则或ipvs规则)的数量也会急剧增加,导致后续对Service后端Endpoint的添加、删除等更新操作的成本急剧上升。假设在Kubernetes集群中有10000个Endpoint运行在大约5000个Node上,则对单个Pod的更新将需要总计约5GB的数据传输,这不仅对集群内的网络带宽浪费巨大,而且对Master的冲击非常大,会影响Kubernetes集群的整体性能,在Deployment不断进行滚动升级操作的情况下尤为突出。

端点分片(Endpoint Slices)通过对Endpoint进行分片管理来实现降低Master和各Node之间的网络传输数据量及提高整体性能的目标。对于Deployment的滚动升级,可以实现仅更新部分Node上的Endpoint信息,Master与Node之间的数据传输量可以减少100倍左右,能够大大提高管理效率。

1、端点分片:

从Kubernetes1.17版本开始,EndpointSlice机制默认是启用的

下面例子已经在命名空间gongguan 中创建了pod和service,现在查看其中创建的端点分片,如下:

八、 Ingress:HTTP 7层路由机制:

Service的表现形式为 IP:Port,即工作在TCP/IP层。而对于基于HTTP的服务来说,不同的URL地址经常对应到不同的后端服务或者虚拟服务器(Virtual Host), 这些应用层的转发机制仅通过Kubernetes的Service机制是无法实现的。 从Kubernetes 1.1版本开始新增Ingress资源对象,用于将不同URL的访问 请求转发到后端不同的Service,以实现HTTP层的业务路由机制。

Kubernetes使用了一个Ingress策略定义和一个具体的Ingress Controller, 两者结合并实现了一个完整的Ingress负载均衡器。

使用Ingress进行负载分发时,Ingress Controller基于Ingress规则将客户端请求直接转发到Service对应的后端Endpoint(Pod)上,这样会跳过kube-proxy的转发功能,kube-proxy不再起作用。如果Ingress Controller提供的是对外服务,则实际上实现的是边缘路由器的功能。

下图显示了一个典型的HTTP层路由的例子,如图:

  • 对http://mywebsite.com/api的访问将被路由到后端名为api的 Service
  • 对http://mywebsite.com/web的访问将被路由到后端名为web的 Service
  • 对http://mywebsite.com/docs的访问将被路由到后端名为docs的 Service

为使用Ingress,需要创建Ingress Controller(带一个默认backend服 务)和Ingress策略设置来共同完成。下面通过一个例子分三步说明 Ingress Controller和Ingress策略的配置方法,以及客户端如何访问Ingress 提供的服务。

ingress由两部分组成:

  • ingress controller:将新加入的Ingress转化成Nginx的配置文件并使之生效
  • ingress服务:将Nginx的配置抽象成一个Ingress对象,每添加一个新的服务只需写一个新的Ingress的yaml文件即可

基于nginx服务的ingress controller根据不同的开发公司,又分为k8s社区的ingress-nginxnginx公司的nginx-ingress,本例子中使用k8s社区版本的Ingress-Nginx

kubernetes官方维护的ingress:

Ingress-nginx的官方文档:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#rewrite
Ingress-nginx Github:https://github.com/kubernetes/ingress-nginx

Nginx-ingress:nginx官方维护的ingress

Nginx-ingress的官方文档:https://docs.nginx.com/nginx-ingress-controller/configuration/ingress-resources/advanced-configuration-with-annotations/
Nginx-ingress Github:https://github.com/nginxinc/kubernetes-ingress/blob/master/docs/nginx-ingress-controllers.md

ingress具体的工作原理如下:

  1. ingress contronler通过与k8s的api进行交互,动态的去感知k8s集群中ingress服务规则的变化,然后读取它,并按照定义的ingress规则,转发到k8s集群中对应的service。
  2. ingress规则写明了哪个域名对应k8s集群中的哪个service,然后再根据ingress-controller中的nginx配置模板,生成一段对应的nginx配置
  3. 然后再把该配置动态的写到ingress-controller的pod里,该ingress-controller的pod里面运行着一个nginx服务,控制器会把生成的nginx配置写入到nginx的配置文件中,然后reload一下,使其配置生效,以此来达到域名分配置及动态更新的效果

ingress可以解决的问题:

  • 动态配置服务: 如果按照传统方式, 当新增加一个服务时, 我们可能需要在流量入口加一个反向代理指向我们新的k8s服务. 而如果用了Ingress, 只需要配置好这个服务, 当服务启动时, 会自动注册到Ingress的中, 不需要而外的操作。
  • 减少不必要的端口暴露:配置过k8s的都清楚, 第一步是要关闭防火墙的, 主要原因是k8s的很多服务会以NodePort方式映射出去, 这样就相当于给宿主机打了很多孔, 既不安全也不优雅. 而Ingress可以避免这个问题, 除了Ingress自身服务可能需要映射出去, 其他服务都不要用NodePort方式

1、 部署Ingress Controller(DaemonSet的方式):

官方原始文件使用的是deployment,replicate 为 1,这样将会在某一台节点上启动对应的nginx-ingress-controller pod。外部流量访问至该节点,由该节点负载分担至内部的service ,为了防止单点故障,改为DaemonSet然后删掉replicate ,配合亲和性部署在指定节点上启动nginx-ingress-controller pod,确保有多个节点启动nginx-ingress-controller pod,后续将这些节点加入到外部硬件负载均衡组实现高可用性。

deployment和daemonset区别:deployment创建的Pod可以一个节点上运行多个,daemonset创建的Pod,一个节点只能运行一个

1.1 添加hostNetwork:

true:添加该字段,暴露nginx-ingress-controller pod的服务端口(80),如图:

1.2 添加亲和性属性(节点定向选择):

#为节点添加标签,只有具有标签ingress-nginx-ready=true的节点才会部署DaemonSet
#下面只给Node节点打标签
kubectl label nodes k8s-node1 ingress-nginx-ready=true
kubectl label nodes k8s-node2 ingress-nginx-ready=true

1.3,修改mandatory.yaml文件,添加节点选择标签,如图:

1.4 修改控制器为DemonSet,副本数注释掉,如图:

1.5 1.23.5版本的deploy.yaml需要修改type类型为ClusterIP,并注释externalTrafficPolicy: Local,如图:

适用于k8s 1.20.8的完整的mandatory.yaml的内容如下:

apiVersion: v1
kind: Namespace
metadata:
  name: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---

kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-configuration
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
kind: ConfigMap
apiVersion: v1
metadata:
  name: tcp-services
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
kind: ConfigMap
apiVersion: v1
metadata:
  name: udp-services
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nginx-ingress-serviceaccount
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
#apiVersion: rbac.authorization.k8s.io/v1beta1
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nginx-ingress-clusterrole
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - endpoints
      - nodes
      - pods
      - secrets
    verbs:
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - nodes
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - services
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - events
    verbs:
      - create
      - patch
  - apiGroups:
      - "extensions"
      - "networking.k8s.io"
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - "extensions"
      - "networking.k8s.io"
    resources:
      - ingresses/status
    verbs:
      - update

---
#apiVersion: rbac.authorization.k8s.io/v1beta1
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: nginx-ingress-role
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - pods
      - secrets
      - namespaces
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - configmaps
    resourceNames:
      # Defaults to "<election-id>-<ingress-class>"
      # Here: "<ingress-controller-leader>-<nginx>"
      # This has to be adapted if you change either parameter
      # when launching the nginx-ingress-controller.
      - "ingress-controller-leader-nginx"
    verbs:
      - get
      - update
  - apiGroups:
      - ""
    resources:
      - configmaps
    verbs:
      - create
  - apiGroups:
      - ""
    resources:
      - endpoints
    verbs:
      - get

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: nginx-ingress-role-nisa-binding
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: nginx-ingress-role
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccount
    namespace: ingress-nginx

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: nginx-ingress-clusterrole-nisa-binding
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: nginx-ingress-clusterrole
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccount
    namespace: ingress-nginx

---

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx-ingress-controller
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
#  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/part-of: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
      annotations:
        prometheus.io/port: "10254"
        prometheus.io/scrape: "true"
    spec:
      hostNetwork: true
      # wait up to five minutes for the drain of connections
      terminationGracePeriodSeconds: 300
      serviceAccountName: nginx-ingress-serviceaccount
      nodeSelector:
        kubernetes.io/os: linux
        ingress-nginx-ready: 'true'     #多个节点打上此标签,每个节点都会运行一个ingress-controller,实现高可用
      containers:
        - name: nginx-ingress-controller
          image: registry.aliyuncs.com/google_containers/nginx-ingress-controller:0.30.0
          args:
            - /nginx-ingress-controller
            - --configmap=$(POD_NAMESPACE)/nginx-configuration
            - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
            - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
            - --publish-service=$(POD_NAMESPACE)/ingress-nginx
            - --annotations-prefix=nginx.ingress.kubernetes.io
          securityContext:
            allowPrivilegeEscalation: true
            capabilities:
              drop:
                - ALL
              add:
                - NET_BIND_SERVICE
            # www-data -> 101
            runAsUser: 101
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
            - name: https
              containerPort: 443
              protocol: TCP
          livenessProbe:
            failureThreshold: 3
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            initialDelaySeconds: 10
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 10
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 10
          lifecycle:
            preStop:
              exec:
                command:
                  - /wait-shutdown

---

apiVersion: v1
kind: LimitRange
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  limits:
  - min:
      memory: 90Mi
      cpu: 100m
    type: Container

1.5 执行命令kubectl create -f mandatory创建此ingress,如图:

从上图中可以看出,ingress已经创建成功,因为设置了hostNetwork=true,因此podIp和宿主机IP相同,并且由于设置了定向选择,因此在两个节点上都有ingress的Pod

2、进行案例测试

2.1 首先在命名空间update通过deployment创建一个nginx类型应用,如图:

2.2 创建service文件,类型选择clusterIP,内容如下:

通过serviceIP和端口访问服务试试,可以访问,如图:

注意:ClusterIP只用于集群内部通讯,外部是无法访问的,因此,如果要在外部通过域名访问内部的Pod,还是需要ingress的策略配置文件

2.3,创建ingress策略文件,ingress.yaml,内容如下:

  • metadata.name:自定义名字
  • namespace:策略规则用于的命名空间,一般与应用在同一namespace
  • host:指定要访问的域名
  • path:域名后访问的路径
  • pathType:基于以 / 分隔的 URL 路径前缀匹配。匹配对大小写敏感,并且对路径中的元素逐个完成,除了Prefix,还有一种类型为Exact(精确匹配URL路径,区分大小写)
  • service.name:上一步创建的service的名称
  • number:service中配置的访问pod的端口

注意:如果一个请求同时被在Ingress中设置的多个URL路径匹配,则系统将以最长的匹配路径为优先。如果有两条同等长度的匹配路径,则精确匹配类型(Exact)优先于前缀匹配类型(Prefix)。

执行命令kubectl create -f ingress.yaml,查看结果如下:

2.4,本地电脑添加host,将域名解析到k8s-node1和k8s-node2上,然后通过域名访问,如图:

附加:

上面的Ingress策略路由只是单条,如果是多条,配置方式如下

1、克隆上文中的nginx.yaml为tomcat.yaml,并修改内部的参数为tomcat,如图:

2、创建service,文件内容如下:

3、编辑Ingress策略配置文件,添加tomcat路由,如图:

4、通过页面进行访问,如图:

注意:tomcat默认启动后没有主界面,可在webapps目录下创建ROOT目录,在此目录下新建index.html文件,自定义内容即可

上图中是一个主机多个路径,如果是多个主机,可以按照以下方式配置,如图:

5、常见的路径类型匹配规则示例:

路径类型在ingress中配置的路径请求路径是否匹配
Prefix/所有路径
Prefix /foo/foo,/foo/
Prefix /foo/ /foo,/foo/
Prefix /aaa/bb/aaa/bbb
Prefix /aaa/bbb /aaa/bbb
Prefix /aaa/bbb/ /aaa/bbb是,忽略结尾的”/”
Prefix /aaa/bbb /aaa/bbb/是,匹配结尾的”/”
Prefix /aaa/bbb /aaa/bbb/ccc是,匹配子路径
Prefix /aaa/bbb /aaa/bbbxyz否,无匹配前缀
Prefix /,/aaa/aaa/ccc是,匹配的是/aaa前缀
Prefix /,/aaa,/aaa/bbb/aaa/bbb是,匹配的是/aaa/bbb前缀
Prefix /,/aaa/aaa/bbb/ccc是,匹配了”/”
Prefix /aaa/ccc
Prefix +Exact混合/foo(Prefix),/foo(Exact)/foo是,优先匹配Exact
Exact/foo/foo
Exact /foo/bar
Exact /foo/foo/
Exact /foo//foo

6、host通配符设置:

在规则(rule)中设置的host用于匹配请求中的域名(虚拟主机名),设置为完整的字符串表示精确匹配,例如“foo.bar.com”。Kubernetes 从 1.18 版 本 开 始 支 持 为 host 设 置 通 配 符 “*” , 例 如“*.foo.com”

精确匹配要求HTTP请求头中host参数的值必须与Ingress host设置的值完全一致,通配符匹配要求HTTP请求头中host参数的值需要与Ingress host设置的值的后缀一致,并且仅支持一层DNS匹配,如下表示常见的通配符匹配示例:

ingress host配置请求头中host值是否匹配
*.foo.combar.foo.com
*.foo.combaz.bar.foo.com否,不是一层DNS匹配
*.foo.comfoo.com 否,不是一层DNS匹配

ingress高可用结构

作为集群流量接入层,Ingress Controller的高可用性显得尤为重要,高可用性首先要解决的就是单点故障问题,一般常用的是采用多副本部署的方式,我们在Kubernetes集群中部署高可用Ingress Controller接入层同样采用多节点部署架构,同时由于Ingress作为集群流量接入口,建议采用独占Ingress节点的方式,以避免业务应用与Ingress服务发生资源争抢

如上述部署架构图,由多个独占Ingress实例组成统一接入层承载集群入口流量同时可依据后端业务流量水平扩缩容Ingress节点。当然如果您前期的集群规模并不大,也可以采用将Ingress服务与业务应用混部的方式,但建议进行资源限制和隔离。

如果集群在内部网络,外网环境需要访问,此时可以通过Nginx做一次跳转即可

适用于k8s 1.23.5的ingress-controller文件也是采用DaemonSet,配置方法与上面一样,deploy.yaml内容如下:


apiVersion: v1
kind: Namespace
metadata:
  name: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx

---
# Source: ingress-nginx/templates/controller-serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: controller
  name: ingress-nginx
  namespace: ingress-nginx
automountServiceAccountToken: true
---
# Source: ingress-nginx/templates/controller-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: controller
  name: ingress-nginx-controller
  namespace: ingress-nginx
data:
  allow-snippet-annotations: 'true'
---
# Source: ingress-nginx/templates/clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
  name: ingress-nginx
rules:
  - apiGroups:
      - ''
    resources:
      - configmaps
      - endpoints
      - nodes
      - pods
      - secrets
      - namespaces
    verbs:
      - list
      - watch
  - apiGroups:
      - ''
    resources:
      - nodes
    verbs:
      - get
  - apiGroups:
      - ''
    resources:
      - services
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - networking.k8s.io
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ''
    resources:
      - events
    verbs:
      - create
      - patch
  - apiGroups:
      - networking.k8s.io
    resources:
      - ingresses/status
    verbs:
      - update
  - apiGroups:
      - networking.k8s.io
    resources:
      - ingressclasses
    verbs:
      - get
      - list
      - watch
---
# Source: ingress-nginx/templates/clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
  name: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: ingress-nginx
subjects:
  - kind: ServiceAccount
    name: ingress-nginx
    namespace: ingress-nginx
---
# Source: ingress-nginx/templates/controller-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: controller
  name: ingress-nginx
  namespace: ingress-nginx
rules:
  - apiGroups:
      - ''
    resources:
      - namespaces
    verbs:
      - get
  - apiGroups:
      - ''
    resources:
      - configmaps
      - pods
      - secrets
      - endpoints
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ''
    resources:
      - services
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - networking.k8s.io
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - networking.k8s.io
    resources:
      - ingresses/status
    verbs:
      - update
  - apiGroups:
      - networking.k8s.io
    resources:
      - ingressclasses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ''
    resources:
      - configmaps
    resourceNames:
      - ingress-controller-leader
    verbs:
      - get
      - update
  - apiGroups:
      - ''
    resources:
      - configmaps
    verbs:
      - create
  - apiGroups:
      - ''
    resources:
      - events
    verbs:
      - create
      - patch
---
# Source: ingress-nginx/templates/controller-rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: controller
  name: ingress-nginx
  namespace: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: ingress-nginx
subjects:
  - kind: ServiceAccount
    name: ingress-nginx
    namespace: ingress-nginx
---
# Source: ingress-nginx/templates/controller-service-webhook.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: controller
  name: ingress-nginx-controller-admission
  namespace: ingress-nginx
spec:
  type: ClusterIP
  ports:
    - name: https-webhook
      port: 443
      targetPort: webhook
      appProtocol: https
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/component: controller
---
# Source: ingress-nginx/templates/controller-service.yaml
apiVersion: v1
kind: Service
metadata:
  annotations:
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: controller
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  type: ClusterIP
  #externalTrafficPolicy: Local
  ipFamilyPolicy: SingleStack
  ipFamilies:
    - IPv4
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: http
      appProtocol: http
    - name: https
      port: 443
      protocol: TCP
      targetPort: https
      appProtocol: https
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/component: controller
---
# Source: ingress-nginx/templates/controller-deployment.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: controller
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/instance: ingress-nginx
      app.kubernetes.io/component: controller
  revisionHistoryLimit: 10
  minReadySeconds: 0
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/component: controller
    spec:
      dnsPolicy: ClusterFirst
      containers:
        - name: controller
          image: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.1.1
          imagePullPolicy: IfNotPresent
          lifecycle:
            preStop:
              exec:
                command:
                  - /wait-shutdown
          args:
            - /nginx-ingress-controller
            - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
            - --election-id=ingress-controller-leader
            - --controller-class=k8s.io/ingress-nginx
            - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
            - --validating-webhook=:8443
            - --validating-webhook-certificate=/usr/local/certificates/cert
            - --validating-webhook-key=/usr/local/certificates/key
          securityContext:
            capabilities:
              drop:
                - ALL
              add:
                - NET_BIND_SERVICE
            runAsUser: 101
            allowPrivilegeEscalation: true
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: LD_PRELOAD
              value: /usr/local/lib/libmimalloc.so
          livenessProbe:
            failureThreshold: 5
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            initialDelaySeconds: 10
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 1
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            initialDelaySeconds: 10
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 1
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
            - name: https
              containerPort: 443
              protocol: TCP
            - name: webhook
              containerPort: 8443
              protocol: TCP
          volumeMounts:
            - name: webhook-cert
              mountPath: /usr/local/certificates/
              readOnly: true
          resources:
            requests:
              cpu: 100m
              memory: 90Mi
      nodeSelector:
        kubernetes.io/os: linux
        ingress-nginx-ready: 'true'
      serviceAccountName: ingress-nginx
      hostNetwork: true
      terminationGracePeriodSeconds: 300
      volumes:
        - name: webhook-cert
          secret:
            secretName: ingress-nginx-admission
---
# Source: ingress-nginx/templates/controller-ingressclass.yaml
# We don't support namespaced ingressClass yet
# So a ClusterRole and a ClusterRoleBinding is required
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: controller
  name: nginx
  namespace: ingress-nginx
spec:
  controller: k8s.io/ingress-nginx
---
# Source: ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
# before changing this value, check the required kubernetes version
# https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#prerequisites
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: admission-webhook
  name: ingress-nginx-admission
webhooks:
  - name: validate.nginx.ingress.kubernetes.io
    matchPolicy: Equivalent
    rules:
      - apiGroups:
          - networking.k8s.io
        apiVersions:
          - v1
        operations:
          - CREATE
          - UPDATE
        resources:
          - ingresses
    failurePolicy: Fail
    sideEffects: None
    admissionReviewVersions:
      - v1
    clientConfig:
      service:
        namespace: ingress-nginx
        name: ingress-nginx-controller-admission
        path: /networking/v1/ingresses
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ingress-nginx-admission
  namespace: ingress-nginx
  annotations:
    helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
    helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: admission-webhook
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: ingress-nginx-admission
  annotations:
    helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
    helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: admission-webhook
rules:
  - apiGroups:
      - admissionregistration.k8s.io
    resources:
      - validatingwebhookconfigurations
    verbs:
      - get
      - update
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: ingress-nginx-admission
  annotations:
    helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
    helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: admission-webhook
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: ingress-nginx-admission
subjects:
  - kind: ServiceAccount
    name: ingress-nginx-admission
    namespace: ingress-nginx
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: ingress-nginx-admission
  namespace: ingress-nginx
  annotations:
    helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
    helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: admission-webhook
rules:
  - apiGroups:
      - ''
    resources:
      - secrets
    verbs:
      - get
      - create
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ingress-nginx-admission
  namespace: ingress-nginx
  annotations:
    helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
    helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: admission-webhook
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: ingress-nginx-admission
subjects:
  - kind: ServiceAccount
    name: ingress-nginx-admission
    namespace: ingress-nginx
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/job-createSecret.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: ingress-nginx-admission-create
  namespace: ingress-nginx
  annotations:
    helm.sh/hook: pre-install,pre-upgrade
    helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: admission-webhook
spec:
  template:
    metadata:
      name: ingress-nginx-admission-create
      labels:
        helm.sh/chart: ingress-nginx-4.0.15
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/version: 1.1.1
        app.kubernetes.io/managed-by: Helm
        app.kubernetes.io/component: admission-webhook
    spec:
      containers:
        - name: create
          image: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1 
          imagePullPolicy: IfNotPresent
          args:
            - create
            - --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
            - --namespace=$(POD_NAMESPACE)
            - --secret-name=ingress-nginx-admission
          env:
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          securityContext:
            allowPrivilegeEscalation: false
      restartPolicy: OnFailure
      serviceAccountName: ingress-nginx-admission
      nodeSelector:
        kubernetes.io/os: linux
      securityContext:
        runAsNonRoot: true
        runAsUser: 2000
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/job-patchWebhook.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: ingress-nginx-admission-patch
  namespace: ingress-nginx
  annotations:
    helm.sh/hook: post-install,post-upgrade
    helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: admission-webhook
spec:
  template:
    metadata:
      name: ingress-nginx-admission-patch
      labels:
        helm.sh/chart: ingress-nginx-4.0.15
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/version: 1.1.1
        app.kubernetes.io/managed-by: Helm
        app.kubernetes.io/component: admission-webhook
    spec:
      containers:
        - name: patch
          image: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1
          imagePullPolicy: IfNotPresent
          args:
            - patch
            - --webhook-name=ingress-nginx-admission
            - --namespace=$(POD_NAMESPACE)
            - --patch-mutating=false
            - --secret-name=ingress-nginx-admission
            - --patch-failure-policy=Fail
          env:
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          securityContext:
            allowPrivilegeEscalation: false
      restartPolicy: OnFailure
      serviceAccountName: ingress-nginx-admission
      nodeSelector:
        kubernetes.io/os: linux
      securityContext:
        runAsNonRoot: true
        runAsUser: 2000

执行kubectl apply -f deploy.yaml创建pod,执行kubectl get po -n ingress-nginx -o wide查看创建的pod,如图:

从上图可以看出,因为通过DaemonSet方式创建,因此两个pod分布于两个节点上,admission名字的Pod显示Completed表示正常

1.23.5的资源文件会创建ingressclass,名称为nginx,控制器为k8s.io/ingress-nginx,如图:

什么是ingressclass呢?如果集群中定义了多个ingressclass,那么定义ingress规则文件的时候,就需要指定哪个控制器来解析规则,上图中我们安装完成后只定义了一个ingressclass

验证

1、在命名空间update中创建一个Pod,yaml文件内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx                     #deployment名字
  namespace: update             #命名空间
  labels:
    name: deployment-nginx
spec:
  selector:
    matchLabels:
      app: nginx            #管理标签为nginx-pod的pod
  replicas: 2                    #副本个数为2
  template:                      #创建pod的模板
    metadata:
      labels:
        app: nginx           #pod标签,标签选择器就是选择这个标签
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

2、在命名空间update中创建service,文件内容如下:

apiVersion: v1
kind: Service
metadata:
  name: service-nginx
  namespace: update
spec:
  ports:
  - port: 8082
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx

3、创建ingress策略文件,内容如下:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-update
  namespace: update
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx             #指定IngressClass名称
  rules:
  - host: www.gong.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: service-nginx
            port:
              number: 8082

添加hosts后,访问即可,如图:

注意:上面的ingress规则文件中指定了了ingressClassName为nginx,如果不设置ingressClassName参数,那么请求的时候会提示404错误,因为找不到ingress控制器,此时可以设置一个默认的ingressclass,比如我们设置安装后自带的名称为nginx的ingressclass为默认的,命令如下:

kubectl edit ingressclass nginx
#新增内容如下:
ingressclass.kubernetes.io/is-default-class: "true"

设置完成后,即使不用配置ingressClassName参数,就会默认使用nginx这个ingressclass

附加

如果需要创建多个ingressclass,可单独定义资源文件,内容如下:

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  labels:
    helm.sh/chart: ingress-nginx-4.0.15
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 1.1.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: controller
  name: nginx-class                          #自定义nginx-class名字
  namespace: update                          #指定命名空间,和pod以及service在同一个命名空间
spec:
  controller: k8s.io/ingress-nginx           #定义的controller为上面创建的ingress-controller

ingress支持灰度发布(金丝雀发布)

注意:Ingress也有局限性,能被Ingress聚合的Service服务,只能是http/https服务,不能是其他协议的服务,如果还有其他协议的服务,可以使用Gateway API替代,Gateway API还支持UDP,与Service Mesh无缝对接

标签