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

1、认识service

1.1 为什么要使用service

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

1.2 service介绍

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

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

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

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,不需要客户端知道关于 Kubernetes、Service、或 Pod 的任何信息。

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

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,不需要客户端知道关于 Kubernetes、Service、或 Pod 的任何信息。 这应该比 userspace 代理更快、更可靠。然而,不像 userspace 代理,如果初始选择的 Pod 没有响应,iptables 代理能够自动地重试另一个 Pod,所以它需要依赖 readiness probes。

1.3.3 ipvs代理模式

  ipvs (IP Virtual Server) 实现了传输层负载均衡,也就是我们常说的4层LAN交换,作为 Linux 内核的一部分。ipvs运行在主机上,在真实服务器集群前充当负载均衡器。ipvs可以将基于TCP和UDP的服务请求转发到真实服务器上,并使真实服务器的服务在单个 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 也依赖 iptables,ipvs 会使用 iptables 进行包过滤、SNAT、masquared(伪装)。具体来说,ipvs 将使用ipset来存储需要DROP或masquared的流量的源或目标地址,以确保 iptables 规则的数量是恒定的,这样我们就不需要关心我们有多少服务了

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

① 修改配置文件

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

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

ip_vs,ip_vs_rr,ip_vs_wrr,ip_vs_sh,nf_conntrack_ipv4

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

  • apiVersion: v1  版本
  • kind: Service  类型
  • metadata  元数据
  • spec  期望状态
    • ports:服务公开的端口列表;把哪个端口和后端建立联系

      • port:此服务将公开的端口
      • targetPort:要在服务所针对的pod上访问的端口的编号或名称
      • nodePort:K8S 集群节点上的端口
    • selector:标签选择器;关联到哪些pod资源上
    • clusterIP:服务的IP地址,通常由主服务器随机分配
    • type:确定服务的公开方式。 默认为ClusterIP
      • ClusterIP(默认)
      • NodePort
      • LoadBalancer
      • ExternelName
    • sessionAffinity:service负载均衡,默认值是None,根据iptables规则随机调度;可使用sessionAffinity保持会话连线;
  • status  当前状态

1.5 service的4中类型

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

2、创建clusterIP类型的service

(1)编写yaml文件并创建名为redis的service

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

  1. [root@master manifests]# vim redis-svc.yaml
  2. apiVersion: apps/v1
  3. kind: Deployment
  4. metadata:
  5. name: redis
  6. namespace: default
  7. spec:
  8. replicas: 1
  9. selector:
  10. matchLabels:
  11. app: redis
  12. role: logstor
  13. template:
  14. metadata:
  15. labels:
  16. app: redis
  17. role: logstor
  18. spec:
  19. containers:
  20. - name: redis
  21. image: redis:4.0-alpine
  22. ports:
  23. - name: redis
  24. containerPort: 6379
  25. ---
  26. apiVersion: v1
  27. kind: Service
  28. metadata:
  29. name: redis
  30. namespace: default
  31. spec:
  32. selector:
  33. app: redis
  34. role: logstor
  35. clusterIP: 10.99.99.99
  36. type: ClusterIP
  37. ports:
  38. - port: 6380
  39. targetPort: 6379
  40. [root@master manifests]# kubectl apply -f redis-svc.yaml
  41. deployment.apps/redis created
  42. service/redis created

  

(2)查询验证

  1. [root@master ~]# kubectl get svc
  2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3. kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 142d
  4. redis ClusterIP 10.99.99.99 <none> 6380/TCP 12s
  5. ---查询service详细信息,pod绑定成功
  6. [root@master ~]# kubectl describe svc redis
  7. Name: redis
  8. Namespace: default
  9. Labels: <none>
  10. 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...
  11. Selector: app=redis,role=logstor
  12. Type: ClusterIP
  13. IP: 10.99.99.99
  14. Port: <unset> 6380/TCP
  15. TargetPort: 6379/TCP
  16. Endpoints: 10.244.2.94:6379
  17. Session Affinity: None
  18. Events: <none>

  

3、创建NodePort类型的service

3.1 创建service

(1)编写yaml文件并创建名为myapp的service

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

  1. [root@master manifests]# vim myapp-svc.yaml
  2. apiVersion: apps/v1
  3. kind: Deployment
  4. metadata:
  5. name: myapp-deploy
  6. namespace: default
  7. spec:
  8. replicas: 3
  9. selector:
  10. matchLabels:
  11. app: myapp
  12. release: canary
  13. template:
  14. metadata:
  15. labels:
  16. app: myapp
  17. release: canary
  18. spec:
  19. containers:
  20. - name: myapp
  21. image: ikubernetes/myapp:v1
  22. ports:
  23. - name: http
  24. containerPort: 80
  25. ---
  26. apiVersion: v1
  27. kind: Service
  28. metadata:
  29. name: myapp
  30. namespace: default
  31. spec:
  32. selector:
  33. app: myapp
  34. release: canary
  35. clusterIP: 10.97.97.97
  36. type: NodePort
  37. ports:
  38. - port: 80
  39. targetPort: 80
  40. nodePort: 31180
  41. [root@master manifests]# kubectl apply -f myapp-svc.yaml
  42. deployment.apps/myapp-deploy unchanged
  43. service/myapp created

  

(2)查询验证

  1. [root@master ~]# kubectl get svc
  2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3. kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 145d
  4. myapp NodePort 10.97.97.97 <none> 80:31180/TCP 39s
  5. redis ClusterIP 10.99.99.99 <none> 6380/TCP 2d
  6. [root@master ~]# kubectl describe svc myapp
  7. Name: myapp
  8. Namespace: default
  9. Labels: <none>
  10. 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...
  11. Selector: app=myapp,release=canary
  12. Type: NodePort
  13. IP: 10.97.97.97
  14. Port: <unset> 80/TCP
  15. TargetPort: 80/TCP
  16. NodePort: <unset> 31180/TCP
  17. Endpoints: 10.244.1.96:80,10.244.2.101:80,10.244.2.102:80
  18. Session Affinity: None
  19. External Traffic Policy: Cluster
  20. Events: <none>

  

(3)在集群外访问服务

3.2 使用sessionAffinity保持会话连接

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

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

  

(2)打补丁修改sessionAffinity为clientip;实现会话连接

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

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

  

(3)查询验证

  1. [root@master ~]# kubectl describe svc myapp
  2. Name: myapp
  3. Namespace: default
  4. Labels: <none>
  5. 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...
  6. Selector: app=myapp,release=canary
  7. Type: NodePort
  8. IP: 10.97.97.97
  9. Port: <unset> 80/TCP
  10. TargetPort: 80/TCP
  11. NodePort: <unset> 31180/TCP
  12. Endpoints: 10.244.1.96:80,10.244.2.101:80,10.244.2.102:80
  13. Session Affinity: ClientIP
  14. External Traffic Policy: Cluster
  15. Events: <none>

  

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

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

  

(5)重新打补丁修改为None,立即恢复为随机调度

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

  

4、创建无头service

(1)编写yaml文件并创建名为myapp-svc的service

绑定上面创建myapp的3个pod

  1. [root@master manifests]# vim myapp-svc-headless.yaml
  2. apiVersion: v1
  3. kind: Service
  4. metadata:
  5. name: myapp-svc
  6. namespace: default
  7. spec:
  8. selector:
  9. app: myapp
  10. release: canary
  11. clusterIP: None
  12. ports:
  13. - port: 80
  14. targetPort: 80
  15. [root@master manifests]# kubectl apply -f myapp-svc-headless.yaml
  16. service/myapp-svc created

  

(2)查询验证

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

  

(3)和有头正常myapp的service对比

无头service的解析:

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

有头正常myapp的service的解析:

  1. [root@master manifests]# dig -t A myapp.default.svc.cluster.local. @10.96.0.10
  2. ... ...
  3. ;; ANSWER SECTION:
  4. myapp.default.svc.cluster.local. 5 IN A 10.97.97.97
  5. ... ...

 

kubernetes系列08—service资源详解的更多相关文章

  1. kubernetes系列07—Pod控制器详解

    本文收录在容器技术学习系列文章总目录 1.Pod控制器 1.1 介绍 Pod控制器是用于实现管理pod的中间层,确保pod资源符合预期的状态,pod的资源出现故障时,会尝试 进行重启,当根据重启策略无 ...

  2. Kubernetes K8S之Service服务详解与示例

    K8S之Service概述与代理说明,并详解所有的service服务类型与示例 主机配置规划 服务器名称(hostname) 系统版本 配置 内网IP 外网IP(模拟) k8s-master Cent ...

  3. kubernetes系列09—Ingress控制器详解

    本文收录在容器技术学习系列文章总目录 1.认识Ingress 1.1 什么是Ingress? 通常情况下,service和pod仅可在集群内部网络中通过IP地址访问.所有到达边界路由器的流量或被丢弃或 ...

  4. kubernetes系列10—存储卷详解

    本文收录在容器技术学习系列文章总目录 1.认识存储卷 1.1 背景 默认情况下容器中的磁盘文件是非持久化的,容器中的磁盘的生命周期是短暂的,这就带来了一系列的问题:第一,当一个容器损坏之后,kubel ...

  5. ASP.NET MVC深入浅出系列(持续更新) ORM系列之Entity FrameWork详解(持续更新) 第十六节:语法总结(3)(C#6.0和C#7.0新语法) 第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字 各种通讯连接方式 设计模式篇 第十二节: 总结Quartz.Net几种部署模式(IIS、Exe、服务部署【借

    ASP.NET MVC深入浅出系列(持续更新)   一. ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态模 ...

  6. Kubernetes K8S之存储Volume详解

    K8S之存储Volume概述与说明,并详解常用Volume示例 主机配置规划 服务器名称(hostname) 系统版本 配置 内网IP 外网IP(模拟) k8s-master CentOS7.7 2C ...

  7. Kubernetes YAML 文件全字段详解

    Kubernetes YAML 文件全字段详解 Deployment yaml 其中主要参数都在podTemplate 中,DaemonSet StatefulSet 中的pod部分一样. apiVe ...

  8. Kubernetes K8S之存储ConfigMap详解

    K8S之存储ConfigMap概述与说明,并详解常用ConfigMap示例 主机配置规划 服务器名称(hostname) 系统版本 配置 内网IP 外网IP(模拟) k8s-master CentOS ...

  9. Android中Service(服务)详解

    http://blog.csdn.net/ryantang03/article/details/7770939 Android中Service(服务)详解 标签: serviceandroidappl ...

随机推荐

  1. BZOJ_1076_[SCOI2008]奖励关_状压DP

    BZOJ_1076_[SCOI2008]奖励关_状压DP 题意: 你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关.在这个奖励关里,系统将依次随机抛出k次宝物, 每次你都可以选择吃或者不吃(必须在抛 ...

  2. Python并发编程之深入理解yield from语法(八)

    大家好,并发编程 进入第八篇. 直到上一篇,我们终于迎来了Python并发编程中,最高级.最重要.当然也是最难的知识点--协程. 当你看到这一篇的时候,请确保你对生成器的知识,有一定的了解.当然不了解 ...

  3. 【毕业原版】-《伦敦艺术大学毕业证书》UAL一模一样原件

    ☞伦敦艺术大学毕业证书[微/Q:865121257◆WeChat:CC6669834]UC毕业证书/联系人Alice[查看点击百度快照查看][留信网学历认证&博士&硕士&海归& ...

  4. css3新增动画

    1.transiition过渡:样式改变就会执行transition (1)格式:transiition:1s width linear,2s 1s height; (2)参数: transition ...

  5. djiango的模板语言(template)

    老师的博客:http://www.cnblogs.com/liwenzhou/p/7931828.html 官方文档:https://docs.djangoproject.com/en/1.11/re ...

  6. RabbitMQ的介绍及使用进阶(Docker+.Net Core)

    目录: 一.什么是RabbitMQ 二.RabbitMQ运用场景 三.RabbitMQ优势及特点 四.Centos7中Docker安装RabbitMQ 五..Net Core 中使用RabbitMQ ...

  7. Java8新特性之三:Stream API

    Java8的两个重大改变,一个是Lambda表达式,另一个就是本节要讲的Stream API表达式.Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找.过滤.筛选等操作 ...

  8. Hadoop HA高可用集群搭建(Hadoop+Zookeeper+HBase)

    声明:作者原创,转载注明出处. 作者:帅气陈吃苹果 一.服务器环境 主机名 IP 用户名 密码 安装目录 master188 192.168.29.188 hadoop hadoop /home/ha ...

  9. Java 在PDF文档中绘制图形

    本篇文档将介绍通过Java编程在PDF文档中绘制图形的方法.包括绘制矩形.椭圆形.不规则多边形.线条.弧线.曲线.扇形等等.针对方法中提供的思路,也可以自行变换图形设计思路,如菱形.梯形或者组合图形等 ...

  10. Java关于读取Excel文件~xlsx xls csv txt 格式文件~持续汇总~

    所需的jar百度网盘链接:https://pan.baidu.com/s/146mrCImkZVvi1CJ5KoiEhQ提取码:c329 1 需要导入jar包,缺1不可 dom4j-1.6.1.jar ...