service-四层负载均衡
概念、原理解读
为什么要有 Service
在Kubernetes 中,Pod 具有生命周期。如果pod 重新启动,其IP 可能会发生变化。所有服务都有Pod 的硬编码IP 地址,如果某个Pod 挂起或重新启动,与刚刚重新启动的Pod 关联的其他服务将无法找到与其关联的Pod。为了解决这个问题,定义:服务可以通过服务访问入口访问该服务背后的应用集群实例。该服务可以访问这组pod。通常通过标签选择器实现。
Pod IP 经常变化。当客户端访问它时,它只需要访问服务,并且请求被代理到pod,因此它无法访问k8s集群之外的任何内容。可以从k8s 集群外部访问该服务。
概述
该服务是固定访问层。客户端可以通过访问服务的IP 和端口来访问与您的服务关联的后端Pod。该服务依赖于部署到Kubernetes 集群的附件:Kubernetes DNS 服务。 Kubernetes 版本默认使用不同的DNS。 1.11 之前的版本使用kubeDN,较新的版本使用coredns。因此,您必须重新安装k8s 才能部署DNS 附件。您必须依赖第三方网络插件(flannel、calico 等)来为您的客户端提供网络功能。每个K8s 节点都有一个名为kube-proxy 的组件,它不断监控apiserver 的服务资源的变化信息,并且必须随时连接到apiserver。要在服务资源的内容发生更改(创建、删除等)时获取有关apiserver 的信息,请使用Kubernetes 特定的请求方法watch(监视)使用kube-proxy。这些规则实现了当前节点上的服务资源调度,并允许您将请求调度到后端特定的Pod资源。该规则可以是iptables 或ipvs,具体取决于服务的实现方式。
工作原理
k8s 创建Service 时,会根据标签选择器搜索Pod,并创建与Service 同名的Endpoint 对象。如果Pod 地址发生变化,端点也会相应变化。当服务发出请求时,它会接收前端客户端并使用端点来定位地址转发到的Pod 进行访问。 (负载均衡kube-proxy决定Pod转发到哪个节点。)
三类 IP 地址
节点网络:物理或虚拟节点的网络(例如ens33接口的网络地址)
Pod网络,创建的Pod的IP地址
[root@k8s01 控制器]# kubectl get pods -o Wide
名称就绪状态重启年龄IP 节点指定节点就绪门
myapp-v1-75fb478d6c-4j2sx 1/1 运行0 27 米10.244.236.165 k8s02 无无
myapp-v1-75fb478d6c-4j8p6 1/1 运行0 27 米10.244.236.164 k8s02 无无
集群网络(集群地址,也称为服务网络)。该地址是虚拟地址(virtual lip),没有在特定接口上配置,仅出现在服务规则中。
[root@k8s01 控制器]# kubectl 获取svc
名称类型集群IP 外部IP 端口期限
kubernetes ClusterIP 10.96.0.1 无443/TCP 2d21h
创建 Service 资源
#检查定义服务资源所需的字段
[root@k8s01 控制器]# kubectl 解释服务
KIND:服务
版本: v1
描述:
服务是软件服务的命名抽象(例如mysql)
配置代理侦听的本地端口(例如3306),
确定哪个pod 将响应提交的请求的选择器
代理人。
字段:
API版本字符串
#service 资源使用的API 组
输入字符串
#创建的资源类型
元数据对象
#定义元数据
规格对象
状态对象
#检查服务规范字段是如何定义的
[root@k8s01 控制器]# kubectl 解释service.spec
KIND:服务
版本: v1
RESOURCE: 规范对象
描述:
规范定义了服务的行为。
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
ServiceSpec 描述您在服务上创建的属性。
字段:
分配LoadBalancerNodePortsboolean
集群ip字符串
*动态分配的地址可以在创建时指定,但创建后不能更改。
集群IP[] 字符串
externalIPs[] 字符串
外部名称字符串
外部流量策略字符串
healthCheckNodePortinteger
ipFamilies[] 字符串
ipFamilyPolicy字符串
负载均衡器IP 字符串
loadBalancerSourceRanges[]字符串
端口[]对象
#定义与后端pod建立连接的服务端口
publicNotReadyAddresses 布尔值
选择器映射[字符串] 字符串
#使用标签选择器选择相关的pod
会话关联字符串
#service在实现负载均衡时也支持sessionAffinity。 sessionAffinity是什么意思?会话联系。默认为无,随机调度(基于iptables 规则)。为sessionAffinity 定义客户端IP 可确保来自同一客户端的IP 请求被调度到同一pod。
会话亲和性配置对象
sessionAffinityConfig 包含会话亲和性配置。
拓扑键[]字符串
输入字符串
#定义服务类型
Service 的四种类型
检查#Service.spec.type 定义所需的字段
[root@k8s01 控制器]# kubectl 解释service.spec.type
KIND:服务
版本: v1
FIELD: 类型字符串
描述:
类型决定了服务的公开方式。默认为ClusterIP。
选项包括ExternalName、ClusterIP、NodePort 和LoadBalancer。
“ClusterIP”分配集群内部IP地址以实现负载平衡。
端点由选择器或其他方式确定。
通过手动构造Endpoints 对象或EndpointSlice 来指定。
目的。如果clusterIP 为“None”,则不分配虚拟IP,并且
端点作为一组端点而不是虚拟IP 公开。
“NodePort”构建在ClusterIP 之上,为每个节点分配一个端口。
路由到构建“LoadBalancer”的同一端点。
使用NodePort 创建外部负载均衡器(如果当前负载均衡器支持)
Cloud)路由到与clusterIP 相同的端点。
其他几个字段将此服务别名为指定的externalName。
不适用于外部名称服务。 详细信息:
https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types
外部名称:
适合k8s集群内部容器访问外部资源,没有选择器,也没有定义端口或端点。 *以下服务定义将prod 命名空间中的my-service 服务映射到my.database.example.com。
api版本: v1
kind:服务
元数据:
name: 我的服务
命名空间:产品
规格:
type: 外部名称
externalName: my.database.example.com
当您查询主机my-service.prod.svc.cluster.local 时,集群DNS 返回值为my.database.example.com 的CNAME 记录。
服务的FQDN 为:service_name.svc.cluster.local
例如上面的例子:my-service.prod.svc.cluster.local
集群IP:
通过k8s集群内部IP公开服务如果选择该值,则该服务只能在集群内部访问。这也是默认的服务类型。
节点端口:
Node 通过每个节点的IP和静态端口暴露k8s集群中的服务。您可以通过请求: 将请求代理到内部Pod。
客户端—–NodeIP:NodePort—-服务Ip:ServicePort—-PodIP:ContainerPort。
负载平衡器:
可以使用云提供商的负载均衡器向外部公开服务。外部负载均衡器可以路由到NodePort 和ClusterIP 服务。
Service 的端口
#检查服务的spec.ports字段是如何定义的
[root@k8s01controller]# kubectl 解释service.spec.ports
KIND:服务
版本: v1
RESOURCE: 端口[] 对象
描述:
此服务公开的端口列表。详细信息:
https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies
ServicePort 包含有关服务端口的信息。
字段:
应用程序协议字符串
名称字符串
#定义端口名称
节点端口整数
|#主机上的映射端口。例如,如果您的Web 应用程序需要由k8s 集群外部的其他用户访问,则必须配置type=NodePort。如果配置nodePort=30001,则其他机器可以访问scheme : //k8s可以使用ip:30001(例如http://192.168.1.63:30001)通过浏览器访问服务。如果在k8s上部署MySQL数据库,则不需要配置NodePort,因为MySQL不需要外部访问,只需从内部服务访问即可。
端口整数-必填-
#服务端口。这是可以访问k8s集群内部服务的端口。
协议字符串
此端口的IP 协议支持“TCP”、“UDP”和“SCTP”。
这是TCP。
目标端口字符串
# targetPort 是pod 上的端口。来自端口和节点端口的流量通过kube-proxy 到达后端pod 的targetPort,最后进入容器。例如nginx官方暴露了80端口,与创建容器时暴露的端口一致(使用DockerFile中的EXPOSE)。
ClusterIP
创建一个Pod
podtest.yaml
apiVersion: 应用程序/v1
kind:的部署
元数据:
name: my-nginx
规格:
复制品: 2
选择器:
匹配标签:
run: my-nginx
模板:
元数据:
标签:
run: my-nginx
规格:
集装箱:
– name: my-nginx
图片: nginx:最新
imagePullPolicy: 如果不存在
端口:
-containerPort: 80 # Pod 中的容器必须公开的端口
[root@k8s01服务]# kubectl apply -f pod_test.yaml
已创建deployment.apps/my-nginx
#显示刚刚创建的Pod IP地址
[root@k8s01 服务]# kubectl get pods -o Wide
名称就绪状态重启年龄IP 节点指定节点就绪门
my-nginx-65fc647b5d-gc5zh 1/1 运行0 29 秒10.244.236.167 k8s02 无无
my-nginx-65fc647b5d-tf2vz 1/1 运行0 29 秒10.244.236.166 k8s02 无无
请求pod 的IP 地址并查看结果
[root@k8s01服务]# kubectl exec -it my-nginx-65fc647b5d-tf2vz — /bin/bash
请注意,尽管Pod 定义了容器端口,但未使用为该节点安排的端口80,也未使用任何特定NAT 规则将流量路由到该Pod。 这意味着您可以使用同一容器端口在同一节点上运行多个Pod,并使用集群中其他Pod 或节点的IP 访问它们。
其中一个Pod 被意外删除:
[root@k8s01 服务]# kubectl get pods -o Wide
名称就绪状态重启年龄IP 节点指定节点就绪门
my-nginx-65fc647b5d-gc5zh 1/1 运行0 8 分38 秒10.244.236.167 k8s02 无无
my-nginx-65fc647b5d-tf2vz 1/1 运行0 8 分38 秒10.244.236.166 k8s02 无无
[root@k8s01 服务]# kubectl 删除pod my-nginx-65fc647b5d-gc5zh
Pod \’my-nginx-65fc647b5d-gc5zh\’ 已被删除
[root@k8s01 服务]# kubectl get pods -o Wide
名称就绪状态重启年龄IP 节点指定节点就绪门
my-nginx-65fc647b5d-mp5t2 1/1 运行0 13 秒10.244.236.168 k8s02 无无
my-nginx-65fc647b5d-tf2vz 1/1 运行0 9 分5 秒10.244.236.166 k8s02 无无
从上面可以看到pod已经重新生成:my-nginx-65fc647b5d-mp5t2,IP为10.244.236.168,并在k8s上创建了一个pod。当Pod 被删除时,重新生成的Pod 的IP 地址会发生变化。因此,您需要在pod 前端添加固定的接入层。
接下来,创建服务。
#显示Pod 标签:
[root@k8s01 服务]# get kubectl pod –show-labels
姓名就绪状态恢复年龄标签
my-nginx-65fc647b5d-mp5t2 1/1 运行0 4m2s pod-template-hash=65fc647b5d,run=my-nginx
我的Nginx
-65fc647b5d-tf2vz 1/1 Running 0 12m pod-template-hash=65fc647b5d,run=my-nginx
创建 Service
service_test.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
type: ClusterIP
ports:
– port: 80 # service的端口,暴露给k8s集群内部服务访问
protocol: TCP
targetPort: 80 # pod容器中定义的端口
selector:
run: my-nginx # 选择拥有run=my-nginx标签的pod
上述 yaml 文件将创建一个 Service,具有标签 run=my-nginx 的 Pod,目标 TCP 端口 80,并且在一个抽象的 Service 端口(targetPort:容器接收流量的端口;port:抽象的 Service 端口,可以使任何其它 Pod 访问该 Service 的端口)上暴露
[root@k8s01 service]# kubectl apply -f service-test.yaml
service/my-nginx created
[root@k8s01 service]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d22h
my-nginx ClusterIP 10.106.190.4 <none> 80/TCP 4s
#在 k8s 控制节点访问 service 的 ip:端口就可以把请求代理到后端 pod
[root@k8s01 service]# curl 10.106.190.4:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
#通过上面可以看到请求 service IP:port 跟直接访问 pod ip:port 看到的结果一样,这就说明service 可以把请求代理到它所关联的后端 pod
**注意:**上面的 10.106.190.4:80 地址只能是在 k8s 集群内部可以访问,在外部无法访问,比方说我们想要通过浏览器访问,那么是访问不通的,如果想要在 k8s 集群之外访问,是需要把 service type 类型改成 nodePort 的
#查看 service 详细信息
[root@k8s01 service]# kubectl describe svc my-nginx
Name: my-nginx
Namespace: default
Labels: run=my-nginx
Annotations: <none>
Selector: run=my-nginx
Type: ClusterIP
IP Families: <none>
IP: 10.106.190.4
IPs: 10.106.190.4
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.236.166:80,10.244.236.168:80
Session Affinity: None
Events: <none>
[root@k8s01 service]# kubectl get ep my-nginx
NAME ENDPOINTS AGE
my-nginx 10.244.236.166:80,10.244.236.168:80 4m25s
service 可以对外提供统一固定的 ip 地址,并将请求重定向至集群中的 pod。其中“将请求重定向至集群中的 pod”就是通过 endpoint 与 selector 协同工作实现。selector 是用于选择 pod,由selector 选择出来的 pod 的 ip 地址和端口号,将会被记录在 endpoint 中。endpoint 便记录了所有 pod的 ip 地址和端口号。当一个请求访问到 service 的 ip 地址时,就会从 endpoint 中选择出一个 ip 地址和端口号,然后将请求重定向至 pod 中。具体把请求代理到哪个 pod,需要的就是 kube-proxy 的轮询实现的。service 不会直接到 pod,service 是直接到 endpoint 资源,就是地址加端口,再由 endpoint 再关联到 pod。
service 只要创建完成,我们就可以直接解析它的服务名,每一个服务创建完成后都会在集群 dns 中动态添加一个资源记录,添加完成后我们就可以解析了,资源记录格式是:
SVC_NAME.NS_NAME.DOMAIN.LTD.
服务名.命名空间.域名后缀
集群默认的域名后缀是 svc.cluster.local
就像我们上面创建的 my-nginx 这个服务,它的完整名称解析就是:my-nginx.default.svc.cluster.local
[root@k8s01 service]# kubectl get pods
NAME READY STATUS RESTARTS AGE
my-nginx-65fc647b5d-mp5t2 1/1 Running 0 15m
my-nginx-65fc647b5d-tf2vz 1/1 Running 0 24m
[root@k8s01 service]# kubectl exec -it my-nginx-65fc647b5d-tf2vz — /bin/bash
root@my-nginx-65fc647b5d-tf2vz:/# curl my-nginx.default.svc.cluster.local
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
NodePort
创建一个 pod 资源
pod-nodeport.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx-nodeport
spec:
selector:
matchLabels:
run: my-nginx-nodeport
replicas: 2
template:
metadata:
labels:
run: my-nginx-nodeport
spec:
containers:
– name: my-nginx-nodeport-container
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
– containerPort: 80
#更新资源清单文件
[root@k8s01 service]# kubectl apply -f pod-nodeport.yaml
deployment.apps/my-nginx-nodeport created
#查看 pod 是否创建成功
[root@k8s01 service]# kubectl get pods -l run=my-nginx-nodeport -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
my-nginx-nodeport-69d7b95994-h79t8 1/1 Running 0 32s 10.244.236.169 k8s02 <none> <none>
my-nginx-nodeport-69d7b95994-ljw46 1/1 Running 0 32s 10.244.235.143 k8s03 <none> <none>
创建 service,代理 pod
service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx-nodeport
labels:
run: my-nginx-nodeport
spec:
type: NodePort
ports:
– port: 80
protocol: TCP
targetPort: 80
nodePort: 30380
selector:
run: my-nginx-nodeport
[root@k8s01 service]# kubectl apply -f service-nodeport.yaml
service/my-nginx-nodeport created
[root@k8s01 service]# kubectl get svc -l run=my-nginx-nodeport
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-nginx-nodeport NodePort 10.106.116.28 <none> 80:30380/TCP 13s
#访问 service
[root@k8s01 service]# curl 10.106.116.28:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
注意:
10.106.116.28 是 k8s 集群内部的 service ip 地址,只能在 k8s 集群内部访问,在集群外无法访问。
在集群外访问 service
[root@ajie102 ~]# curl 10.106.116.28:30380
curl: (7) Failed connect to 10.106.116.28:30380; No route to host
[root@ajie102 ~]# curl 125.124.155.47:30380
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
在浏览器访问 service
服务请求走向:
Client→node ip:30380->service ip:80→pod ip:container port
Client ->125.124.155.47:30380->10.106.116.28:80->pod ip:80
ExternalName
应用场景:跨名称空间访问
需求:default 名称空间下的 client 服务想要访问 nginx-ns 名称空间下的 nginx-svc 服务
client.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: client
spec:
selector:
matchLabels:
app: busybox
template:
metadata:
labels:
app: busybox
spec:
containers:
– name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command:
– \’/bin/sh\’
– \’-c\’
– \’sleep 3600\’
clinet_svc.yaml
apiVersion: v1
kind: Service
metadata:
name: client-svc
spec:
type: ExternalName
externalName: nginx-svc.nginx-ns.svc.cluster.local
ports:
– port: 80
targetPort: 80
name: http
该文件中指定了到 nginx-svc 的软链,让使用者感觉就好像调用自己命名空间的服务一样。
[root@k8s01 service]# kubectl create ns nginx-ns
namespace/nginx-ns created
server_nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: nginx-ns
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
– name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
[root@k8s01 service]# kubectl apply -f server_nginx.yaml
deployment.apps/nginx created
#查看 pod 是否创建成功
[root@k8s01 service]# kubectl get pods -n nginx-ns
NAME READY STATUS RESTARTS AGE
nginx-bb957bbb5-65kxd 1/1 Running 0 25s
nginx_svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: nginx-ns
spec:
selector:
app: nginx
ports:
– port: 80
targetPort: 80
name: http
protocol: TCP
[root@k8s01 service]# kubectl apply -f nginx_svc.yaml
service/nginx-svc created
#登录到 client pod
[root@k8s01 service]# kubectl get pods
NAME READY STATUS RESTARTS AGE
client-57875f4ddb-srfwc 1/1 Running 0 8m43s
[root@k8s01 service]# kubectl exec -it client-57875f4ddb-srfwc — /bin/sh
/ # wget -q -O – nginx-svc.nginx-ns.svc.cluster.local
/ # wget -q -O – client-svc.default.svc.cluster.local
上面两个请求的结果一样
kube-proxy 组件详解
ginx-ns
spec:
selector:
app: nginx
ports:
– port: 80
targetPort: 80
name: http
protocol: TCP
“`shell
[root@k8s01 service]# kubectl apply -f nginx_svc.yaml
service/nginx-svc created
#登录到 client pod
[root@k8s01 service]# kubectl get pods
NAME READY STATUS RESTARTS AGE
client-57875f4ddb-srfwc 1/1 Running 0 8m43s
[root@k8s01 service]# kubectl exec -it client-57875f4ddb-srfwc — /bin/sh
/ # wget -q -O – nginx-svc.nginx-ns.svc.cluster.local
/ # wget -q -O – client-svc.default.svc.cluster.local
上面两个请求的结果一样
#以上关于service四层负载均衡的相关内容来源网络仅供参考,相关信息请以官方公告为准!
原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/92790.html