kubernetes服务发布 [TOC]
前言 每个Pod都会获取到它自己的IP地址,但是这些IP地址不总是稳定和可依赖的 ,这样就会导致一个问题:在Kubernetes集群中,如果一组Pod(比如后端的Pod)为其他Pod(比如前端的Pod提供服务,那么如果它们之间使用Pod的IP地址进行通信,在Pod重建后,将无法再进行连接。
于是Kubernetes引用了Service这样一种抽象概念:逻辑上的一组Pod,即一种可以访问Pod的策略。这一组Pod能够被Service通过标签选择器 访问到,之后就可以使用Service进行通信,集群内部服务之间的访问通Service的名称来进行通信的,因为service的名称是亘古不变的。Kubernetes的Service定义了一个服务的访问入口地址,前端的应用(Pod)通过这个入口地址访问其背后的一组由Pod副本组成的集群实例,Service 与其后端Pod副本集群之间则是通过Label Selector来实现无缝对接的。
既然每个Pod都会被分配一个单独的IP地址,而且每个Pod都提供了一个独立的Endpoint(PodIP+ContainerPort)以被客户端访问,现在多个Pod副本组成了一个集群来提供服务。
那么客户端如何来访问它们呢?一般的做法是部署一个负载均衡器(软件或硬件), 为这组Pod开启一个对外的服务端口,如80端口,并且将这些Pod的Endpoint列表加入80端口的转发列表,客户端就可以通过负载均衡器的对外IP地址+服务端口来访问此服务。 客户端的请求最后会被转发到哪个Pod,由负载均衡器的算法所决定。
Kubernetes也遵循上述常规做法,运行在每个Node上的kube-proxy进程其实就是一个智能的软件负载均衡器,负责把对Service的请求转发到后端的某个Pod实例上,并在内部实现服务的负载均衡与会话保持机制。但Kubernetes发明了一种很巧妙又影响深远的设计: Service没有共用一个负载均衡器的IP地址,每个Service都被分配了一个全局唯一的虚拟IP地址,这个虚拟IP被称为Cluster IP。这样一来,每个服务就变成了具备唯一IP地址的通信节点,服务调用就变成了最基础的TCP网络通信问题。
Pod的Endpoint地址会随着Pod的销毁和重新创建而发生改变,因为新Pod的IP地址与之前旧Pod的不同。而Service一旦被创建,Kubernetes就会自动为它分配一个可用的Cluster IP,而且在Service的整个生命周期内,它的Cluster IP一般不会发生改变。 于是,服务发现这个棘手的问题在Kubernetes的架构里也得以轻松解决:只要用Service的Name与Service的Cluster IP地址做一个DNS域名映射即可完美解决问题。
1、Service:集群内部通讯流量成为东西流量(svc有ns隔离性) 1.1 简介 Service是Kubernetes实现微服务架构的核心概念,通过创建Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上。
Service用于为一组提供服务的Pod抽象一个稳定的网络访问地址,通过Service的定义设置的访问地址是DNS域名格式的服务名称,对于客户端应用来说,网络访问方式并没有改变(DNS域名的作用等价于主机名、互联网域名或IP地址)。 Service还提供了负载均衡器功能,将客户端请求负载分发到后端提供具体服务的各个Pod上。
1.2 Kubernetes的服务发现机制 服务发现机制指客户端应用在一个Kubernetes集群中如何获知后端服务的访问地址。Kubernetes提供了两种机制供客户端应用以固定的方式获取后端服务的访问地址:环境变量方式和DNS方式
1.2.1 环境变量方式 在一个Pod运行起来的时候,系统会自动为其容器运行环境注入所有集群中有效Service的信息。Service的相关信息包括服务IP、服务端口号、各端口号相关的协议等,通过{SVCNAME}_SERVICE_HOST和 {SVCNAME}_SERVICE_PORT 格式进行设置。其中,SVCNAME的命名规则为:将Service的name字符串转换为全大写字母,将中横线“-”替 换为下画线“_”。
假设已经创建一个SVC,进去SVC后端的任意一个Pod中
1 2 3 4 5 6 7 8 9 10 11 12 [root@k8s-master01 ~] / NGINX_PORT_80_TCP=tcp://10.96.11.64:80 NGINX_SERVICE_HOST=10.96.11.64 NGINX_SERVICE_PORT=80 NGINX_PORT=tcp://10.96.11.64:80 NGINX_PORT_80_TCP_ADDR=10.96.11.64 NGINX_PORT_80_TCP_PORT=80 NGINX_PORT_80_TCP_PROTO=tcp /
1.2.2 DNS方式 DNS方式Service在Kubernetes系统中遵循DNS命名规范,Service的DNS域名表示方法为<servicename>.<namespace>.svc.<clusterdomain>,其中servicename为服务的名称,namespace为其所在namespace的名称, clusterdomain为Kubernetes集群设置的域名后缀(例如cluster.local),服务名称的命名规则遵循gRFC 1123规范的要求。
对于客户端应用来说,DNS域名格式的Service名称提供的是稳定、 不变的访问地址,可以大大简化客户端应用的配置,是Kubernetes集群中推荐的使用方式。 当Service以DNS域名形式进行访问时,就需要在Kubernetes集群中存在一个DNS服务器来完成域名到ClusterIP地址的解析工作了,目前由CoreDNS作为Kubernetes集群的默认DNS服务器提供域名解析服务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 [root@k8s-master01 ~] / Server: 10.96.0.10 Address: 10.96.0.10:53 Name: metrics-server.kube-system.svc.cluster.local Address: 10.96.135.159 / Server: 10.96.0.10 Address: 10.96.0.10:53 Name: kubernetes.default.svc.cluster.local Address: 10.96.0.1
1.3 Label和Selector 1.3.1 简介 1. Label简介 Label(标签)是Kubernetes系统中的另一个核心概念,相当于我们熟悉的“标签”。一个Label是一个key=value键值对,其中的key与value由用户自己指定。Label可以被附加到各种资源对象上,例如Node、 Pod、Service、Deployment等,一个资源对象可以定义任意数量的 Label,同一个Label也可以被添加到任意数量的资源对象上。Label通常在资源对象定义时确定,也可以在对象创建后动态添加或者删除。我们可以通过给指定的资源对象捆绑一个或多个不同的Label来实现多维度的资源分组管理功能,以便灵活、方便地进行资源分配、调度、配置、 部署等管理工作。
2. Selector简介 Label Selector(标签选择器)查询和筛选拥有某些Label的资源对象,Kubernetes通过这种方式实现了类似SQL的简单又通用的对象查询机制。Label Selector可以被类比为SQL语句中的where查询条件,例 如,“name=redis-slave”这个Label Selector作用于Pod时,可以被类比 为select * from pod where name='redis-slave'这样的语句。当前有两种Label Selector表达式:基于等式的(Equality-based)Selector表达式和基于集合的(Set-based)Selector表达式。
基于等式的Selector表达式采用等式类表达式匹配标签:
基于集合的Selector表达式则使用集合操作类表达式匹配标签:
name in (redis-master,redis-slave):匹配所有具有 name=redis-master标签或者name=redis-slave标签的资源对象。
name not in (php-frontend):匹配所有不具有name=php-frontend标签的资源对象。
3. 示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 [root@k8s-master01 ~] node/k8s-node01 labeled node/k8s-node02 labeled [root@k8s-master01 ~] node/k8s-master01 labeled [root@k8s-master01 ~] [root@k8s-master01 ~] NAME STATUS ROLES AGE VERSION k8s-master01 Ready <none> 5d1h v1.23.16 k8s-node01 Ready <none> 5d1h v1.23.16 k8s-node02 Ready <none> 5d1h v1.23.16 [root@k8s-master01 ~] NAME STATUS ROLES AGE VERSION k8s-master02 Ready <none> 5d1h v1.23.16 k8s-master03 Ready <none> 5d1h v1.23.16 k8s-node01 Ready <none> 5d1h v1.23.16 k8s-node02 Ready <none> 5d1h v1.23.16 [root@k8s-master01 ~] NAME STATUS ROLES AGE VERSION k8s-master01 Ready <none> 5d1h v1.23.16 [root@k8s-master01 ~] NAME STATUS ROLES AGE VERSION k8s-master01 Ready <none> 5d1h v1.23.16 [root@k8s-master01 ~] NAME STATUS ROLES AGE VERSION k8s-master01 Ready <none> 5d1h v1.23.16 k8s-node01 Ready <none> 5d1h v1.23.16 k8s-node02 Ready <none> 5d1h v1.23.16
修改标签
未修改之前标签
1 2 3 4 5 6 7 8 9 10 11 [root@k8s-master01 ~] node/k8s-node01 unlabeled node/k8s-node02 unlabeled [root@k8s-master01 ~] node/k8s-node01 labeled node/k8s-node02 labeled [root@k8s-master01 ~]
删除标签
未删除之前截图
1 2 3 4 5 [root@k8s-master01 ~] [root@k8s-master01 ~]
1.4 Service资源创建 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 [root@k8s-master01 ~]# cat >> nginx-svc.yaml <<-EOF --- apiVersion: v1 kind: Service metadata: name: webapp spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 name: nginx --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: nginx name: nginx spec: replicas: 5 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - image: registry.cn-zhangjiakou.aliyuncs.com/taosweet/nginx:1.24.0-alpine name: nginx ports: - containerPort: 80 name: nginx EOF [root@k8s-master01 ~]# kubectl apply -f nginx-svc.yaml service/webapp created deployment.apps/nginx created [root@k8s-master01 ~]# kubectl get -f nginx-svc.yaml
该示例为webapp:80即可访问到具有app=nginx标签的pod的80端口上
需要注意的是,Service能够将一个接收端口映射到任意的targetPort,如果targetPort为空,targetPort将被设置为与Port字段相同的值。targetPort可以设置为一个字符串,引用backendPod的一个端口的名称,这样的话即使更改了Pod的端口,也不会对service的访问造成影响。
Kubernetes Service 能够支持TCP,UDP,SCTP等协议,默认TCP协议
在提供服务的Pod副本集运行过程中,如果Pod列表发生了变化,则Kubernetes的Service控制器会持续监控后端Pod列表的变化,实时更新Service对应的后端Pod列表。一个Service对应的后端由Pod的IP和容器端口号组成,即一个完整的PodIP:ConrainerPort访问地址,这在Kubernetes系统中叫作Endpoint。通过查看Service的详细信息,可以看到其后端Endpoint列表
1 2 $ kubectl get svc -n kube-system
1 2 3 [root@k8s-master01 ~] /
2、Service的负载均衡机制 简介:当一个Service对象在Kubernetes集群中被定义出来时,集群内的客户端应用就可以通过服务IP访问到具体的Pod容器提供的服务了。从服务IP到后端Pod的负载均衡机制,则是由每个Node上的kube-proxy负责实现的。对kube-proxy的代理模式、会话保持机制和基于拓扑感知的服务路由机制(EndpointSlices)。
2.1 kube-proxy的代理模式 目前kube-proxy提供了以下代理模式(通过启动参数–proxy-mode设置)
iptables模式 :kube-proxy通过设置Linux Kernel的iptables规则, 实现从Service到后端Endpoint列表的负载分发规则,效率很高。但是, 如果某个后端Endpoint在转发时不可用,此次客户端请求就会得到失败的响应,此时应该通过为Pod设置 readinessprobe(服务可用性健康检查)来保证只有达到ready状态的Endpoint才会被设置为Service的后端Endpoint。
ipvs模式 :在Kubernetes 1.11版本中达到Stable阶段,kube-proxy通过设置Linux Kernel的netlink接口设置IPVS规则,转发效率和支持的吞吐率都是最高的。ipvs模式要求Linux Kernel启用IPVS模块,如果操作系统未启用IPVS内核模块,kube-proxy则会自动切换至iptables模式。同时,ipvs模式支持更多的负载均衡策略:
rr :round-robin,轮询。
lc :least connection,最小连接数。
dh :destination hashing,目的地址哈希。
sh :source hashing,源地址哈希。
sed :shortest expected delay,最短期望延时。
nq :never queue,永不排队。
3、 Service发布类型
ClusterIP:Kubernetes默认会自动设置Service的虚拟IP地址,仅可被集群内部的客户端应用访问。
NodePort:在所有安装了Kube-Proxy的节点上打开一个端口,此端口可以代理至后端Pod,可以通过NodePort从集群外部访问集群内的服务。
LoadBalancer:将Service映射到一个已存在的负载均衡器的IP地址上,通常在公有云环境中使用。
ExternalName:将Service映射为一个外部域名地址,通过 externalName字段进行设置。
Service对集群之外暴露服务的主要方式有两种:NodePort和LoadBalancer
NodePort方式的缺点是会占用很多集群机器的端口,那么当集群服务变多的时候,这个缺点就愈发明显
LB方式的缺点是每个service需要一个LB,浪费、麻烦,并且需要kubernetes之外设备的支持
3.1 NodePort类型使用 如果将Service的 type字段设置为NodePort,则Kubernetes将从--service-node-port-range参数指定的范围(默认为30000-32767)中自动分配端口,也可以手动指定NodePort,创建该Service后,集群每个节点都将暴露一个端口,通过某个宿主机的IP+端口即可访问到后端的应用。
1 2 3 [root@k8s-master01 ~] --service-node-port-range=30000-32767 \
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [root@k8s-master01 ~] --- apiVersion: v1 kind: Service metadata: name: webapp spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 name: nginx type : NodePort [root@k8s-master01 ~] service/webapp replaced [root@k8s-master01 ~]
3.2 ExternalName Service ExternalName Service是Service的特例,它没有Selector,也没有定义任何端口和Endpoint,它通过返回该外部服务的别名来提供服务。比如可以定义一个Service,后端设置为一个外部域名,这样通过Service的名称即可访问到该域名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [root@k8s-master01 ~]# vim external-service.yaml --- apiVersion: v1 kind: Service metadata: name: external-service spec: type: ExternalName externalName: www.baidu.com [root@k8s-master01 ~]# kubectl create -f external-service.yaml service/external-service created [root@k8s-master01 ~]# kubectl get svc
1 2 3 4 5 [root@k8s-master01 ~] / Connecting to external-service (110.242.68.3:80) wget: server returned error: HTTP/1.1 403 Forbidden
3.3 Service代理Kubernetes集群之外的服务(重点) 普通的Service通过Label Selector对后端Endpoint列表进行了一次抽象,如果后端的Endpoint不是由Pod副本集提供的,则Service还可以抽象定义任意其他服务,将一个Kubernetes集群外部的已知服务定义为Kubernetes内的一个Service,供集群内的其他应用访问,常见的应用场景包括:
希望在生产环境中使用外部的数据库集群,但测试环境使用自己的数据库。
已部署的一个集群外服务,例如数据库服务、缓存服务等。
你正在将工作负载迁移到 Kubernetes。在评估该方法时,你仅在 Kubernetes 中运行一部分后端。
迁移过程中对某个服务进行Kubernetes内的服务名访问机制的验证。
对于这种应用场景,用户在创建Service资源对象时不设置Label Selector(后端Pod也不存在),同时再定义一个与Service关联的Endpoint资源对象,在Endpoint中设置外部服务的IP地址和端口号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 [root@k8s-master01 ~]# vim nginx-svc-external.yaml --- apiVersion: v1 kind: Service metadata: labels: app: nginx-svc-external name: nginx-svc-external spec: ports: - name: http port: 80 protocol: TCP targetPort: 80 type: ClusterIP --- apiVersion: v1 kind: Endpoints metadata: labels: app: nginx-svc-external name: nginx-svc-external subsets: - addresses: - ip: 192.168 .174 .30 - ip: 192.168 .174 .31 ports: - name: http port: 80 protocol: TCP
1 2 3 4 5 6 [root@k8s-master01 ~] service/nginx-svc-external created [root@k8s-master01 ~]
1 2 3 4 5 6 [root@k8s-master01 ~] [root@k8s-master01 ~] /
3.4 多端口Service 使用场景:某些服务对外暴露的端口不只有一个,所以此时需要用到多端口Service(rabbitmq,zookeeper)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 --- apiVersion: v1 kind: Service metadata: labels: k8s-app: kube-dns kubernetes.io/cluster-service: "true" kubernetes.io/name: CoreDNS name: kube-dns spec: - name: dns port: 53 protocol: UDP targetPort: 53 - name: dns-tcp port: 53 protocol: TCP targetPort: 53 - name: metrics port: 9153 protocol: TCP targetPort: 9153 selector: k8s-app: kube-dns type: ClusterIP
如果使用相同的协议,名称不能一样
3.5 LoadBalancer类型(公有云使用) 简介:通常在公有云环境中设置Service的类型为“LoadBalancer”,可以将 Service映射到公有云提供的某个负载均衡器的IP地址上,客户端通过负载均衡器的IP和Service的端口号就可以访问到具体的服务,无须再通过kube-proxy提供的负载均衡机制进行流量转发。公有云提供的LoadBalancer可以直接将流量转发到后端Pod上,而负载分发机制依赖于公有云服务商的具体实现。
3.6 Service支持的网络协议
TCP :Service的默认网络协议,可用于所有类型的Service。
UDP :可用于大多数类型的Service,LoadBalancer类型取决于云服务商对UDP的支持。
HTTP :取决于云服务商是否支持HTTP和实现机制。
PROXY :取决于云服务商是否支持HTTP和实现机制。
SCTP :从Kubernetes 1.12版本引入,到1.19版本时达到Beta阶段,默认启用。
4、Headless Service的概念和应用 简介:在某些应用场景中,客户端应用不需要通过Kubernetes内置Service实现的负载均衡功能,或者需要自行完成对服务后端各实例的服务发现机制,或者需要自行实现负载均衡功能,此时可以通过创建一种特殊的名为“Headless”的服务来实现。 Headless Service的概念是这种服务没有入口访问地址(无ClusterIP 地址),kube-proxy不会为其创建负载转发规则,而服务名(DNS域名)的解析机制取决于该Headless Service是否设置了Label Selector。
4.1 Headless Service设置了Label Selector 如果Headless Service设置了Label Selector,Kubernetes则将根据 Label Selector查询后端Pod列表,自动创建Endpoint列表,将服务名(DNS域名)的解析机制设置为:当客户端访问该服务名时,得到的是全部Endpoint列表(而不是一个确定的IP地址)。
以下面的Headless Service为例,其设置了Label Selector:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 [root@k8s-master01 ~]# vim nginx-headless.yaml --- apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: nginx name: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - image: registry.cn-zhangjiakou.aliyuncs.com/taosweet/nginx:1.24.0-alpine name: nginx resources: requests: cpu: 10m [root@k8s-master test]# kubectl apply -f nginx-headless.yaml [root@k8s-master test]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96 .0 .1 <none> 443 /TCP 9d nginx ClusterIP None <none> 80 /TCP 85s webapp ClusterIP 10.106 .192 .111 <none> 80 /TCP 4h36m [root@k8s-master test]# kubectl get endpoints
==注意:在解析service的时候,应在容器中解析,因为宿主机的DNS和集群内部属于隔离的,在宿主机的命令行中无法解析成功==
5、Ingress:(ingress控制器没有ns隔离性,Ingress有ns隔离性) 5.1 前言 根据前面对Service概念的说明,我们知道Service的表现形式为IP地址和端口号(ClusterIP:Port),即工作在TCP/IP层。而对于基于HTTP 的服务来说,不同的URL地址经常对应到不同的后端服务或者虚拟服务器(Virtual Host),这些应用层的转发机制仅通过Kubernetes的Service机制是无法实现的。
Kubernetes从1.1版本开始引入Ingress资源对象,用于将Kubernetes集群外的客户端请求路由到集群内部的服务上,同时提供7层(HTTP和HTTPS)路由功能。Ingress在Kubernetes 1.19版本时达到v1稳定版本。 Kubernetes使用了一个Ingress策略定义和一个具体提供转发服务的Ingress Controller,两者结合,实现了基于灵活Ingress策略定义的服务路由功能。如果是对Kubernetes集群外部的客户端提供服务,那么Ingress Controller实现的是类似于边缘路由器的功能。需要注意的是,Ingress只能以HTTP和HTTPS提供服务,对于使用其他网络协议的服务,可以通过设置Service的类型(type)为NodePort或LoadBalancer 对集群外部的客户端提供服务。 使用Ingress进行服务路由时,Ingress Controller基于Ingress规则将客户端请求直接转发到Service对应的后端Endpoint(Pod)上,这样会跳过kube-proxy设置的路由转发规则,以提高网络转发效率。 Ingress为Kubernetes集群中的服务提供了入口,可以提供负载均衡、SSL终止和基于名称的虚拟主机,应用的灰度发布等功能;在生产环境中常用的Ingress有Nginx、HAProxy、Istio等。Ingress 公开从集群外部到集群内服务 的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。
1 2 3 4 5 6 7 8 9 10 11 12 upstream api { server 192.168.1.1; server 192.168.1.2; } server { listen 80; server_name www.kengni.com; location /api { proxy_pass http://api; } }
5.2 创建Ingress Controller 官网链接:https://kubernetes.github.io/ingress-nginx/deploy/
简介:Ingress Controller需要实现基于不同HTTP URL向后转发的负载分发规则,并可以灵活设置7层负载分发策略 。目前Ingress Controller已经有许多实现方案,包括Nginx、HAProxy、Kong、Traefik、Istio 等开源软件的实现,以及公有云GCE、Azure、AWS等提供的Ingress应用网关,在Kubernetes中,Ingress Controller会持续监控API Server的/ingress 接口(即用户定义的到后端服务的转发规则)的变化。当/ingress接口后端的服务信息发生变化时,Ingress Controller会自动更新其转发规则。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 [root@k8s-master01 ~] --- apiVersion: v1 kind: Namespace metadata: labels: app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx name: ingress-nginx --- apiVersion: v1 automountServiceAccountToken: true kind: ServiceAccount metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx namespace: ingress-nginx --- apiVersion: v1 kind: ServiceAccount metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx-admission namespace: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 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: - coordination.k8s.io resourceNames: - ingress-nginx-leader resources: - leases verbs: - get - update - apiGroups: - coordination.k8s.io resources: - leases verbs: - create - apiGroups: - "" resources: - events verbs: - create - patch - apiGroups: - discovery.k8s.io resources: - endpointslices verbs: - list - watch - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx-admission namespace: ingress-nginx rules: - apiGroups: - "" resources: - secrets verbs: - get - create --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx rules: - apiGroups: - "" resources: - configmaps - endpoints - nodes - pods - secrets - namespaces verbs: - list - watch - apiGroups: - coordination.k8s.io resources: - leases 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 - apiGroups: - discovery.k8s.io resources: - endpointslices verbs: - list - watch - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx-admission rules: - apiGroups: - admissionregistration.k8s.io resources: - validatingwebhookconfigurations verbs: - get - update --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 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 --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx-admission namespace: ingress-nginx roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: ingress-nginx-admission subjects: - kind: ServiceAccount name: ingress-nginx-admission namespace: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: ingress-nginx subjects: - kind: ServiceAccount name: ingress-nginx namespace: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx-admission roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: ingress-nginx-admission subjects: - kind: ServiceAccount name: ingress-nginx-admission namespace: ingress-nginx --- apiVersion: v1 data: allow-snippet-annotations: "true" kind: ConfigMap metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx-controller namespace: ingress-nginx --- apiVersion: v1 kind: Service metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx-controller namespace: ingress-nginx spec: ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - appProtocol: http name: http port: 80 protocol: TCP targetPort: http - appProtocol: https name: https port: 443 protocol: TCP targetPort: https selector: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx type : NodePort --- apiVersion: v1 kind: Service metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx-controller-admission namespace: ingress-nginx spec: ports: - appProtocol: https name: https-webhook port: 443 targetPort: webhook selector: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx type : ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx-controller namespace: ingress-nginx spec: minReadySeconds: 0 revisionHistoryLimit: 10 selector: matchLabels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx template: metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx spec: containers: - args: - /nginx-ingress-controller - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller - --election-id=ingress-nginx-leader - --controller-class=k8s.io/ingress-nginx - --ingress-class=nginx - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller - --validating-webhook=:8443 - --validating-webhook-certificate=/usr/local /certificates/cert - --validating-webhook-key=/usr/local /certificates/key 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 image: registry.cn-hangzhou.aliyuncs.com/hujiaming/nginx-ingress-controller:v1.6.4 imagePullPolicy: IfNotPresent lifecycle: preStop: exec : command : - /wait -shutdown livenessProbe: failureThreshold: 5 httpGet: path: /healthz port: 10254 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 name: controller ports: - containerPort: 80 name: http protocol: TCP - containerPort: 443 name: https protocol: TCP - containerPort: 8443 name: webhook protocol: TCP readinessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 resources: requests: cpu: 100m memory: 90Mi securityContext: allowPrivilegeEscalation: true capabilities: add: - NET_BIND_SERVICE drop: - ALL runAsUser: 101 volumeMounts: - mountPath: /usr/local /certificates/ name: webhook-cert readOnly: true dnsPolicy: ClusterFirst nodeSelector: kubernetes.io/os: linux serviceAccountName: ingress-nginx terminationGracePeriodSeconds: 300 volumes: - name: webhook-cert secret: secretName: ingress-nginx-admission --- apiVersion: batch/v1 kind: Job metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx-admission-create namespace: ingress-nginx spec: template: metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx-admission-create spec: containers: - 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 image: registry.cn-beijing.aliyuncs.com/dotbalo/kube-webhook-certgen:v20220916-gd32f8c343 imagePullPolicy: IfNotPresent name: create securityContext: allowPrivilegeEscalation: false nodeSelector: kubernetes.io/os: linux restartPolicy: OnFailure securityContext: fsGroup: 2000 runAsNonRoot: true runAsUser: 2000 serviceAccountName: ingress-nginx-admission --- apiVersion: batch/v1 kind: Job metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx-admission-patch namespace: ingress-nginx spec: template: metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx-admission-patch spec: containers: - 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 image: registry.cn-hangzhou.aliyuncs.com/hujiaming/kube-webhook-certgen:v20220916-gd32f8c343 imagePullPolicy: IfNotPresent name: patch securityContext: allowPrivilegeEscalation: false nodeSelector: kubernetes.io/os: linux restartPolicy: OnFailure securityContext: fsGroup: 2000 runAsNonRoot: true runAsUser: 2000 serviceAccountName: ingress-nginx-admission --- apiVersion: networking.k8s.io/v1 kind: IngressClass metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: nginx spec: controller: k8s.io/ingress-nginx --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: labels: app.kubernetes.io/component: admission-webhook app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.6.4 name: ingress-nginx-admission webhooks: - admissionReviewVersions: - v1 clientConfig: service: name: ingress-nginx-controller-admission namespace: ingress-nginx path: /networking/v1/ingresses failurePolicy: Fail matchPolicy: Equivalent name: validate.nginx.ingress.kubernetes.io rules: - apiGroups: - networking.k8s.io apiVersions: - v1 operations: - CREATE - UPDATE resources: - ingresses sideEffects: None [root@k8s-master01 ~] namespace/ingress-nginx created serviceaccount/ingress-nginx created serviceaccount/ingress-nginx-admission created role.rbac.authorization.k8s.io/ingress-nginx created role.rbac.authorization.k8s.io/ingress-nginx-admission created clusterrole.rbac.authorization.k8s.io/ingress-nginx created clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created rolebinding.rbac.authorization.k8s.io/ingress-nginx created rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created configmap/ingress-nginx-controller created service/ingress-nginx-controller created service/ingress-nginx-controller-admission created deployment.apps/ingress-nginx-controller created job.batch/ingress-nginx-admission-create created job.batch/ingress-nginx-admission-patch created ingressclass.networking.k8s.io/nginx created
测试访问ingress-nginx的svc
1 2 3 4 5 6 7 8 [root@k8s-master01 ~] <html> <head><title>404 Not Found</title></head> <body> <center><h1>404 Not Found</h1></center> <hr><center>nginx</center> </body> </html>
5.3 域名发布服务 5.3.1 创建web服务 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 [root@k8s-master01 ~]# vim nginx-deploy.yaml --- apiVersion: v1 kind: Service metadata: name: webapp spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 name: nginx --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: nginx name: nginx spec: replicas: 5 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - image: registry.cn-zhangjiakou.aliyuncs.com/taosweet/nginx:1.24.0-alpine name: nginx ports: - containerPort: 80 name: nginx [root@k8s-master01 ~]# kubectl create -f nginx-deploy.yaml deployment.apps/nginx created [root@k8s-master01 ~]# kubectl get svc
5.3.2 创建Ingress 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [root@k8s-master01 ~]# vim nginx-ingress-file.yaml --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx-ingress spec: ingressClassName: nginx rules: - host: ingress.tanke.love http: paths: - backend: service: name: webapp port: number: 80 path: / pathType: ImplementationSpecific [root@k8s-master01 ~]# kubectl create -f nginx-ingress-file.yaml ingress.networking.k8s.io/nginx-ingress created
5.3.3 路由的匹配方式 Ingress中的每个路径都需要有对应的路径类型(Path Type)。未明确设置 pathType 的路径无法通过合法性检查。当前支持的路径类型有三种:
1 2 3 4 5 6 7 8 9 [root@k8s-master01 ~] HTTP/1.1 200 OK Date: Tue, 20 Dec 2022 08:13:34 GMT Content-Type: text/html Content-Length: 612 Connection: keep-alive Last-Modified: Sat, 11 May 2019 00:35:53 GMT ETag: "5cd618e9-264" Accept-Ranges: bytes
一旦Ingress资源成功创建,Ingress Controller就会监控到其配置的路由策略,并更新到Nginx的配置文件中生效。以本例中的Nginx Controller为例,它将更新其配置文件的内容为在Ingress中设定的路由策略。登录一个nginx-ingress-controller Pod,在/etc/nginx/nginx.conf可以看到对ingress.tanke.love的转发规则的正确配置 :
1 2 [root@k8s-master ingress]
1 2 3 4 [root@k8s-master01 ~] ingress-nginx-controller-8556b74844-s9fwk:/etc/nginx$ grep -A 20 "ingress.tanke.love" nginx.conf
5.3.4 不配置域名发布服务(了解) 在Kubernetes Ingress中,通常需要配置域名(Host)来指定外部请求的路由目标,但在某些情况下,您可能不想或不需要配置域名。您可以通过配置一个没有域名的Ingress资源来发布服务,这样所有请求都会匹配该Ingress规则,不论其Host头部是什么。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 [root@k8s-master01 ~] --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: no-host-ingress spec: ingressClassName: nginx rules: - http: paths: - backend: service: name: webapp port: number: 80 path: /no-host pathType: prefix [root@k8s-master01 ~] ingress.networking.k8s.io/no-host created [root@k8s-master01 ~] 执行结果: NAME CLASS HOSTS ADDRESS PORTS AGE nginx-ingress nginx nginx.test.com 10.96.121.23 80 109m no-host nginx * 10.96.121.23 80 115s [root@k8s-master01 ~] 执行结果: NAME READY STATUS RESTARTS AGE ingress-nginx-admission-create-dl2rg 0/1 Completed 0 51m ingress-nginx-admission-patch-svpd4 0/1 Completed 1 51m ingress-nginx-controller-84c544699d-bb9xm 1/1 Running 0 51m [root@k8s-master01 ~] HTTP/1.1 404 Not Found Date: Tue, 20 Dec 2022 08:59:16 GMT Content-Type: text/html Content-Length: 154 Connection: keep-alive