Kubernetes基本概念的学习-Service

1、Service存在的意义

Service引入主要是解决Pod的动态变化,提供统一的访问入口:

   防止Pod失联,准备找到提供同一个服务的Pod(服务发现)

   定义一组Pod的访问策略(负载均衡)

Service可以简单的理解为逻辑上的一组Pod,一种可以访问Pod的策略,而且其他Pod可以通过这个Service访问到这个Service代理的Pod,相对于Pod而言,它会有一个固定的名称,一旦创建就固定不变。

Kubernetes Pod 是有生命周期的,它们可以被创建,也可以被销毁,然而一旦被销毁生命就永远结束。 通过 ReplicationController 能够动态地创建和销毁 Pod(例如,需要进行扩缩容,或者执行 滚动升级)。 每个 Pod 都会获取它自己的 IP 地址,即使这些 IP 地址不总是稳定可依赖的。 这会导致一个问题:在 Kubernetes 集群中,如果一组 Pod(称为 backend)为其它 Pod (称为 frontend)提供服务,那么那些 frontend 该如何发现,并连接到这组 Pod 中的哪些 backend 呢?答案是:Service。

Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。 这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector实现的。

service是用于一组pod的负载均衡和服务发现的,比如后端有6个跑着应用程序的pod,使用service就能实现对这6个pod的负载均衡分发客户端请求了,如果pod扩容了,那么service就会自动发现pod并把它加入自己的后端请求endpoint列表中。

 2、Pod与Service的关联

Service通过标签关联一组Pod;

Service为一组Pod:

selector 关联pod的标签

3、Service的创建

首先创建pod的yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web2
spec:
  replicas: 3 
  selector:
    matchLabels: 
      app: nginx2
  template:
    metadata:
      labels:
        app: nginx2
    spec:
      containers:
      - name: nginx
        image: nginx:1.17

创建pod

[root@master01 ~]# kubectl apply -f deployment.yaml 

可以查看pod的标签

[root@master01 ~]# kubectl get pod --show-labels
NAME                    READY   STATUS    RESTARTS   AGE   LABELS
web2-7b57499dd7-g5zlx   1/1     Running   0          12m   app=nginx2,pod-template-hash=7b57499dd7
web2-7b57499dd7-pqgbm   1/1     Running   0          12m   app=nginx2,pod-template-hash=7b57499dd7
web2-7b57499dd7-s2wjg   1/1     Running   0          12m   app=nginx2,pod-template-hash=7b57499

下面可以创建service的yaml,其中selector下app后面的nginx2就是要负载的pod的标签

apiVersion: v1
kind: Service
metadata:
  name: web2
spec:
  selector:
    app: nginx2
  ports:
    - protocol: TCP
      port: 80   #Service自己的端口
      targetPort: 80  #要暴露的端口
  type: NodePort

创建service

[root@master01 ~]# kubectl apply -f service.yaml 

查看创建的service

[root@master01 ~]# kubectl get service
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.1.0.1       <none>        443/TCP        10d
web2         NodePort    10.1.114.168   <none>        80:31917/TCP   10s

查看service关联的ip

[root@master01 ~]# kubectl get endpoints
NAME         ENDPOINTS                                              AGE
kubernetes   192.168.4.91:6443                                      10d
web2         10.244.205.227:80,10.244.205.228:80,10.244.75.102:80   2m47s

 4、Service类型——ClusterIP

默认类型是ClusterIP。默认,分配一个稳定的IP地址,即VIP,只能在集群内部访问

[root@master01 ~]# kubectl get service
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.1.0.1       <none>        443/TCP   11d
web          ClusterIP   10.1.164.147   <none>        80/TCP    6s

在node节点可以访问ClusterIP的地址: 

[root@work02 ~]# curl 10.1.164.147:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;

 5、Service类型-NodePort

在每个节点上启用一个端口来暴露服务,可以在集群外部访问。也会分配一个稳定内部进群IP地址。

访问地址:<任意NodeIP>:<NodePort>

端口默认范围:30000-32767 

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector:
    app: web
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: NodePort

 6、Service类型-LoadBalancer

LoadBalancer:与NodePort类似,在每个节点启用一个端口来暴露服务。除此之外,Kubernetes会请求底层云平台(华为云、腾讯云)上的负载均衡器,将每个Node([NodeIP]:[NodePort])作为后端添加进去。

 service类型总结:

ClusterIP:在集群内部使用,也是默认值

ExternalName:通过返回定义的CNAME别名

NodePort:在所有安装了kube-proxy的节点上打开一个端口,此端口可以代理至后端的Pod,然后集群外部可以使用节点的IP地址和NodePort的端口号访问到集群的Pod服务。NodePort端口的默认范围是30000-32768

LoadBalance:使用云平台的

7、Service的网络代理模式

iptables

 

ipvs

 

8、继续编写一个Service

apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: default
spec:
  selector:
    app: myapp
    release: canary
  clusterIP: 10.96.96.96
  type: ClusterIP
  ports:
  - port: 8080   #访问Service的端口
    targetPort: 80  #代理Pod的端口

9、无头Service

apiVersion: v1
kind: Service
metadata:
  name: headless-service
  namespace: default
spec:
  selector:
    app: myapp
    release: canary
  clusterIP: None
  type: ClusterIP
  ports:
  - port: 8080
    targetPort: 80

无头service就是在定义service时指定 service.spec.clusterIP:None,即没有clusterip,这就是headless service,简称无头service。
无头service也有标签选择器,有标签选择器就说明有对应的endpoint。

平时的应用一般有这样2种情况,多个应用实例之间没有区别,比如最常见的nginx反向代理到后端服务器的多个应用上,这些后端应用是没有说明区别的。但是这样情况呢,比如Redis集群,每个Redis节点都是不同的,它们之间相互通行并组成一个集群,这时我们使用普通的service向nginx那样反向代理到多个后端应用就显得不合适了。

使用无头service。如要搭建6个节点的redis集群(3主3从架构),我们定义service并不是说要让service将请求连接负载均衡分发到这6个pod,因为这6个pod的实例都是不同的,他们都跑着不同的应用。这时无头service就派上用场的,无头service没有clusterip,直接绑定具体的Pod的IP,无头service经常用于statefulset的有状态部署。
同时创建所谓的 headless service 资源, 这个 headless service 不分配 ClusterIP, 因为根本不会用到. 集群内的节点是通过Pod名称+序号.Service名称确定彼此进行通信的, 只要序号不变, 访问就不会出错.

headless service不具有普通Service资源的负载均衡能力, 因为没有ClusterIP, 所以kube-proxy组件不处理此类服务, 在访问此类服务的时候返回的是所有后端Pod的Endpoints列表.

访问一个普通的Service, kube-proxy会将请求重定向到后端的某个Pod, 多次请求虽然发送到的后端可能不同, 但是前端是无感知的, 因为Service本身有固定IP.

但是访问一个headless service, 其实是随机且直接访问到后端Pod, 比如多次ping redis-service, 你会发现解析出来的地址是不同的, 而这些地址都是Pod的地址.

10、Service的三种代理模式

  •  userspace 代理模式(K8S 1.1之前版本)
  •  iptables 代理模式(K8S 1.10之前版本)
  •  ipvs 代理模式(K8S 1.11 之后版本,激活ipvs需要修改配置);让kubelet所在的主机,启动时装入以下几个模块:ip_vs,ip_vs_rr,ip_vs_wrr,ip_vs_sh,nf_conntrack_ipv4

 

posted @ 2023-02-12 21:37  中仕  阅读(7)  评论(0编辑  收藏  举报