前言

本篇是Kubernetes第八篇,大家一定要把环境搭建起来,看是解决不了问题的,必须实战。Pod篇暂时应该还缺少两篇,等Service和存储相关内容介绍以后,补充剩下的两篇,有状态的Pod会涉及这两块的内容。

Kubernetes系列文章:
  1. Kubernetes介绍
  2. Kubernetes环境搭建
  3. Kubernetes-kubectl介绍
  4. Kubernetes-Pod介绍(-)
  5. Kubernetes-Pod介绍(二)-生命周期
  6. Kubernetes-Pod介绍(三)-Pod调度
  7. Kubernetes-Pod介绍(四)-Deployment

为什么需要Service

在应用创建一个Nginx的Pod集合,由3个Pod组成,每个容器的端口端口号都是80;

  1. 编辑nginx-deployment.yaml;
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: backend
  replicas: 3
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        resources:
          limits:
            memory: "128Mi"
            cpu: "128m"
        ports:
        - containerPort: 80
  1. 创建Deployment资源;
kubectl apply -f nginx-deployment.yaml
  1. 查看Pod的IP;
kubectl get pods -o wide

image.png
  1. 通过IP访问Pod;
curl 10.100.1.92:80

image.png

这样就会存在问题,由于Pod的生命是有限的,如果Pod重启IP有可能会发生变化。如果我们的服务都是将Pod的IP地址写死,Pod的IP发生变化以后,后端服务也将会不可用。当然我们可以通过手动更新如nginx的upstream配置来改变后端的服务IP。也可以通过Consul,ZooKeeper、etcd等工具,把我们的服务注册到这些服务发现中心,然后让这些工具动态的去更新Nginx的配置就可以了,我们完全不用去手工的操作了。


img

Kubernetes提供了Service对象,它定义了一组Pod的逻辑集合和一个用于访问它们的策略,这个概念和微服务非常类似。一个Serivce下面包含的Pod集合一般是由Label Selector来决定的。这样就可以不用去管后端的Pod如何变化,只需要指定Service的地址就可以了,这厮因为我们在中间添加了一层服务发现的中间件,Pod销毁或者重启后,把这个Pod的地址注册到这个服务发现中心去。Service的这种抽象就可以帮我们达到这种解耦的目的。

Service原理初探

我们以前面创建的nginx为案例,通过创建一个Service来给3个Pod做负载:

  1. 创建Service方式有两种,一种是通过kubectl expose命令来创建,另外一个种通过yaml文件来创建,这里我们采用yaml方式来创建,创建一个nginx-service.yaml文件;
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  #定义后端pod标签为app=backend
  selector:
    app: backend
  ports:
  #service端口号
  - port: 80
    #pod的端口号
    targetPort: 80
  1. 创建Service对象;
kubectl apply -f nginx-service.yaml
  1. 查看Service的IP地址;
kubectl get svc
  1. 通过ServiceIP和端口号访问;
curl 10.96.165.211:80

image.png
  1. 查看Service的Endpoint的列表;
kubectl describe svc nginx-service

image.png

这里我们可以初步看出来Service的服务发现离不开Endpoint对象,Endpoint是Kubernetes中的一个资源对象,存储在Etcd中,用来记录一个Service对应的所有Pod的访问地址。Service配置Selector,Endpoint Controller才会自动创建对应的Endpoint对象;否则不会创建Endpoint对象。Endpoint Controller主要有以下作用:

  1. 负责生成和维护所有endpoint对象的控制器
  2. 负责监听Service和对应Pod的变化,监听到Service被删除,则删除和该Service同名的Endpoint对象;监听到新的Service被创建,则根据新建Service信息获取相关Pod列表,然后创建对应Endpoint对象;监听到Service被更新,则根据更新后的Service信息获取相关Pod列表,然后更新对应Endpoint对象;监听到Pod事件,则更新对应的Service的Endpoint对象,将Pod IP记录Eendpoint中;

Endpoint完成服务发现,真正从服务IP到后端Pod的负载均衡的实现则是由每个Node节点上的kube-proxy负责实现的,kube-proxy会监听Service和Endpoints的更新并调用其代理模块在主机上刷新路由转发规则,从而实现动态跟新服务列表,整体访问情况可以参考下图,这是第一代kube-proxy实现方式,现在的实现方式有所调整,但是我觉得这个是最容易让人明白的方式。


image.png

下图是第二代或者第三代实现方式,实现方式:


img

Service负载均衡

Service路由转发都是由 kube-proxy 组件来实现的,Service 仅以一种 ClusterIP 的形式存在,kube-proxy 将Service访问请求转发到后端的多个Pod的实例上,kube-proxy 的路由转发规则是通过其后端的代理模块实现的,kube-proxy 的代理模块目前有三种实现方案:

userspace

在userspace(用户空间代理)模式下,kube-proxy进程是一个真实的TCP/UDP代理,负责从Service到Pod的访问流量的转发,如下图:

userspace模式下kube-proxy通过API Server的Watch接口实时跟踪Service与Endpoint的变更信息,来实现动态更新iptables规则;对每个Service它都为其所在Node节点开放一个端口,作为其服务代理端口;发往该端口的请求会采用一定的策略转发给与该服务对应的后端Pod实体。kube-proxy同时会在本地节点设置 iptables 规则,这个规则用于捕获通过Cluter IP和Port访问Service请求,并将这些转发到对应的端口上,如果采用DNS形式,前面还有DNS解析层。


img

userspace该模式下最大的问题是,Service的请求会先从用户空间进入内核iptables,然后再回到用户空间,最后在由kube-proxy完成后端Endpoints的选择和代理工作,这样需要用户空间和内核态一直来回切换,这样带来的系统开销会很大。

iptables

Kubernetes从1.2版本开始,将iptables作为kube-proxy的默认模式。iptables模式下的kube-proxy不再起到Proxy的作用,其核心功能:通过API Server的Watch接口实时跟踪Service与Endpoint的变更信息,并更新对应的iptables规则,Client的请求流量则通过iptables的NAT机制“直接路由”到目标Pod。


img

与第1代的userspace模式相比,iptables模式完全工作在内核态,不用再经过用户态的kube-proxy中转,因而性能更强。iptables模式虽然实现起来简单,但存在无法避免的缺陷:在集群中的Service和Pod大量增加以后,iptables中的规则会急速膨胀,导致性能显著下降,在某些极端情况下甚至会出现规则丢失的情况,并且这种故障难以重现与排查。

IPVS

img

Kubernetes从1.8版本开始引入第3代的IPVS(IPVirtualServer)模式,IPVS在Kubernetes1.11中升级为GA稳定版。iptables与IPVS虽然都是基于Netfilter实现的,但因为定位不同,二者有着本质的差别:iptables是为防火墙而设计的;IPVS则专门用于高性能负载均衡,并使用更高效的数据结构(Hash表),允许几乎无限的规模扩张。由此解决掉了iptables的弊病。

与iptables相比,IPVS拥有以下明显优势:

  1. 为大型集群提供了更好的可扩展性和性能;

  2. 支持比iptables更复杂的复制均衡算法(最小负载、最少连接、加权等);

  3. 支持服务器健康检查和连接重试等功能;

  4. 可以动态修改ipset的集合,即使iptables的规则正在使用这个集合;

由于IPVS无法提供包过滤、airpin-masqueradetricks(地址伪装)、SNAT等功能,因此在某些场景(如NodePort的实现)下还要与iptables搭配使用。

在IPVS模式下,kube-proxy又做了重要的升级,即使用iptables的扩展ipset,而不是直接调用iptables来生成规则链。iptables规则链是一个线性的数据结构,ipset则引入了带索引的数据结构,因此当规则很多时,也可以很高效地查找和匹配。

会话保持机制

Service支持通过设置sessionAffinity实现基于客户端的IP的会话保持,首次将某个客户端来源的IP发起请求转发到后端某个Pod上,之后从相同的客户端IP发起的请求都被转发到相同的Pod上,配置参数为spec.sessionAffinity,也可以设置会话保持的最长时间,在此之后重新设置访问规则,通过配置spec.sessionAffinityConfig.clientIP.timeoutSeconds来实现,可以参考以下配置:

Service支持通过设置sessionAffinity实现基于客户端的IP的会话保持,首次将某个客户端来源的IP发起请求转发到后端某个Pod上,之后从相同的客户端IP发起的请求都被转发到相同的Pod上,配置参数为spec.sessionAffinity,也可以设置会话保持的最长时间,在此之后重新设置访问规则,通过配置spec.sessionAffinityConfig.clientIP.timeoutSeconds来实现,可以参考以下配置:

  apiVersion: v1
  kind: Service
  metadata:
    name: nginx-service
  spec:
    sessionAffinity: ClientIP
    sessionAffinityConfig:
      clientIP:
        timeoutSeconds: 1000
    #定义后端pod标签为app=backend
    selector:
      app: backend
    ports:
    #service端口号
    - port: 80
      #pod的端口号
      targetPort: 80

Service类型

Service支持的类型也就是Kubernetes 中将服务暴露的方式,默认有四种 ClusterIP、NodePort、LoadBalancer、ExternelName,下面会详细介绍每种类型Service的使用场景。

ClusterIP

ClusterIP类型的Service是Kubernetes集群默认的服务暴露方式,它只能用于集群内部通信,可以被各 Pod 访问,也可以手动指定ClusterIP,不过要确保该IP在Kubernetes集群设置ClusterIP的范围内部,并且没有被其他Service使用,整个访问流程如下:


img

集群内部整体结构可参考以下模型:


img
NodePort

对于我们来说,不全是集群内访问,也需要集群外业务访问。那么ClusterIP就满足不了了。NodePort是一种对外提供访问的方式,NodePort类型的Service可以让Kubemetes集群每个节点上保留一个相同的端口,外部访问连接首先访问节点IP:Port,然后将这些连接转发给服务对应的Pod。整体的访问流程:


image.png

集群内部整体结构可参考以下模型:


img
LoadBalancer

LoadBalancer类型的Service其实是NodePort类型Service的扩展,通过一个特定的LoadBalancer访问Service,这个LoadBalancer将请求转发到节点的NodePort,可以理解为端口的Nginx负载均衡器。

LoadBalancer本身不是属于Kubernetes的组件,这部分通常是由具体厂商(云服务提供商)提供,不同厂商的Kubernetes集群与LoadBalancer的对接实现各不相同,被提供的负载均衡器的信息将会通过Service的status.loadBalancer字段被发布出去。

整体结构可参考以下模型:


image.png
ExternalName

ExternalName类型的服务用于将集群外的服务定义为Kubernetes集群的Service,并且通过externalName字段指定外部服务的地址,可以是域名也可以是IP格式。集群内部的客户端可以通过这个Service访问外部服务,这种类型的服务没有后端Pod,因此也不需要设置Label Selector。

整体结构可参考以下模型:


img

结束

欢迎大家点点关注,点点赞!

Kubernetes-Service介绍(一)-基本概念的更多相关文章

  1. K8S Kubernetes 简单介绍 转自 http://time-track.cn/kubernetes-trial.html Kubernetes初体验

    这段时间学习了一下 git jenkins docker  最近也在看  Kubernetes  感觉写得很赞  也是对自己对于K8S 有了进一步得理解  感谢 倪 大神得Blog 也希望看到这篇Bl ...

  2. 【解构云原生】初识Kubernetes Service

    编者按:云原生是网易杭州研究院(网易杭研)奉行的核心技术方向之一,开源容器平台Kubernetes作为云原生产业技术标准.云原生生态基石,在设计上不可避免有其复杂性,Kubernetes系列文章基于网 ...

  3. Kubernetes组件介绍

    一.api-server   基本概念 该端口默认值为6443,可通过启动参数"--secure-port"的值来修改默认值. 默认IP地址为非本地(Non-Localhost)网 ...

  4. 三十一、kubernetes网络介绍

    Kubernetes 网络介绍 Service是Kubernetes的核心概念,通过创建Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上 ...

  5. 二十三、Pod的service介绍

    Pod 的 Service 介绍 一.Service 介绍 Kubernetes Service 定义了这样一种抽象: 一个 Pod 的逻辑分组,一种可以访问它们的策略,通常称为微服务. 这一组 Po ...

  6. C#多线程之旅(1)——介绍和基本概念

    原文地址:C#多线程之旅(1)——介绍和基本概念 C#多线程之旅目录: C#多线程之旅(1)——介绍和基本概念 C#多线程之旅(2)——创建和开始线程 C#多线程之旅(3)——线程池 C#多线程之旅( ...

  7. Android Service总结02 service介绍

    Android Service总结02 service介绍 版本 版本说明 发布时间 发布人 V1.0 介绍了Service的种类,常用API,生命周期等内容. 2013-03-16 Skywang ...

  8. Kubernetes service 使用定义

    Kubernetes service 使用定义 介绍说明 • 防止Pod失联• 定义一组Pod的访问策略• 支持ClusterIP,NodePort以及LoadBalancer三种类型• Servic ...

  9. kubernetes 实践一:基本概念和架构

    这里记录kubernetes学习和使用过程中的内容. CentOS7 k8s-1.13 flanneld-0.10 docker-18.06 etcd-3.3 kubernetes基本概念 kuber ...

  10. Docker系列(十三):Kubernetes Service的负载均衡和网络路由的秘密

    Kubernetes Service设计分析 什么是单体程序?所有的模块都在一个进程中 微服务,每一个服务是一个进程的模式 kubernetes中的service其实只是一个概念,是一组相同lable ...

随机推荐

  1. git 拉取代码指定分支

    问题背景: 新项目还在开发阶段,没有正式对外发布,所以开发同事合并代码到develop上(或者其他名称分支上),而不是到master分支上 通过git拉取代码的时候,默认拉取的是master分支,如下 ...

  2. 模拟文件上传(二):使用apache fileupload组件进行文件上传

    其中涉及到的jar包: jsp显示层: <%@ page language="java" import="java.util.*" pageEncodin ...

  3. go defer关键字使用规则

    defer 用于延迟函数的调用,每次defer都会把一个函数压入栈中,函数返回前再把延迟的函数取出并执行 数据结构 type _defer struct { sp uintptr //函数栈指针 pc ...

  4. 程序挂了之后别再跟我说让我帮你重启啦! 让supervisor帮你搞定...

    目录 有啥用? 安装 生成配置文件 启动supervisor 自定义配置文件 控制命令 求关注啦 有啥用? 很多我们项目排期进入联调.测试阶段,如果QA同学是直接跟你要一个后端环境的话,那简单点大概率 ...

  5. Excel vba call Python script on Mac

    How can I launch an external python process from Excel 365 VBA on OSX? It took me a while, but I fig ...

  6. Nginx反向代理之巨坑underscores_in_headers

    一.背景 因为项目需求,在做Windows的相关的事情:基本架构就是Nginx--> Nginx --> IIS,在Linux机器上通过Nginx做反向代理到Windows的IIS:然后遇 ...

  7. 在node节点部署kubectl管理k8s集群

    感谢!原文链接:https://blog.csdn.net/sinat_35930259/article/details/79994078 kubectl是k8s的客户端程序,也是k8s的命令行工具, ...

  8. noip模拟41

    A. 你相信引力吗 很明显的单调栈的题,考场上没有想到平移最大值,而是想着复制一倍序列破环成链,然后发现最大值的部分特别难维护,而且耗费时间过长,只好牺牲时间复杂度加了个 \(map\) 去重. 首先 ...

  9. 经典多级时间轮定时器(C语言版)

    经典多级时间轮定时器(C语言版) 文章目录 经典多级时间轮定时器(C语言版) 1. 序言 2. 多级时间轮实现框架 2.1 多级时间轮对象 2.2 时间轮对象 2.3 定时任务对象 2.4 双向链表 ...

  10. Java链表练习题小结

    链表 链表(Linked List)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer).一个链表节点至少包含一个 数据域和 ...