kubernetes系列08—service资源详解

本文收录在容器技术学习系列文章总目录html

一、认识service

1.1 为何要使用service

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

 

1.2 service介绍

  Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种能够访问它们的策略 —— 一般称为微服务。 这一组 Pod 可以被 Service 访问到,一般是经过 Label Selector(下面咱们会讲到咱们为何须要一个没有label selector的服务)实现的。redis

  举个例子,考虑一个图片处理 backend,它运行了3个副本。这些副本是可互换的 —— frontend 不须要关心它们调用了哪一个 backend 副本。 然而组成这一组 backend 程序的 Pod 实际上可能会发生变化,frontend 客户端不该该也不必知道,并且也不须要跟踪这一组 backend 的状态。 Service 定义的抽象可以解耦这种关联。算法

  对 Kubernetes 集群中的应用,Kubernetes 提供了简单的 Endpoints API,只要 Service 中的一组 Pod 发生变动,应用程序就会被更新。 对非 Kubernetes 集群中的应用,Kubernetes 提供了基于 VIP 的网桥的方式访问 Service,再由 Service 重定向到 backend Podvim

 

1.3 三种代理模式

  •  userspace 代理模式(K8S 1.1以前版本)
  •  iptables 代理模式(K8S 1.10以前版本)
  •  ipvs 代理模式(K8S 1.11 以后版本,激活ipvs须要修改配置)

1.3.1 userspace 代理模式

  这种模式,kube-proxy 会监视 Kubernetes master  Service 对象和 Endpoints 对象的添加和移除。 对每一个 Service,它会在本地 Node 上打开一个端口(随机选择)。 任何链接到代理端口的请求,都会被代理到 Service backend Pods 中的某个上面(如 Endpoints 所报告的同样)。 使用哪一个 backend Pod,是基于 Service  SessionAffinity 来肯定的。 最后,它安装 iptables 规则,捕获到达该 Service  clusterIP(是虚拟 IP)和 Port 的请求,并重定向到代理端口,代理端口再代理请求到 backend Pod后端

  网络返回的结果是,任何到达 Service IP:Port 的请求,都会被代理到一个合适的 backend,不须要客户端知道关于 KubernetesService、或 Pod 的任何信息。api

  默认的策略是,经过 round-robin 算法来选择 backend Pod。 实现基于客户端 IP 的会话亲和性,能够经过设置 service.spec.sessionAffinity 的值为 "ClientIP" (默认值为 "None")。bash

 

 1.3.2 iptables 代理模式

  这种模式,kube-proxy 会监视 Kubernetes master  Service 对象和 Endpoints 对象的添加和移除。 对每一个 Service,它会安装 iptables 规则,从而捕获到达该 Service  clusterIP(虚拟 IP)和端口的请求,进而将请求重定向到 Service 的一组 backend 中的某个上面。 对于每一个 Endpoints 对象,它也会安装 iptables 规则,这个规则会选择一个 backend Pod服务器

  默认的策略是,随机选择一个 backend实现基于客户端 IP 的会话亲和性,能够将 service.spec.sessionAffinity 的值设置为 "ClientIP" (默认值为 "None")。网络

  和 userspace 代理相似,网络返回的结果是,任何到达 Service IP:Port 的请求,都会被代理到一个合适的 backend,不须要客户端知道关于 KubernetesService、或 Pod 的任何信息。 这应该比 userspace 代理更快、更可靠。然而,不像 userspace 代理,若是初始选择的 Pod 没有响应,iptables 代理可以自动地重试另外一个 Pod,因此它须要依赖 readiness probes

 

1.3.3 ipvs代理模式

  ipvs (IP Virtual Server) 实现了传输层负载均衡,也就是咱们常说的4LAN交换,做为 Linux 内核的一部分。ipvs运行在主机上,在真实服务器集群前充当负载均衡器。ipvs能够将基于TCPUDP的服务请求转发到真实服务器上,并使真实服务器的服务在单个 IP 地址上显示为虚拟服务。

  在kubernetes v1.8 中引入了 ipvs 模式,在 v1.9 中处于 beta 阶段,在 v1.11 中已经正式可用了。 iptables 模式在 v1.1 中就添加支持了,从 v1.2 版本开始 iptables 就是 kube-proxy 默认的操做模式,ipvs iptables 都是基于netfilter的, ipvs 模式和 iptables 模式之间的差别:

  •  ipvs 为大型集群提供了更好的可扩展性和性能
  •  ipvs 支持比 iptables 更复杂的复制均衡算法(最小负载、最少链接、加权等等)
  •  ipvs 支持服务器健康检查和链接重试等功能

  同时ipvs 也依赖 iptablesipvs 会使用 iptables 进行包过滤、SNATmasquared(假装)。具体来讲,ipvs 将使用ipset来存储须要DROPmasquared的流量的源或目标地址,以确保 iptables 规则的数量是恒定的,这样咱们就不须要关心咱们有多少服务了

ipvs虽然在v1.1版本中已经支持,可是想要使用,还需激活ipvs

修改配置文件

[root@master ~]# vim /etc/sysconfig/kubelet
KUBE_PROXY=MODE=ipvs

编写脚本,让kubelet所在的主机,启动时装入如下几个模块:

ip_vsip_vs_rrip_vs_wrrip_vs_shnf_conntrack_ipv4

 

1.4 service定义资源清单几个字段

  •  apiVersionv1  版本
  •  kindService  类型
  •  metadata  元数据
  •  spec  指望状态
    •  ports:服务公开的端口列表;把哪一个端口和后端创建联系
      •  port:此服务将公开的端口
      •  targetPort:要在服务所针对的pod上访问的端口的编号或名称
      •  nodePortK8S 集群节点上的端口
    •  selector:标签选择器;关联到哪些pod资源上
    •  clusterIP:服务的IP地址,一般由主服务器随机分配
    •  type:肯定服务的公开方式。 默认为ClusterIP
      •  ClusterIP(默认)
      •  NodePort
      •  LoadBalancer
      •  ExternelName
    •  sessionAffinityservice负载均衡,默认值是None,根据iptables规则随机调度;可以使用sessionAffinity保持会话连线;
  •  status  当前状态

 

1.5 service4中类型

  •  ClusterIP(默认):仅用于集群内通讯,集群内部可达,能够被各pod访问,节点自己可访问;
  •  NodePort:构建在ClusterIP上,并在路由到clusterIP的每一个节点上分配一个端口;
    •  client ---> NodeIP:NodePort ---> ClusterIP:ServicePort ---> PodIP:containePort
  •  LoadBalancer:构建在NodePort上,并建立一个外部负载均衡器(若是在当前云中受支持),它将路由到clusterIP
  •  ExternelName:经过CNAMEserviceexternalName的值(好比:foo.bar.example.com)映射起来. 要求kube-dns的版本为1.7或以上.

 

二、建立clusterIP类型的service

1)编写yaml文件并建立名为redisservice

先建立一个deployment,启动一个redis pod;在使用service绑定这个pod

[root@master manifests]# vim redis-svc.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
      role: logstor
  template:
    metadata:
      labels:
        app: redis
        role: logstor
    spec:
      containers:
      - name: redis
        image: redis:4.0-alpine
        ports:
        - name: redis
          containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: default
spec:
  selector:
    app: redis
    role: logstor
  clusterIP: 10.99.99.99
  type: ClusterIP
  ports:
  - port: 6380
    targetPort: 6379
[root@master manifests]# kubectl apply -f redis-svc.yaml
deployment.apps/redis created
service/redis created

  

2)查询验证

[root@master ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP    142d
redis        ClusterIP   10.99.99.99   <none>        6380/TCP   12s
---查询service详细信息,pod绑定成功
[root@master ~]# 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.99.99.99","ports":[{"por...
Selector:          app=redis,role=logstor
Type:              ClusterIP
IP:                10.99.99.99
Port:              <unset>  6380/TCP
TargetPort:        6379/TCP
Endpoints:         10.244.2.94:6379
Session Affinity:  None
Events:            <none>

  

三、建立NodePort类型的service

3.1 建立service

1)编写yaml文件并建立名为myappservice

先建立一个deployment,启动3myapp pod;在使用service绑定这3pod

[root@master manifests]# vim myapp-svc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      release: canary
  template:
    metadata:
      labels:
        app: myapp
        release: canary
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        ports:
        - name: http
          containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  selector:
    app: myapp
    release: canary
  clusterIP: 10.97.97.97
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
    nodePort: 31180
[root@master manifests]# kubectl apply -f myapp-svc.yaml
deployment.apps/myapp-deploy unchanged
service/myapp created

  

2)查询验证

[root@master ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP        145d
myapp        NodePort    10.97.97.97   <none>        80:31180/TCP   39s
redis        ClusterIP   10.99.99.99   <none>        6380/TCP       2d
[root@master ~]# 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":{"clusterIP":"10.97.97.97","ports":[{"nod...
Selector:                 app=myapp,release=canary
Type:                     NodePort
IP:                       10.97.97.97
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  31180/TCP
Endpoints:                10.244.1.96:80,10.244.2.101:80,10.244.2.102:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

  

3)在集群外访问服务

 

3.2 使用sessionAffinity保持会话链接

1sessionAffinity默认是None,没有修改前,访问业务是随机调度

[root@master ~]# while true; do curl 192.168.10.103:31180/hostname.html; sleep 1; done
myapp-deploy-69b47bc96d-mmb5v
myapp-deploy-69b47bc96d-wtbx7
myapp-deploy-69b47bc96d-wtbx7
myapp-deploy-69b47bc96d-cj48v
... ...

  

2)打补丁修改sessionAffinityclientip;实现会话链接

也可使用exec修改;或者直接修改yaml文件也能够;

[root@master ~]# kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"ClientIP"}}'
service/myapp patched

  

3)查询验证

[root@master ~]# 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":{"clusterIP":"10.97.97.97","ports":[{"nod...
Selector:                 app=myapp,release=canary
Type:                     NodePort
IP:                       10.97.97.97
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  31180/TCP
Endpoints:                10.244.1.96:80,10.244.2.101:80,10.244.2.102:80
Session Affinity:         ClientIP
External Traffic Policy:  Cluster
Events:                   <none>

  

4)访问业务查询验证;发现同一客户端的请求始终发往同一pod

[root@master ~]# while true; do curl 192.168.10.103:31180/hostname.html; sleep 1; done
myapp-deploy-69b47bc96d-cj48v
myapp-deploy-69b47bc96d-cj48v
myapp-deploy-69b47bc96d-cj48v
myapp-deploy-69b47bc96d-cj48v
... ...

  

5)从新打补丁修改成None,当即恢复为随机调度

[root@master ~]# kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"None"}}'
service/myapp patched
[root@master ~]# while true; do curl 192.168.10.103:31180/hostname.html; sleep 1; done
myapp-deploy-69b47bc96d-cj48v
myapp-deploy-69b47bc96d-mmb5v
myapp-deploy-69b47bc96d-cj48v
myapp-deploy-69b47bc96d-mmb5v

  

四、建立无头service

1)编写yaml文件并建立名为myapp-svcservice

绑定上面建立myapp3pod

[root@master manifests]# vim myapp-svc-headless.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
  namespace: default
spec:
  selector:
    app: myapp
    release: canary
  clusterIP: None
  ports:
  - port: 80
    targetPort: 80
[root@master manifests]# kubectl apply -f myapp-svc-headless.yaml
service/myapp-svc created

  

2)查询验证

[root@master ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP        145d
myapp        NodePort    10.97.97.97   <none>        80:31180/TCP   2h
myapp-svc    ClusterIP   None          <none>        80/TCP         6s
redis        ClusterIP   10.99.99.99   <none>        6380/TCP       2d

  

3)和有头正常myappservice对比

无头service的解析:

[root@master manifests]# dig -t A myapp-svc.default.svc.cluster.local. @10.96.0.10
... ...
;; ANSWER SECTION:
myapp-svc.default.svc.cluster.local. 5 IN A	10.244.1.96
myapp-svc.default.svc.cluster.local. 5 IN A	10.244.2.101
myapp-svc.default.svc.cluster.local. 5 IN A	10.244.2.102
... ...

有头正常myappservice的解析:

[root@master manifests]# dig -t A myapp.default.svc.cluster.local. @10.96.0.10
... ...
;; ANSWER SECTION:
myapp.default.svc.cluster.local. 5 IN	A	10.97.97.97
... ...
相关文章
相关标签/搜索