Kubernetes中比较全面的Service笔记


使用场景

  1. client想自己决定使用哪个Real Server,可以通过查询DNS来获取真实的Server地址,也就是PodIP;
  2. headless service关联的每个endpoint(也就是Pod)都会有对应的DNS域名,也就是上面说的域名,这样Pod之间就可以直接互相访问;

连接集群外部服务

ExternalName

kind: Service
apiVersion: v1
metadata:
  name: search
  namespace: default
spec:
  type: ExternalName
  externalName: www.baidu.com
$ kubectl get svc
NAME         TYPE           CLUSTER-IP   EXTERNAL-IP      PORT(S)   AGE
search       ExternalName   <none>       www.baidu.com    <none>    9s

解析一下域名:

$ nslookup search.default.svc.cluster.local 10.43.0.10
Server:		10.43.0.10
Address:	10.43.0.10:53

search.default.svc.cluster.local	canonical name = www.baidu.com
www.baidu.com	canonical name = www.a.shifen.com
Name:	www.a.shifen.com
Address: 39.156.66.14
Name:	www.a.shifen.com
Address: 39.156.66.18

search.default.svc.cluster.local	canonical name = www.baidu.com
www.baidu.com	canonical name = www.a.shifen.com
Name:	www.a.shifen.com
Address: 2409:8c00:6c21:104c:0:ff:b02c:156c
Name:	www.a.shifen.com
Address: 2409:8c00:6c21:104f:0:ff:b03f:3ae
-----------------------------------------------------
$ nslookup www.baidu.com
Server:		172.24.1.1
Address:	172.24.1.1:53

Non-authoritative answer:
www.baidu.com	canonical name = www.a.shifen.com
Name:	www.a.shifen.com
Address: 39.156.66.18
Name:	www.a.shifen.com
Address: 39.156.66.14

Non-authoritative answer:
www.baidu.com	canonical name = www.a.shifen.com
Name:	www.a.shifen.com
Address: 2409:8c00:6c21:104f:0:ff:b03f:3ae
Name:	www.a.shifen.com
Address: 2409:8c00:6c21:104c:0:ff:b02c:156c

可以很明显看到,ExternalName仅在DNS级别实施的,换言之就是针对有域名的外部服务,只是为外部服务在集群内的DNS服务器上,也就是coredns创建了个简单的CNAME DNS记录。search.default.svc.cluster.local canonical name = www.baidu.com

CNAME记录指向全限定域名而不是IP地址

Endpoints理解

Service和pod之间并不是直接关联的,他们中间存在一个介质endpoints;

Service endpoints Pod1 Pod2 Pod3
# kubectl describe svc -n kubernetes-dashboard kubernetes-dashboard
Name:                     kubernetes-dashboard
Namespace:                kubernetes-dashboard
Labels:                   k8s-app=kubernetes-dashboard
Selector:                 k8s-app=kubernetes-dashboard
Type:                     NodePort
IP:                       10.1.192.5
Port:                     <unset>  443/TCP
TargetPort:               8443/TCP
NodePort:                 <unset>  30000/TCP
Endpoints:                10.244.0.10:8443,10.244.0.13:8443
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

Selector:通过这个来确定哪些pod与这个endpoints连接

Endpoints:Service endpoint对应的pod的IP和端口列表

endpoints里面是一个endpoint列表:

# kubectl get endpoints -n kubernetes-dashboard kubernetes-dashboard
NAME                   ENDPOINTS                           AGE
kubernetes-dashboard   10.244.0.10:8443,10.244.0.13:8443   56d

Endpoints对应的就是PodIP和端口

关于endpoints需要注意的地方:

  1. endpoints在一般情况中是自动创建的,这里指的一般情况是svc中指定了selector,也可以不指定那就需要手动创建,下面会讲到。
  2. endpoints与svc关联是通过相同的名字,所以需要保证svc和endpoints的名字一致。
  3. svc中的端口,是你在集群中访问需要的端口,而真正的外部服务的IP和端口是在endpoints中指明的,这两个端口可以不同,相同只是便于分辨而已。

通过Endpoints连接集群外部服务

也可以称为外挂式部署。

首先理解所谓服务(应用层),无非就是IP+端口。

所谓外挂式,就是把集群外的服务,挂载到集群里面,看上去和部署在集群里面的服务一样。

关键在于创建了一个endpoint

如果创建了不包含pod selector(在集群里见到selector就是Pod的selector,比如节点选择器就要指明NodeSelector)的service,kubernetes就不会创建endpoint(毕竟缺少选择器,将不会知道service中包含哪些pod)。这样就需要手动创建Endpoints资源来指定endpoint列表。

  1. 首先创建一个没有selector的service

    apiVersion: v1
    kind: Service
    metadata:
      name: external-service
    spec:
      ports:
      - port: 80
    

    这里的port只是集群内部访问的端口,跟真正外部服务的端口没有关系,简单来说就是在集群内部访问这个端口转发到endpoints上指定的外部服务的真正端口

  2. 手动创建endpoints

    apiVersion: v1
    kind: Endpoints
    metadata:
      name: external-service
    subsets:
      - addresses:
        - ip: 11.11.11.11
        - ip: 22.22.22.22
        ports:
        - port: 32322
    

    地址可以指定多个实现负载均衡;这里的port就是真正服务的端口。

NodePort

NodePort将集群内部的服务映射为NodeIP+NodePort,外部客户端访问服务只需要

一个典型nodeport.yaml例子:

apiVersion: v1
kind: Service
metadata:
  name: kube-node-service
  labels:
    name: kube-node-service
spec:
  type: NodePort      
  ports:
  - port: 80          
    targetPort: 8081  
    protocol: TCP
    nodePort: 32143   
  selector:
    app: web 
  • 一个nodePort类型的service会使所有的节点的nodePort端口打开。
  • port是指service的port;targetPort:containerPort
  • 不指定targetPort的话,就是和port一样的。

LoadBalancer

一个简单的LoadBalancer yaml

apiVersion: v1
kind: Service
metadata:
  name: kubia-loadbalancer
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: kubia