Kubernetes ---- Service介绍

Service

介绍:

实现方式:
   1. userspace: 用户空间
       用户的请求到达对应节点之上的iptables or ipvs规则(Service的规则),由Service先将他转为本地监听在某个套接字上的用户空间的kube-proxy进行处理,处理完成后再转给Service IP,最终代理至后端Pod.
   2. iptables: 直接调度 
       用户请求到达iptables后直接进行调度,无需进入用户空间处理;
   3. ipvs: 直接调度
       用ipvs进行调度,与iptables类似


kube-proxy
  始终监视着master上的api server服务中有关Service的变动信息;
  api server上有关Service对象的变动比如创建、删除,kube-proxy都要将其转化为当前节点上能够实现将用户请求调度到后端特定Pod资源之上的规则(iptables or ipvs)取决于Service实现方式


通过YAML文件创建Service:

1. 类型介绍

# 可手动指定Service的虚拟IP地址
svc.spec.clusterIP <string>

# 标签选择器,用于关联后端的Pod
svc.spec.selector <map[string]string>

# 关联后端Pod的端口
svc.spec.ports <[]Object>

# service的类型(ExternalName, ClusterIP, NodePort, LoadBalancer)
svc.spec.type <string>

ClusterIP: 默认为此类型,仅用于集群内通信
NodePort: 接入机器外部的流量,客户端直接通过节点的IP+NodePort暴露出来的端口就可访问
LoadBalancer: 比如在云环境上搭建了K8S集群(阿里云、AWS云),使用此种类型的Service会自动创建负载均衡器(阿里云的SLB)
ExternalName: 需要被kube-dns能够解析,用于将Service关联至外围服务以供Pod访问,外围服务将处理结果转交个Node,Node再返回给Service,Service再返回给Pod client,从而让Pod访问外围的服务(集群内不存在的服务)

资源记录格式(CoreDns):
   SVC_NAME.NS_NAME.DOMAIN.LTD.

   svc.cluster.local.

   redis.default.svc.cluster.local.

2.创建ClusterIP类型的Service.

$ vim svc-demo.yaml
  apiVersion: v1
   kind: Service
   metadata:
     name: redis
     namespace: default
   spec:
     clusterIP: 10.97.97.97
     type: ClusterIP
     selector:
       app: redis
       role: logstor
   ports:
   - name: redis
     port: 6479
     targetPort: 6379
     protocol: TCP

$ kubectl apply -f svc-demo.yaml
$ kubectl get svc NAME   TYPE   CLUSTER
-IP   EXTERNAL-IP   PORT(S)   AGE redis ClusterIP 10.97.97.97   <none>     6379/TCP   2m52s # 后端的Pod是之前创建的一个redis $ kubectl describe svc redis Name: redis Namespace: default Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration:  {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"redis","namespace":"default"},"spec":{"clusterIP":"10.97.97.97","... Selector: app=redis,role=logstor Type: ClusterIP IP: 10.97.97.97 Port: redis 6379/TCP TargetPort: 6379/TCP Endpoints: 10.244.1.63:6379 Session Affinity: None Events: <none> # 下列的Pod是之前搞Deployment的时候创建的,现在要把这些发布出去. $ kubectl get pods --show-labels NAME               READY STATUS RESTARTS AGE       LABELS deploy-demo-f5dfc4cf4-cb58r 1/1   Running   1    20h   app=myapp,pod-template-hash=f5dfc4cf4,release=canary deploy-demo-f5dfc4cf4-mm27c 1/1   Running   1    20h   app=myapp,pod-template-hash=f5dfc4cf4,release=canary deploy-demo-f5dfc4cf4-p7zvp 1/1   Running   1    20h   app=myapp,pod-template-hash=f5dfc4cf4,release=canary deploy-demo-f5dfc4cf4-rbqnh 1/1   Running   1   20h   app=myapp,pod-template-hash=f5dfc4cf4,release=canary deploy-demo-f5dfc4cf4-wz8tr 1/1   Running   1   20h   app=myapp,pod-template-hash=f5dfc4cf4,release=canary

3.创建NodePort类型的Service.

$ vim svc-np-demo.yaml
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: default
spec:
type: NodePort
selector:
app: myapp
release: canary
ports:
- name: myapp-port
nodePort: 30001
port: 80
targetPort: 80

$ kubectl apply -f svc-np-demo.yaml

$ kubectl get svc
NAME         TYPE     CLUSTER-IP   EXTERNAL-IP   PORT(S)     AGE
kubernetes   ClusterIP    10.96.0.1    <none>      443/TCP     14d
myapp     NodePort     10.97.65.55  <none>       80:30001/TCP  61s
redis     ClusterIP    10.97.97.97   <none>        6379/TCP    20m

$ kubectl describe svc myapp
Name: myapp
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"ports":[{"name":"myapp-por...
Selector: app=myapp,release=canary
Type: NodePort
IP: 10.97.65.55
Port: myapp-port 80/TCP
TargetPort: 80/TCP
NodePort: myapp-port 30001/TCP
Endpoints: 10.244.1.64:80,10.244.1.65:80,10.244.1.66:80 + 2 more...
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>

# 集群外部机器一直访问此Service,会发现返回的结果中包含所有Pod.
$ while true;do curl http://192.168.222.100:30001/hostname.html;sleep 1; done
deploy-demo-f5dfc4cf4-wz8tr
deploy-demo-f5dfc4cf4-p7zvp
deploy-demo-f5dfc4cf4-p7zvp
deploy-demo-f5dfc4cf4-cb58r
deploy-demo-f5dfc4cf4-wz8tr
deploy-demo-f5dfc4cf4-cb58r
deploy-demo-f5dfc4cf4-rbqnh
deploy-demo-f5dfc4cf4-rbqnh
deploy-demo-f5dfc4cf4-wz8tr
deploy-demo-f5dfc4cf4-rbqnh
deploy-demo-f5dfc4cf4-p7zvp
deploy-demo-f5dfc4cf4-rbqnh
deploy-demo-f5dfc4cf4-cb58r
.....

小功能如果启用下面这个功能的话那么来自同一客户端的请求始终发送给第一次接收请求的Pod

svc.spec.sessionAffinity <string>
  string:

    ClientIP

    None(默认值)

# 打补丁更新配置,也可以使用"kubectl edit -f xxx"或直接vim文件,随后使用"kubectl apply -f xxx"也可以.
$ kubectl patch svc myapp -p '{"spec":{"sessionAffinity":{"ClientIP"}}}' # 再次查看,会发现多了"**"那一行. $ kubectl describe svc myapp Name: myapp Namespace: default Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"ports":[{"name":"myapp-por... Selector: app=myapp,release=canary Type: NodePort IP: 10.97.65.55 Port: myapp-port 80/TCP TargetPort: 80/TCP NodePort: myapp-port 30001/TCP Endpoints: 10.244.1.64:80,10.244.1.65:80,10.244.1.66:80 + 2 more... ** Session Affinity: ClientIP External Traffic Policy: Cluster Events: <none> # 而且客户端访问这个Service的结果永远都是一样的

 

4. headless Service(无头Service)

说明:

  之前的Service的工作过程我想大家应该都知道,当客户端访问Service的时候,实际是会有kube-dns进行解析Service的名称,将名称解析为ClusterIP,随后根据算法调度后端Pod以便响应客户端请求,这个headless Service无需配置ClusterIP
要设为"None",那么当客户端请求过来的时候会将Service Name直接解析为后端Pod的地址以便提供响应.

4.1 使用YAML文件创建的方法

$ vim myapp-svc-headless.yaml
  apiVersion: v1
  kind: Service
  metadata:
    name: myapp-headless
    namespace: default
  spec:
    clusterIP: None
    type: ClusterIP
      selector:
        app: myapp
        release: canary
    ports:
    - port: 80
      targetPort: 80 
$ kubectl apply -f myapp-svc-headless.yaml

# 会发现"**"标记的那一行中的ClusterIP为None,不用慌,这是正常现象.
$ kubectl get svc 
NAME     TYPE     CLUSTER-IP     EXTERNAL-IP     PORT(S)     AGE
kubernetes ClusterIP   10.96.0.1     <none>        443/TCP     15d
myapp     NodePort   10.97.65.55    <none>        80:30001/TCP   160m
** myapp-headless ClusterIP None      <none>        80/TCP       15m
redis     ClusterIP   10.97.97.97    <none>        6379/TCP      179m

# 随后我们手动解析这个没有ClusterIP的Service,查看结果(answer上边的和下边的省略了),发现解析结果为后端的所有Pod的地址.
$ dig -t A myapp-headless.default.svc.cluster.local @10.96.0.10
.....
;; ANSWER SECTION:
myapp-headless.default.svc.cluster.local. 30 IN    A 10.244.1.64
myapp-headless.default.svc.cluster.local. 30 IN    A 10.244.1.66
myapp-headless.default.svc.cluster.local. 30 IN    A 10.244.1.65
myapp-headless.default.svc.cluster.local. 30 IN    A 10.244.2.67
myapp-headless.default.svc.cluster.local. 30 IN    A 10.244.2.68
......

 

posted @ 2020-06-12 15:32  k-free  阅读(229)  评论(0编辑  收藏  举报