Kubernetes流量负载:Service与Ingress全解析(K8s)

文章目录

  • 一、Service
    • [1.1 Service介绍](#1.1 Service介绍)
    • [1.2 Service类型](#1.2 Service类型)
      • [1.2.1 创建Server前准备](#1.2.1 创建Server前准备)
      • [1.2.2 ClusterlP类型的Service](#1.2.2 ClusterlP类型的Service)
      • [1.2.3 HeadLiness类型的Service](#1.2.3 HeadLiness类型的Service)
      • [1.2.4 NodePort类型的Service](#1.2.4 NodePort类型的Service)
      • [1.2.5 LoadBalancer类型的Service](#1.2.5 LoadBalancer类型的Service)
      • [1.2.6 ExternalName类型的Service](#1.2.6 ExternalName类型的Service)
  • 二、Ingress
    • [2.1 Ingress介绍](#2.1 Ingress介绍)
    • [2.2 Ingress使用](#2.2 Ingress使用)

一、Service

1.1 Service介绍

pod是应用程序的载体,我们可以通过pod的ip来访问应用程序,但是pod的ip地址不是固定的,这也就意味着不方便直接采用pod的ip对服务进行访问。
Service :对提供同一个服务的多个pod进行聚合,并且提供一个统一的入口地址。通过访问Service的入口地址就能访问到后面的pod服务。

每个Node节点上都运行着一个kube-proxy服务进程。当创建Service的时候会通过api-server向etcd写入创建的service的信息,而kube-proxy会基于监听的机制发现这种Service的变动,然后它会将最新的Service信息转换成对应的访问规则。

10.97.97.97:80 是service提供的访问入口,当访问这个入口的时候,可以发现后面有三个pod的服务在等待调用,kube-proxy会基于rr(轮询)的策略,将请求分发到其中一个pod上去,这个规则会同时在集群内的所有节点上都生成,所以在任何一个节点上访问都可以。
ipvsadm -Ln

1.2 Service类型

用于定义一组 Pod 的访问策略,实现负载均衡和服务发现

yaml 复制代码
kind: Service    # 资源类型
apiVersion: v1   # 资源版本
metadata:        # 元数据
  name: service  # 资源名称
  namespace: dev # 命名空间
spec:     # 描述
  selector:    # 标签选择器,用于确定当前service代理哪些pod
    app: nginx
  type:          # Service类型,指定service的访问方式
  clusterIP:     # 虚拟服务的ip地址
  sessionAffinity: # session亲和性,支持ClientIP、None两个选项
  ports:         # 端口信息
    - protocol: TCP
      port: 3017       # service端端口
      targetPort: 5003 # pod端口
      nodePort: 31122  # 主机端口

1.2.1 创建Server前准备

在使用service之前,首先利用Deployment创建出3个pod,注意要为pod设置app=nginx-pod的标签

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pc-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
		metadata:
			labels:
				app: nginx-pod
		spec:
			containers:
			- name: nginx
				image: nginx:1.17.1
				ports:
				- containerPort: 80

创建:kubectl create -f deployment.yaml

查看pod详情:kubectl get pods -n dev -o wide --show-labels

为了方便后面的测试,修改下三台nginx的index.html页面(三台修改的IP地址不一致)

kubectl exec -it pc-deployment-66cb59b984-8p84h -n dev /bin/sh

echo "10.244.1.40"> /usr/share/nginx/html/index.html

修改完毕之后,访问测试:curl 10.244.1.40curl 10.244.2.33curl 10.244.1.39

1.2.2 ClusterlP类型的Service

ClusterIP 是 Kubernetes Service 的默认类型,为集群内部提供稳定的虚拟 IP 和负载均衡功能。其流量负载机制基于以下核心组件和策略:EndpointSlice 与 Endpointskube-proxy 的负载均衡

EndpointSlice 与 Endpoints

Endpoint 是 Kubernetes 中记录 Service 后端实际 Pod IP 和端口的资源对象,由 Endpoint Controller 自动管理。Service 通过 Selector 匹配 Pod 并动态更新 Endpoint,实现流量负载均衡
自动维护 :当 Pod 因扩缩容或故障发生变化时,Endpoint 自动更新。
与 Service 关联 :每个 Service 默认生成同名 Endpoint,存储符合条件的 Pod 地址列表。
手动配置 :支持不依赖 Selector 的 Service,通过自定义 Endpoint 指向外部服务(如数据库)。

查看:kubectl get endpoints -n dev -o wide
动态负载均衡:默认情况下,Service 通过 Selector 选择 Pod,Endpoint 自动填充

yaml 复制代码
# Service 定义示例
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

指向外部服务:若需将 Service 流量导向集群外服务(如云数据库),可手动创建 Endpoint

yaml 复制代码
# 无 Selector 的 Service
apiVersion: v1
kind: Service
metadata:
  name: external-db
spec:
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306
---
# 手动定义 Endpoint
apiVersion: v1
kind: Endpoints
metadata:
  name: external-db
subsets:
  - addresses:
      - ip: 192.168.1.100  # 外部服务 IP
    ports:
      - port: 3306

kube-proxy 的负载均衡

每个节点上的 kube-proxy 组件负责实现 Service 的虚拟 IP 到后端 Pod 的流量转发,支持三种模式:
iptables 模式 :默认模式,通过随机选择规则实现负载均衡。kube-proxy为service后端的每个Pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个PodIP。该模式下kube-proxy不承担四层负责均衡器的角色,只负责创建iptables规则。该模式的优点是较userspace模式效率更高,但不能提供灵活的LB策略,当后端Pod不可用时也无法进行重试
ipvs 模式 :基于内核级负载均衡,支持更丰富的调度算法(如 rr、wrr、lc 等)。ipvs模式和iptables类似,kube-proxy监控Pod的变化并创建相应的ipvs规则。ipvs相对iptables转发效率更高。除此以外,ipvs支持更多的LB算法
userspace 模式(已弃用):为每一个Service创建一个监听端口,发向ClusterIP的请求被Iptables规则重定向到kube-proxy监听的端口上,kube-proxy根据LB算法选择一个提供服务的Pod并和其建立链接,以将请求转发到Pod上。该模式下,kube-proxy充当了一个四层负责均衡器的角色。由于kube-proxy运行在userspace中,在进行转发处理时会增加内核和用户空间之间的数据拷贝,虽然比较稳定,但是效率比较低
ipvs 模式必须安装ipvs内核模块,否则会降级为iptables,开启ipvs:
kubectl edit cm kube-proxy -n kube-system
kubectl delete pod -l k8s-app=kube-proxy -n kube-system
ipvsadm -Ln

负载分发策略

默认:如果不定义则默认为轮询
sessionAffinity:ClientIP:会话保持,来自同一个客户端发起的所有请求都会转发到固定的一个Pod上
查看ipvs的映射规则rr轮询:ipvsadm -Ln

循环访问测试:while true;do curl 10.97.97.97:80; sleep 5; done;

修改分发策略----sessionAffinity: ClientIP

查看ipvs规则[persistent 代表持久]:ipvsadm -Ln

循环访问测试:while true;do curl 10.97.97.97:80; sleep 5; done;

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: service-clusterip
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: 10.97.97.97 # service的ip地址,如果不写,默认会生成一个
  type: ClusterIP
	ports:
	- port: 80        # Service端口
	  targetPort: 80  # pod端口

启用会话保持

yaml 复制代码
spec:
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 3600

创建service:kubectl create -f service-clusterip.yaml

查看service:kubectl get svc -n dev -o wide

查看service的详细信息:kubectl describe svc service-clusterip -n dev

在这里有一个Endpoints列表,里面就是当前service可以负载到的服务入口

查看ipvs的映射规则:ipvsadm -Ln

访问10.97.97.97:80观察效果:curl 10.97.97.97:80

1.2.3 HeadLiness类型的Service

在某些场景中,开发人员可能不想使用Service提供的负载均衡功能,而希望自己来控制负载均衡策略,针对这种情况,kubernetes提供了HeaitLiness Service,这类Service不会分配Cluster IP,如果想要访问service,只能通过service的域名进行查询。

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: service-headliness
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None # 将clusterIP设置为None,即可创建headliness Service
  type: ClusterIP
	ports:
	- port: 80
	  targetPort: 80 

创建service:kubectl create -f service-headliness.yaml

获取service,发现CLUSTER-IP未分配:kubectl get svc service-headliness -n dev -o wide

查看service详情:kubectl describe svc service-headliness -n dev

查看域名的解析情况:kubectl exec -it pc-deployment-66cb59b984-8p84h -n dev /bin/shcat /etc/resolv.conf
dig @10.96.0.10 service-headliness.dev.svc.cluster.local (10.96.0.10为上面查询到的)

1.2.4 NodePort类型的Service

在之前的样例中,创建的Service的ip地址只有集群内部才可以访问,如果希望将Service暴露给集群外部使用,那么就要使用到另外一种类型的Service,称为NodePort类型。NodePort的工作原理其实就是将service的端口映射到Node的一个端口上 ,然后就可以通过NodeIp:NodePort来访问service了。

特点

外部流量直接到达节点,再由 kube-proxy 转发到 Pod。

需要手动管理节点 IP 变化

适用场景

开发测试环境或简单外部访问需求

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: service-nodeport
  namespace: dev
spec:
  selector:
    app: nginx-pod
  type: NodePort # service类型
	ports:
	- port: 80
	  nodePort: 30002 #指定綁定的node的端口(默认的取值范围是:30000-32767),如果不指定,会默认分配
	  targetPort: 80 

创建service:kubectl create -f service-nodeport.yaml

查看service:kubectl get svc -n dev -o wide

接下来可以通过电脑主机的浏览器去访问集群中任意一个nodeip的30002端口,即可访问到pod

1.2.5 LoadBalancer类型的Service

LoadBalancer和NodePort很相似,目的都是向外部暴露一个端口,区别在于LoadBalancer会在集群的外部再来做一个负载均衡设备,而这个设备需要外部环境支持的,外部服务发送到这个设备上的请求,会被设备负载之后转发到集群中。

特点

自动创建外部负载均衡器。

通常结合 NodePort 实现(流量先到 LB,再转发到节点)

适用场景

生产环境,需高可用外部访问

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
	name: service-externalname
	namespace: dev
spec:
	type: ExternalName # service类型
	externalName: www.baidu.com #改成ip地址也可以

1.2.6 ExternalName类型的Service

ExternalName类型的Service用于引入集群外部的服务,它通过externalName属性指定外部一个服务的地址,然后在集群内部访问此service就可以访问到外部的服务了。

特点

返回 CNAME 记录,无 Pod 选择器

适用场景

集成集群外服务,如 AWS RDS

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
	name: service-externalname
	namespace: dev
spec:
	type: ExternalName # service类型
	externalName: www.baidu.com #改成ip地址也可以

创建service:kubectl create -f service-externalname.yaml

域名解析:dig @10.96.0.10 service-externalname.dev.svc.cluster.local

二、Ingress

2.1 Ingress介绍

在前面课程中已经提到,Service对集群之外暴露服务的主要方式有两种:NotePort和LoadBalancer,但是这两种方式,都有一定的缺点:

NodePort方式的缺点是会占用很多集群机器的端口,那么当集群服务变多的时候,这个缺点就愈发明显

LB方式的缺点是每个service需要一个LB,浪费、麻烦,并且需要kubernetes之外设备的支持
基于这种现状,kubernetes提供了Ingress资源对象,Ingress只需要一个NodePort或者一个LB就可以满足暴露多个Service的需求。工作机制大致如下图表示

实际上,Ingress相当于一个7层的负载均衡器,是kubernetes对反向代理的一个抽象,它的工作原理类似于Nginx,可以理解成在Ingress里建立诸多映射规则,Ingress Controller通过监听这些配置规则并转化成Nginx的反向代理配置,然后对外部提供服务。在这里有两个核心概念:
ingress :kubernetes中的一个对象,作用是定义请求如何转发到service的规则
ingress controller:具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发,实现方式有很多,比如Nginx,Contour, Haproxy等等
Ingress(以Nginx为例)的工作原理如下:

1.用户编写Ingress规则,说明哪个域名对应kubernetes集群中的哪个Service

2.Ingress控制器动态感知Ingress服务规则的变化,然后生成一段对应的Nginx配置

3.Ingress控制器会将生成的Nginx配置写入到一个运行着的Nginx服务中,并动态更新

4.到此为止,其实真正在工作的就是一个Nginx了,内部配置了用户定义的请求转发规则

2.2 Ingress使用

环境准备

搭建ingress环境

创建文件夹:mkdir ingress-controllercd ingress-controller/

获取ingress-nginx,本次案例使用的是0.30版本
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml

修改mandatory.yaml文件中的仓库

修改quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0

为quay-mirror.qiniu.com/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0

创建ingress-nginx:kubectl apply -f ./

查看ingress-nginx:kubectl get pod -n ingress-nginx

查看service:kubectl get svc -n ingress-nginx
准备service和pod

为了后面的实验比较方便,创建如下图所示的模型

创建文件

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: dev
spec:
	replicas: 3
	selector:
		matchLabels:
			app: nginx-pod
  template:
		metadata:
			labels:
				app: nginx-pod
		spec:
			containers:
			- name: nginx
			  image: nginx:1.17.1
			  ports:
			  - containerPort: 80

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deployment
  namespace: dev
spec:
	replicas: 3
	selector:
		matchLabels:
			app: tomcat-pod
  template:
		metadata:
			labels:
				app: tomcat-pod
		spec:
			containers:
			- name: tomcat
			  image: tomcat:8.5-jre10-slim
			  ports:
			  - containerPort: 8080

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: dev
spec:
	selector:
		app: nginx-pod
  clusterIP: None
  type: ClousterIP
  ports:
    - port: 80
      targetPort: 80

---

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
  namespace: dev
spec:
	selector:
		app: tomcat-pod
  clusterIP: None
  type: ClousterIP
  ports:
    - port: 8080
      targetPort: 8080

创建: kubectl create -f tomcat-nginx.yaml

查看:kubectl get svc -n dev

Http代理

创建文件

yaml 复制代码
apiVersion: extensions/v1
beta1kind: Ingress
metadata:
	name: ingress-http
	namespace: dev
spec:
	rules:
	- host: nginx.localhost.com   # 通过域名访问
	  http:
	    paths:
			- path: /  # 结合host
				backend:
					serviceName: nginx-service
					servicePort: 80
	- host: tomcat.localhost.com
	http:
		paths:
		- path: /
			backend:
		    serviceName: tomcat-service
		    servicePort: 8080

创建:kubectl create -f ingress-http.yaml

查看:kubectl get ing ingress-http -n dev

查看详情:kubectl describe ing ingress-http -n dev

本机host文件C:\Windows\System32\drivers\etc\hosts添加如下内容(用于域名解析):
192.168.109.100 nginx.localhost.com
192.168.109.100 tomcat.localhost.com

浏览器访问:http://nginx.localhost.com:32240

https代理

生成证书:openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=BJ/L=BJ/0=nginx/CN=localhost.com"

创建密钥:kubectl create secret tls tls-secret --key tls.key --cert tls.crt
创建文件

yaml 复制代码
apiVersion: extensions/v1
beta1kind: Ingress
metadata:
	name: ingress-https
	namespace: dev
spec:
	tls:
		- hosts:
			- nginx.localhost.com
			- tomcat.localhost.com
			secretName: tls-secret # 指定秘钥
	rules:
	- host: nginx.localhost.com
		http:
		paths:
		- path: /
			backend: 
			  serviceName: nginx-service
			  servicePort: 80
	- host: tomcat.localhost.com
		http:
			paths:
			- path: /
				backend:
					serviceName: tomcat-service
					servicePort: 8080

创建:kubectl create -f ingress-https.yaml

查看:kubectl get ing ingress-https -n dev

查看详情:kubectl describe ing ingress-https -n dev

下面可以通过浏览器访问https://nginx.localhost.com:31335 和 https://tomcat.localhost.com:31335来查看了(kubectl get svc -n ingress-nginx查看端口)

相关推荐
w_t_y_y2 小时前
工具Cursor(五)Rules&Skill
java·开发语言
岁岁种桃花儿2 小时前
企业级K8s集群两层Nginx架构实战:Ingress Controller独立部署与动态伸缩全解析
nginx·架构·kubernetes
h7ml2 小时前
企业微信“群机器人”消息合并转发:用Disruptor做环形队列的Java实例
java·机器人·企业微信
颇有几分姿色2 小时前
Spring Boot Actuator未授权访问漏洞 【原理扫描】修复
java·spring boot·后端
1candobetter2 小时前
JAVA后端开发——Spring Boot 多环境配置与实践
java·开发语言·spring boot
玄德公笔记2 小时前
Prometheus监控k8s的metric详解(第二版)-01-scrape 指标抓取
kubernetes·k8s·prometheus·监控·metric·scrape·k8s监控
沛沛老爹2 小时前
Web开发者实战:多模态Agent技能开发——语音交互与合成技能集成指南
java·开发语言·前端·人工智能·交互·skills
Wpa.wk2 小时前
Docke-compose 搭建 testLink环境
java·经验分享·测试工具·容器·testlink
小北方城市网2 小时前
Spring Boot Actuator+Prometheus+Grafana 生产级监控体系搭建
java·spring boot·python·rabbitmq·java-rabbitmq·grafana·prometheus