四层代理Service
四层负载均衡Service基本介绍
在Kubernetes中,四层代理(Layer·4·Proxy)是指基于网络层(传输层)的代理,用于将网络请 求从一个源地址路由到一个目标地址。在Kubernetes中,Service(服务)作为四层代理的一种实现方 式,用于实现服务的负载均衡和服务发现。 Service是Kubernetes中的一个资源对象,它定义了一组具有相同标签的Pod的逻辑集合,并为 这组Pod分配了一个虚拟IP(Cluster·IP)。Service充当了网络终结点,客户端可以通过访问Service 的虚拟IP来访问后端的Pod。
以下是Service的基本介绍: - Cluster·IP:每个Service都分配了一个Cluster·IP,它是一个虚拟的内部IP地址,用于在集群内部进行访问。这个虚拟IP是由Kubernetes自动分配的,并且与Service对象一一对应。
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 71d
$ kubectl describe svc kubernetes
Name: kubernetes
Namespace: default
Labels: component=apiserver
provider=kubernetes
Annotations: <none>
Selector: <none>
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.0.1
IPs: 10.96.0.1
Port: https 443/TCP
TargetPort: 6443/TCP
Endpoints: 192.168.59.63:6443
Session Affinity: None
Events: <none
# 也就是访问 10.96.0.1 时就可以访问 192.168.59.63:6443 这个服务
- 端口映射:Service可以映射一个或多个端口到后端Pod的端口。这意味着客户端可以通过访问Service的某个端口来访问后端Pod的应用程序。
- 负载均衡:Service使用四层代理实现负载均衡,将来自客户端的请求均匀地分发到后端的Pod。当多个Pod属于同一个Service时,Service会自动将请求路由到可用的Pod上,以实现负载均衡。
- DNS解析:每个Service都会自动注册到Kubernetes集群的内置DNS中,通过服务名称可以解 析出Service的虚拟IP。这样,客户端可以使用服务名称作为域名来访问Service,而无需知道具体的 虚拟IP地址。
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 71d
# 其完整的域名 kubernetes.default.svc.cluster.local
# 其靠 kube-dns 将这个域名解析为 10.96.0.1
$ kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 71d
Service与pod之间的关系

为什么不直接请求Pod的ip?而是要创建Service? Pod有生命周期,pod里面的镜像要更新,更新镜像就需要重新创建pod,那如果pod不是共享 物理机ip,pod重新创建ip就会变化,就没法访问了。
在Kubernetes中创建Service时,会使用标签选择器(Label·Selector)来筛选符合条件的 Pod,并为这些Pod创建与Service同名的Endpoint对象。Endpoint对象记录了Service所关联的 后端Pod的网络地址信息。
$ kubectl api-resources | grep Endpoints
endpoints ep v1 true Endpoints
$ kubectl get ep
NAME ENDPOINTS AGE
kubernetes 192.168.59.63:6443 71d
当Pod的地址发生变化时时(例如Pod重启、扩缩容导致Pod重新调度等),Endpoint对象会相应 地更新Pod 地址
当前端客户端发起请求到Service的虚拟IP时,Service通过查找与其关联的Endpoint对象,获 取到当前可用的后端Pod的地址列表。然后,由负载均衡组件(如kube-proxy)根据特定的负载均衡 算法(例如轮询、随机等)从地址列表中选择一个目标Pod,将请求转发到该Pod进行访问。
这样的架构使得前端客户端无需直接关注后端Pod的变化和调度情况,而是通过Service来访问后 端应用程序。Service提供了抽象和透明的方式来进行负载均衡和服务发现,确保了应用程序的高可用性 和可伸缩性。
# 如果配了防火墙,则此处可看转移规则
$ ipvsadm -Ln
Kubernetes集群中的ip地址
- Pod·IP地址:每个运行的Pod都会分配一个独立的IP地址。Pod·IP地址是集群内部的IP 地址,用于Pod之间的通信。
- Service·Cluster·IP地址:Service对象分配的虚拟IP地址称为Cluster·IP。Cluster·IP是 集群内部的IP地址,用于在集群内部进行服务发现和访问。客户端可以通过访问Service的 Cluster·IP地址来访问与该Service相关联的一组Pod。
- Node·IP地址:Node(节点)是Kubernetes集群中的工作节点,每个节点都有一个IP 地址。Node·IP地址用于与集群外部的网络进行通信,例如从外部访问集群中的服务。Node IP地址可以是物理节点的IP地址或云提供商分配的虚拟IP地址。
这三类IP地址在Kubernetes集群中扮演不同的角色: 1. Pod·IP地址用于Pod之间的通信,实现了容器间的网络互通。 2. Service·Cluster·IP地址用于提供服务的访问入口,客户端可以通过访问Service的Cluster IP地址来访问与之关联的一组Pod。 3. Node·IP地址用于与集群外部的网络进行通信,允许外部流量进入集群或从集群中流出。
创建Service资源
kubectl explain svc.spec
- allocateLoadBalancerNodePorts(boolean):表示是否动态分配负载均衡器的节点端口。
- clusterlP·(string):表示Service的Cluster·IP地址,用于集群内部访问Service,默认由系统自动分配。
- clusterlPs·([]string):表示Service的多个Cluster·IP地址,用于集群内部访问Service.
- externallPs·([]string):表示将Service公开到集群外部的外部IP地址列表。
- externalName·(string):表示Service的外部名称,用于将Service映射到外部DNS 名称。
- externalTrafficPolicy·(string):·表示Service外部流量的负载均衡策略,可选值为"Local"或"Cluster"。
- healthCheckNodePort·(integer):表示健康检查的节点端口。A
- ipFamilies·([]string):表示Service支持的IP地址族列表。
- ipFamilyPolicy·(string):表示Service的IP地址族策略,可选值为"SingleStack或"PreferDualStack"。
- IbadBalancerlP·(string):表示分配给负载均衡器的IP地址。←
- loadBalancerSourceRanges·([lstring):表示允许访问负载均衡器的源IP地址范围。
- ports·([object)::定义Service监听的端口映射配置,包括协议、端口号和目标端口等。
- publishNotReadyAddresses·(boolean):表示是否将未就绪的Pod的地址也发布给 Service。
- selector(map[string]string):标签选择器,用于选择与Service关联的后端Pod。
- sessionAffinity·(string):表示会话亲和性的策略,可选值为"None"、“ClientIP"或"ClientiP".
- topologyKeys·([]string):表示用于服务拓扑感知的键列表。
- type·(string):表示Service 的类型,可选值为"ClusterlP"、“NodePort"、"LoadBalancer"或"ExternalName".
Service的type类型
kubectl explain svc.spec.type
Kubernetes中的Service类型定义了不同的访问方式和应用场景。以下是几种常见的Service类 以及它们的应用场景:
- ClusterlP:
- 类型:ClusterlP是默认的Service类型。
-
应用场景:适用于集群内部的服务发现和访问。。ClusterlP将为Service分配一个虚拟 的Cluster·IP地址,只能在集群内部访问。通过该地址,其他Pod或Service可以访 问与之关联的一组Pod。
-
NodePort:
- 类型:NodePort类型将Service公开到集群节点上的某个固定端口。
-
应用场景:适用于需要从集群外部访问Service的场景。i通过指定NodePort类型 Kubernetes会为Service分配一个随机的高端口号,并将该端口映射到每个节点上。 从外部网络,可以通过
: 的方式访问Service。 -
LoadBalancer:
- 类型:LoadBalancer类型通过云服务提供商的负载均衡器将Service公开到外部网络。
-
应用场景:适用于需要高可用性和负载均衡的场景。通过LoadBalancer类型, Kubernetes将与云服务提供商集成,自动创建外部负载均衡器,,并将流量分发到 Service关联的Pod。外部客户端可以通过负载均衡器的公共IP访问Service。
-
ExternalName:
- 类型:ExternalName类型是一种将Service映射到外部DNS名称的方式。个
- 应用场景:适用于将Service与外部服务集成的场景。通过ExternalName类型, Service不会分配Cluster·IP或NodePort,而是直接映射到一个外部DNS名称。兰 集群内部的Pod或Service访问该Service时,DNS解析将会直接返回该外部DNS 名称对应的IP地址。
根据应用需求和场景,选择适当的Service类型可以实现不同的访问方式和网络架构。例如,如果需 要在集群内部实现服务发现和访问,可以使用ClusterlP;如果需要从集群外部访问Service,可以选择 NodePort;如果需要高可用性和负载均衡,可以使用LoadBalancer;如果需要将Service与外部服务 集成,可以使用ExternalName。根据具体的业务需求,可以灵活选择合适的Service类型。
通过定义Service的端口,可以实现将流量从Service端口转发到后端Pod的容器端口。每个端口 定义可以映射到一个或多个后端Pod,实现负载均衡和服务发现的功能。根据实际需求,可以在 spec.ports字段中定义多个端口,以满足不同端口的访问需求。
创建ClusterlP类型的Service
clusterip.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
run: nginx
replicas: 3
template:
metadata:
labels:
run: nginx
spec:
containers:
- name: my-nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
service_clusterip.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
run: nginx
spec:
type: ClusterIP
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
run: nginx
$ kubectl get pod -l run=nginx -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-7bd697c45f-7wqjn 1/1 Running 1 (105m ago) 14h 10.250.158.39 xuegod62 <none> <none>
nginx-7bd697c45f-bhh52 1/1 Running 1 (105m ago) 14h 10.250.158.41 xuegod62 <none> <none>
nginx-7bd697c45f-ln65j 1/1 Running 0 57m 10.250.158.33 xuegod62 <none> <none>
$ kubectl get svc -l run=nginx -owide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nginx ClusterIP 10.100.102.187 <none> 80/TCP 26m run=nginx
$ kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: run=nginx
Annotations: <none>
Selector: run=nginx
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.100.102.187
IPs: 10.100.102.187
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.250.158.33:80,10.250.158.39:80,10.250.158.41:80
Session Affinity: None
Events: <none>
路由规则保存在 ipvsadm -Ln 中。
创建NodePort类型的Service
vim nodepod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx-nodeport
spec:
selector:
matchLabels:
run: nginx-nodeport
replicas: 2
template:
metadata:
labels:
run: nginx-nodeport
spec:
containers:
- name: my-nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
vim service_nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx-nodeport
labels:
run: nginx-nodeport
spec:
type: NodePort
ports:
- port: 80
protocol: TCP
targetPort: 80
nodePort: 30180
selector:
run: nginx-nodeport
这样每个node都有30180 并且映射到 pod的 80端口
创建ExternalName类型的Service
应用场景:跨名称空间访问 需求:default名称空间下的pod想要访问nginx名称空间下的pod服务
nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
namespace: nginx
spec:
selector:
matchLabels:
run: nginx
replicas: 2
template:
metadata:
labels:
run: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
nginx-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: nginx
spec:
type: NodePort
ports:
- port: 80
protocol: TCP
targetPort: 80
nodePort: 30180
selector:
web: nginx
default.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: default
namespace: default
spec:
selector:
matchLabels:
app: busybox
replicas: 2
template:
metadata:
labels:
app: busybox
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-c", "sleep 3600"]
default_svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: nginx
spec:
type: ExternalName
externalName: nginx-svc.nginx.svc.cluster.local
ports:
- port: 80
targetPort: 80
selector:
web: nginx
Service完整的dns名称: Service name.svc namespace.svc.cluster.local
相当于软连接 nginx-svc -> nginx-svc.nginx.svc.cluster.local
实战:映射外部服务案例分享
mysql.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
type: ClusterIP
ports:
port: 3306
mysql_endpoint.yaml
apiVersion: v1
kind: Endpoints
metadata:
name: mysql
subsets:
addresses:
- ip: 192.168.40.62
ports:
port: 3306
这样访问 mysql 域名就可以访问 192.168.40.62:3306 了