Service(SVC)

K8S SVC定义了一种抽象:一组Pod的逻辑分组,一种可以访问他们的策略——通常成为微服务。这一组Pod能够被Service访问到,通常是通过Label Selector

从0开始搞K8S:SVC Service(ClusterIP NodePort)_NodePort

SVC能提供负载均衡的能力,但是有限制:

只提供4层负载能力,没有7层功能(Ingress有7层功能)


SVC的类型

ClusterIP:默认类型,自动分配一个仅Cluster内部可以访问的虚拟IP

NodePort:在ClusterIP基础上为Service在每台及其上绑定一个端口,这样就可以通过NodeIP:NodePort来访问该服务

LoadBalancer:在NodePort的基础上,基础cloud provider创建一个外部父子均衡器,并将请求转发到NodeIP:NodePort

ExternalName:将集群外补的服务引入到集群内来,在即群内部直接诶使用。没有任何代理被创建。


ClusterIP

ClusterIP主要在每个node节点使用iptables/IPVS,将发向ClusterIP对应端口的数据,转发到kube-proxy中。然后kube-proxy自身内部实现由负载均衡的方法,并可以查询到这个service下对应Pod的地址和端口,进而把数据转发给对应的Pod的地址和端口

从0开始搞K8S:SVC Service(ClusterIP NodePort)_ClusterIP_02

为了实现图上的功能,主要需要以下组件的协同工作

  • apiserver:用户通过kubectl命令向apiserver发送创建SVC的命令,apiserver接收到请求后将数据存储到etcd中。
  • kube-proxy: kubernetes的每个节点都有kebu-proxy进程,这个进程负责感知SVC,pod的变化,并肩变化信息写入本地的iptables/IPVS中
  • iptables/IPVS:使用NAT技术将virtualIP的流量转至endpoint中

示例:

先创建一个deployment

pyapp-deploy.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pyapp-deploy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: pyapp
  template:
    metadata:
      labels:
        app: pyapp
    spec:
      imagePullSecrets:
      - name: harbor-admin
      containers:
      - name: pyapp-pod
        image: harbor.tangotz.com/pyapp/pyapp:v2
        ports:
        - containerPort: 5000

启动这个deployment

从0开始搞K8S:SVC Service(ClusterIP NodePort)_service_03

访问对应ip可以返回预期结果

在创建一个使用clusterIP模式的svc,并通过标签app: pyapp绑定deploy管理的pod

svc-clusterip.yml

apiVersion: v1
kind: Service
metadata:
  name: pyapp-svc-clusterip
spec:
  type: ClusterIP
  selector:
    app: pyapp
  ports:
  - port: 8080
    targetPort: 5000

注意对比两个yaml文件:在 Kubernetes 中,Service 和 Deployment 都使用 selector 字段来标识与它们关联的 Pod。但是,这两个资源在如何表示这个 selector 上有所不同。

  • 在 Deployment 中selector 字段通常包含一个嵌套的 matchLabels 字段,该字段定义了用于匹配 Pod 的标签。这是因为 Deployment 需要确保它所控制的 ReplicaSet(进而控制 Pod)具有特定的标签。
  • 在 Service 中selector 字段直接是一个标签选择器,它可以是基于标签的键值对列表。Service 使用这个选择器来确定哪些 Pod 的流量应该被路由到。它不需要像 Deployment 那样嵌套在 matchLabels 下。

这种设计上的区别反映了 Service 和 Deployment 在 Kubernetes 中的不同角色和职责。Service 负责将流量路由到匹配的 Pod,而 Deployment 则负责确保有正确数量和配置的 Pod 在运行。

查看一下SVC的信息

kubectl get svc pyapp-svc-clusterip

从0开始搞K8S:SVC Service(ClusterIP NodePort)_NodePort_04

再来看一下pyapp的pod 和ipvs的信息就可以看到,对应的ip10.107.218.161被转发到pyapp所在pod的IP上

从0开始搞K8S:SVC Service(ClusterIP NodePort)_NodePort_05

实验:

如果此时修改delpoyment的replicas数量,SVC会做和操作呢?

将replicas数量修改为4 ,再看一下ipvs。同一个记录下多了两个新pod的ip

从0开始搞K8S:SVC Service(ClusterIP NodePort)_service_06


NodePort

nodeport的原理在于在node上开了一个端口,将向改端口的流量导入到kube-proxy,然后由kuebe-proxy进一步给到对应pod

资源文件写法与CluseterIP基本一致,只不过将type改为NodePort

svc-nodeport.yml

apiVersion: v1
kind: Service
metadata:
  name: pyapp-svc-nodeport
spec:
  type: NodePort
  selector:
    app: pyapp
  ports:
  - port: 8080
    targetPort: 5000

注意:在这个NodePort示例中,匹配标签的Pod依旧是app: pyapp,与上文ClusterIP匹配标签相同。这样的操作是可以的,并不冲突。即Pod可以通过标签绑定多个SVC。

查看创建好的SVC

从0开始搞K8S:SVC Service(ClusterIP NodePort)_ClusterIP_07

可以看到NodePort同样拥有一个ClusterIP,但是在PORTS字段,ClusterIP与NodePort是不相同的,多出了一个映射端口。

从0开始搞K8S:SVC Service(ClusterIP NodePort)_NodePort_08

使用ipvs可以看到,访问这个31771端口会被转发到对应的pod上

从0开始搞K8S:SVC Service(ClusterIP NodePort)_ClusterIP_09

那么访问pod的方法有两个

  • 在k8s集群内使用ClusterIP:port 此例中为 10.103.45.255:8080

从0开始搞K8S:SVC Service(ClusterIP NodePort)_ClusterIP_10

  • 在网络可到达的范围内使用NodeIP:nodePort 此例中为

master  192.168.0.221:31771 

node01 192.168.0.231:31771

node03 192.168.0.233:31771

node04 192.168.0.234:31771

从0开始搞K8S:SVC Service(ClusterIP NodePort)_NodePort_11

nodePort

在Kubernetes中,使用NodePort模式时,生成的端口默认是随机的。这个随机端口号通常在30000-32767的范围内。然而这个端口是可以固定的

如果想要指定一个固定的NodePort端口,可以通过在Kubernetes的YAML配置文件中进行配置来实现。在Service的YAML配置文件中,可以在type: NodePort下指定nodePort字段,并设置为你想要的端口号。例如:

apiVersion: v1  
kind: Service  
metadata:  
  name: my-service  
spec:  
  type: NodePort  
  ports:  
  - port: 80  
    targetPort: 8080  
    nodePort: 30080  
  selector:  
    app: my-app

在上面的示例中,我们指定了NodePort的端口为30080,对应的容器端口为8080。这样,当外部流量通过节点的30080端口访问时,Kubernetes会将其转发到运行在容器中的8080端口上。

注意,指定的NodePort端口必须在Kubernetes集群中可用,并且不能与集群中其他服务的NodePort端口冲突。如果指定的端口已被其他服务使用,Kubernetes将无法启动服务。

修改后的效果

从0开始搞K8S:SVC Service(ClusterIP NodePort)_NodePort_12

ClusterIP没有变化但你是PORTS中的nodeport变化了,相应的使用你哦的IP:nodeport方式访问就需要使用30080端口

从0开始搞K8S:SVC Service(ClusterIP NodePort)_NodePort_13

总结来说,NodePort和ClusterIP的主要区别在于NodePort允许从集群外部访问Service,而ClusterIP仅允许在集群内部访问。因此,可以将NodePort视为ClusterIP的一个扩展或超集。