第十二章 kubernetes 核心技术-service资源


一、Service概述

service是k8s中的一个重要概念,主要是提供负载均衡和服务自动发现。它是k8s中最核心的资源之一,每一个Service就是我们平常所说的一个“微服务”。在非k8s世界中,管理员可以通过在配置文件中指定IP地址或主机名,容许客户端访问,但在k8s中这种方式是行不通的。因为Pod 是有生命周期的,它们可以被创建或销毁。虽然通过控制器能够动态地创建Pod,但当Pod被分配到某个节点时,K8s都会为其分配一个IP地址,而该IP地址不总是稳定可依赖的。因此,在 Kubernetes 集群中,如果一组 Pod(称为 backend)为其它 Pod (称为 frontend)提供服务,那么那些 frontend 该如何发现,并连接到这组backend的Pod呢?

如上图所示,Kubernetes的Service定义了一个服务的访问入口,前端的应用(Pod)通过这个入口地址访问其背后的一组由Pod副本组成的集群实例,Service与其后端的Pod副本集群之间是通过Label Selector来实现关联的,而Deployment则是保证Service的服务能力和服务质量始终处于预期的标准。

通过分析,识别并建模系统中的所有服务为微服务,最终我们的系统是由多个提供不同业务能力而彼此独立的微服务单元所组成,服务之间通过TCP/IP进行通信,从而形成了强大而又灵活的弹性网络,拥有强大的分布式能力、弹性扩展能力、容错能力。

二、Service存在的意义

#1.防止Pod失联,即服务发现。

#2.定义一组Pod访问策略,即负载均衡。

三、Service的工作方式

在Kubernetes迭代过程中,给Service设置里三种工作方式,分别是:Userspace方式、Iptables以及Ipvs,这三种方式到现在为止,官方推荐使用IPVS, 当集群不支持IPVS的时候,集群会降级到Iptables。

1.Userspace

Client Pod要访问Server Pod时,它先将请求发给本机内核空间中的service规则,由它再将请求,转给监听在指定套接字上的kube-proxy,kube-proxy处理完请求,并分发请求到指定Server Pod后,再将请求递交给内核空间中的service,由service将请求转给指定的Server Pod。由于其需要来回在用户空间和内核空间交互通信,因此效率很差。

2.Iptables模型

直接由内核中的iptables规则,接受Client Pod的请求,并处理完成后,直接转发给指定ServerPod。这种方式不再将请求转发给kube-proxy,性能提升很多。

3.Ipvs模型

在 ipvs 模式下,kube-proxy监视Kubernetes服务和端点,调用 netlink 接口相应地创建 IPVS 规则, 并定期将 IPVS 规则与 Kubernetes 服务和端点同步。 该控制循环可确保IPVS状态与所需状态匹配。 访问服务时,IPVS 将流量定向到后端Pod之一。IPVS代理模式基于类似于 iptables 模式的 netfilter 挂钩函数,但是使用哈希表作为基础数据结构,并且在内核空间中工作。 这意味着,与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。与其他代理模式相比,IPVS 模式还支持更高的网络流量吞吐量。

以上不论哪种,kube-proxy都通过watch的方式监控着kube-APIServer写入etcd中关于Pod的最新状态信息,它一旦检查到一个Pod资源被删除了或新建,它将立即将这些变化反应在 iptables 或 ipvs 规则中,以便iptables和ipvs在调度Clinet Pod请求到Server Pod时,不会出现Server Pod不存在的情况。自k8s1.1以后,service默认使用ipvs规则,若ipvs没有被激活,则降级使用iptables规则. 但在1.1以前,service使用的模式默认为userspace。

四、Service类型

Service是Kubernetes对外访问的窗口,针对不同的场景,kubernetes为我们设置了四种Service的类型。

1.ClusterIP

kubernetes 默认就是这种方式,是集群内部访问的方式,外部是无法访问的。其主要用于为集群内Pod访问时,提供的固定访问地址,默认是自动分配地址,可使用ClusterIP关键字指定固定IP。
#1.导出service文件
[root@kubernetes-master-001 ~]# kubectl  expose deployment web --port=80 --target-port=80 --dry-run=client -o yaml >service1.yaml

#2.部署SVC
[root@kubernetes-master-001 ~]# kubectl  apply  -f service1.yaml 
service/web created

#3.查看SVC
[root@kubernetes-master-001 ~]# kubectl  get  svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1               443/TCP   26h
web          ClusterIP   10.100.37.233           80/TCP    10s

#3.集群内部访问虚拟IP加端口
[root@kubernetes-node-001 ~]# curl 10.100.37.233:80



Welcome to nginx!



Welcome to nginx!

If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com.

Thank you for using nginx.

2.NodePort

NodePort是将主机IP和端口跟kubernetes集群所需要暴露的IP和端口进行关联,方便其对外提供服务。内部可以通过ClusterIP进行访问,外部用户可以通过NodeIP:NodePort的方式单独访问每个Node上的实例

#1.重新编辑service文件
[root@kubernetes-master-001 ~]# vim service1.yaml 
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: web
  name: web1
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: web
  type: NodePort
status:
  loadBalancer: {}
  
#2.部署SVC
[root@kubernetes-master-001 ~]# kubectl  apply  -f service1yaml 
service/web1 created

#3.部署SVC
[root@kubernetes-master-001 ~]# kubectl  get  svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1                443/TCP        26h
web          ClusterIP   10.100.37.233            80/TCP         6m5s
web1         NodePort    10.103.214.171           80:32023/TCP   8s

#4.集群外部访问
[root@kubernetes-master-001 ~]# curl 192.168.13.100:32023



Welcome to nginx!



Welcome to nginx!

If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com.

Thank you for using nginx.

3.LoadBalancer

LoadBalancer类型的service 是可以实现集群外部访问服务的另外一种解决方案。不过并不是所有的k8s集群都会支持,大多是在公有云托管集群中会支持该类型。负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过Service的status.loadBalancer字段被发布出去。
[root@kubernetes-master-001 ~]# cat > svc.yaml <        443/TCP        26h
web          ClusterIP   10.100.37.233            80/TCP         6m5s
web1         NodePort    10.103.214.171           80:32023/TCP   8s
loadbalancer LoadBalancer  10.0.129.18   81.71.12.240   80:30346/TCP   11s

4.Headless Service

kubernates中还有一种service类型:headless serivces功能,字面意思无头service其实就是该service对外无提供IP,即ClusterIP: none。一般用于对外提供域名服务的时候。
[root@kubernetes-master-001 ~]# vim headless-service.yaml 
kind: Service
apiVersion: v1
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  clusterIP: None
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 80
      name: web
---

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nginx-statefulset
  namespace: default
spec:
  serviceName: nginx
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

5.ExternalName

ExternalName Service是Service的一个特例,它没有选择器,也没有定义任何端口或Endpoints。它的作用是返回集群外Service的外部别名。它将外部地址经过集群内部的再一次封装(实际上就是集群DNS服务器将CNAME解析到了外部地址上),实现了集群内部访问即可。例如你们公司的镜像仓库,最开始是用ip访问,等到后面域名下来了再使用域名访问。你不可能去修改每处的引用。但是可以创建一个ExternalName,首先指向到ip,等后面再指向到域名。
kind: Service
apiVersion: v1
metadata:
  name: my-svc
spec:
  type: ExternalName
  externalName: www.baidu.com

相关