1.什么是Service?

在kubernets中,Pod是应用程序的载体,Pod你可以想象成就是容器,为动态的一组Pod提供一个固定的访问入口,它是以一种叫ClusterIP地址来进行标识,而ClusterIP就位于我们集群网络(Cluster Network)当中,我们可以通过Pod的IP地址来进行访问,但是会遇到问题:

  1. 动态Pod的IP地址不是固定的,一旦Pod异常退出、节点故障,则会发生Pod重建,一旦发生重建客户端则会访问失败;
  2. Pod如果扩容多个,会造成客户端无法有效使用新增的Pod,如果Pod进行缩容则会造成客户端访问错误;
  3. 官方文档: https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/

1.2 Service能干什么?

  1. 为了解决这个问题,K8s提供了Service资源,Service为动态的一组Pod提供一个固定的访问入口;这个固定的访问入口可以理解为是一组应用的前端的负载均衡器;就像LVS或Nginx为一组ReadyServer做负载均衡器是一样的,你是看不见的,可以理解为Service就是负载均衡器,但是这种负载均衡器比传统的负载均衡器要强大;Service资源通过"标签选择器Label Selector"把筛选出来的符合条件的一组Pod对象定义成一个逻辑集合,而后Service对外提供自己的IP和端口。

  2. 当客户端请求Service的IP和端口时,Service将请求调度给标签匹配的所有的Pod,Service向客户端隐藏了真实处理请求的Pod资源,使得客户端的请求看上去是由Service直接处理并进行响应。

  3. Service对象的IP地址(Cluster IP或Service IP)是虚拟IP地址,由kubernetes系统在Service对象创建时在专有网络(Service Network)地址中自动分配或由用户手动指定,其次Service是基于端口过滤,并根据事先定义好的规则将请求转发至其后端Pod对应的端口上,因此这种代理机制也称为"端口代理"或"四层代理"工作在TCP/IP协议栈的传输层;

1.3 Service的作用?

  1. 暴露流量,让用户可以通过ServiceIP+ServicePort访问后端的Pod应用;
  2. 负载均衡: 提供基于4层的TCP/IP负载均衡,并不提供HTTP/HTTPS等负载均衡;
  3. 服务发现: 当发现新增Pod则自动加入至Service的后端,如发现Pod异常则会踢出Service后端;

1.4 Service的工作逻辑;

  1. Service持续监视API-Server,监视Service标签选择器所匹配的后端的Pod,并实时跟踪这些Pod对象的变动情况,例如IP地址的变化、Pod对象增加或减少;
  2. Service并不直接与Pod建立关联关系,他们之间还有一个中间层Endpoints,Endpoints对象是一个由IP地址和端口组成的列表,这些IP地址和端口来自于Service标签选择器所匹配到的Pod,默认情况下,创建Service资源时,关联的Endpoints对象会被自动创建;

1.5 Endpoint资源

  1. 创建一个Service的时候会自动创建一个与Service同名的Endpoints,事实上,Service不但能够把标签选择器选中的Pod识别为自己的后端端点,还能够对后端端口做就绪状态检测。如果后端Pod是就绪的就把它加入到后端可用端点列表中,反之踢出;
  2. 这个功能不是Service来做的,而是Service借助一个中间组件,Endpoints也是kubernetes一个标准的资源类型;
  3. Service会自动去管理Endpoints,Endpoints真正能发挥作用的是Endpoint控制器。一旦创建一个Service,需要为Service指定的基本属性是"Label Selector"随后Service控制器会根据这个标签选择器创建一个同名的Endpoints资源,是由Sercice控制器请求创建一个同名的Endpoints资源,随后Endpoints控制器就会介入,因为有一个自己的资源需要被创建。Endpoints控制器就会使用Endpoints的标签选择器与Service一模一样,继承Service的,Endpoints控制器会根据"标签选择器"去查找多少个符合筛选的Pod。最重要的是还会检查Pod的就绪状态,真正去绑定的不是由Service做的,而是由Endpoints做的。Service只负责调度,如果关联到了。Service只是把Endpoint帮查找到的所有处于就绪状态的后端Pod告诉Service,于是成了Service的后端端点;

1.6 Servcie的实现;

  1. 在kubernetes中,Service只是一个抽象的概念,真正起作用实现负载均衡规则的其实是kube-proxy这个进程,它在每一个节点都需要运行一个kube-proxy,用来完成负载均衡规则的创建;

1.7 Kube-Proxy代理模式

1.7.1UserSpace

  1. UserSpace模式下,kube-proxy为ServiceIP创建一个监听端口,当用户向ServiceIP发起请求;首先按请求会被Iptables规则拦截,然后重定向到kube-proxy对应的端口上,然后kube-proxy根据调度算法挑选一个Pod,将请求调度到该Pod上;
  2. 该模式流量经过内核空间后,会送往用户空间Kube-Proxy进程,而后又被送回内核空间,发往调度分配的目标后端Pod;效率太差。报文先到内核空间再回到用户空间,因为报文在用户空间来回切换两次以上,

    1.7.2iptables
  3. iptables模式下,kube-proxy为Service后端的所有Pod创建对应的iptables规则,当用户向ServiceIP发起请求;首先iptables会拦截用户请求,然后直接将请求调度给后端的Pod;问题是一个Service会创建大量的Iptables规则,且不支持更高级的调度算法;

    1.7.3IPVS

    ipvs模式和iptables类似,kube-proxy为Service后端所有的Pod创建对应的IPVS规则, 一个Service只生成一条规则,所以规模较大的场景应使用IPVS。其次IPVS支持更多的高级算法;

2.Service的类型

2.1 Service资源规范

apiVersion: v1       # API的版本
kind: Service # 资源类型定义为Service
metadata:
name: ... # Serivce的名称
namespace: ... # 默认的default
labels:
key1: value1 # 标签 key:value格式;
key2: value2
spec:
type <string> # Service类型,默认为ClusterIP;
selector <map[string]string> # 标签选择器
ports: # ClusterIP:ServicePort
targetPort: <string> #后端目标进程的端口号或名称。
nodePort: <integer> # 节点端口号,仅适用于NodePort和loadbalancer类型。 "建议动态选择30000-32767"
clusterIP <string> # Service的集群IP,建议由系统自动分配
externalTrafficPolicy <string> # 外部流量策略处理方式,local表示由当前节点处理,cluster表示向集群范围调度
loadBalancerIP <string> # 外部负载均衡器使用的IP地址,仅适用于loadbalancer,前提是你的公有云得支持你自己指定;
externalName <string> # 外部服务名称,该名称作为Service的DNS CNAME值

2.2 ClusterIP

ClusterIP: 通过集群内部IP暴露服务,选择ServiceIP只能够在集群内部访问,这也是默认的Service类型;该地址仅在集群内部可见、可达。无法被集群外部客户端访问;而且是默认类型,创建的任何Service默认就是ClusterIP类型,而且只能接受集群内部客户端的访问。

2.2.1 ClusterIP示例;

root@kubernetes-master01:~# cat services-clusterip-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-clusterip
namespace: default
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
clusterIP:
selector: # 标签选择器
app: nginx
ports:
- name: http # 端口名称
protocol: TCP # 协议类型,目前支持TCP、UDP、SCTP默认为TCP
port: 80 # Service的端口号
targetPort: 80 # 后端目标进程的端口号
root@kubernetes-master01:~# kubectl apply -f services-clusterip-nginx.yaml
pod/nginx-clusterip created
service/nginx-svc created

2.2.1.1查看Service;

root@kubernetes-master01:~# kubectl get svc
nginx-svc ClusterIP 10.106.70.164 <none> 80/TCP 3m

2.2.1.2 可以看到后端就一个Pod;

root@kubernetes-master01:~# kubectl get pods --show-labels -l app=nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
nginx-clusterip 1/1 Running 0 8m58s 10.244.4.49 kubernetes-node01 <none> <none> app=nginx

2.2.1.3查看Endpoint资源,Endpoints可以简写为ep;

root@kubernetes-master01:~# kubectl get endpoints
nginx-svc 10.244.4.49:80 10m

2.2.1.4测试访问;只能在集群内部访问,外部无法访问;

root@kubernetes-master01:~# curl -I  10.106.70.164
HTTP/1.1 200 OK
Server: nginx/1.21.5
Content-Type: text/html
Content-Length: 615
Connection: keep-alive
ETag: "61cb5be0-267"
Accept-Ranges: bytes

2.3 NodePort

NodePort:首先是一种ClusterIP类型,也就是说,NodePort是ClusterIP的扩展类型。NodePort类型的Service不仅仅能够被集群内部的客户端可见,还能对外部客户端可见。怎么可见呢?它会与ClusterIP的功能之外在每个节点上使用一个相同的端口号"注意是在每个节点上使用一个相同的端口号"将外部流量引入到该Service上来。

2.3.1 NodePort示例;

root@kubernetes-master01:~# cat services-nodeport-nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-nodeport-svc
namespace: default
spec:
type: NodePort
clusterIP:
selector:
app: nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80 # 后端Pod监听什么端口就写什么端口。要不然到达Service的请求转发给Pod,Pod没有那个端口也没用。一定真正转发到后端程序监听的端口。如果没有特殊情况的话,ServicePort和TargetPort保持一致。NodePort可以不用指定。
nodePort: # 正常情况下应由系统自己分配,默认是3000~32767
root@kubernetes-master01:~# kubectl apply -f services-nodeport-nginx.yaml
service/nginx-nodeport-svc created

2.3.1.1查看Service,意味着访问宿主机IP+nodeport端口就可以访问服务;

root@kubernetes-master01:~# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 36d
nginx-nodeport-svc NodePort 10.111.124.121 <none> 80:32049/TCP 5s
nginx-svc ClusterIP 10.106.70.164 <none> 80/TCP 34m

2.3.1.2 测试,这是windows的命令行,也是没有问题;

C:\Users\海棠>curl -I  10.0.0.1xx:30824
HTTP/1.1 200 OK
Server: nginx/1.21.5
Content-Type: text/html
Content-Length: 615
Connection: keep-alive
ETag: "61cb5be0-267"
Accept-Ranges: bytes

2.4 LoadBalancer

loadBalancer: 这类Service依赖云厂商,需要通过云厂商调用API接口创建软件负载均衡将服务暴露到集群外部,当创建LoadBalancer类型的Service对象时,它会在集群上自动创建一个NodePort类型的Service,集群外部的请求流量会先路由至该负载均衡,并由该负载均衡调度至各个节点的NodePort;

2.4.1 LoadBalancer示例;

root@kubernetes-master01:~# cat  services-loadbalancer-nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-loadbalancer-svc
namespace: default
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
loadBalancerIP: 1.2.3.4

2.4.1.2测试访问;

# 我们还是只能是通过NodePort来访问,因为没有LoadBalancer的IP;
# LoadBalancer其实就是一个增强的NodePort。而LoadBalancer没有限制流量调度策略的。外部流量策略对loadbalancer依然使用,因为LoadBalancer首先是一个NodePort的Service。
C:\Users\冷雨夜>curl -I 10.0.0.1XX:31943
HTTP/1.1 200 OK
Server: nginx/1.21.5
Content-Type: text/html
Content-Length: 615
Connection: kep-alive
ETag: "61cb5be0-267"
Accept-Ranges: bytes

2.5 ExternalName

此类型不是用来定义如何访问集群内服务的,而是把集群外部的某些服务以DNS CANME方式映射到集群内,从而让集群内的Pod资源能够访问外部服务的一种实现方式。

一文搞懂什么是kubernetes Service的更多相关文章

  1. 一文搞懂RAM、ROM、SDRAM、DRAM、DDR、flash等存储介质

    一文搞懂RAM.ROM.SDRAM.DRAM.DDR.flash等存储介质 存储介质基本分类:ROM和RAM RAM:随机访问存储器(Random Access Memory),易失性.是与CPU直接 ...

  2. 基础篇|一文搞懂RNN(循环神经网络)

    基础篇|一文搞懂RNN(循环神经网络) https://mp.weixin.qq.com/s/va1gmavl2ZESgnM7biORQg 神经网络基础 神经网络可以当做是能够拟合任意函数的黑盒子,只 ...

  3. 一文搞懂 Prometheus 的直方图

    原文链接:一文搞懂 Prometheus 的直方图 Prometheus 中提供了四种指标类型(参考:Prometheus 的指标类型),其中直方图(Histogram)和摘要(Summary)是最复 ...

  4. Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!

    本文原作者: Wizey,作者博客:http://wenshixin.gitee.io,即时通讯网收录时有改动,感谢原作者的无私分享. 1.引言 典型的Web端即时通讯技术应用场景,主要有以下两种形式 ...

  5. 一文搞懂vim复制粘贴

    转载自本人独立博客https://liushiming.cn/2020/01/18/copy-and-paste-in-vim/ 概述 复制粘贴是文本编辑最常用的功能,但是在vim中复制粘贴还是有点麻 ...

  6. 三文搞懂学会Docker容器技术(中)

    接着上面一篇:三文搞懂学会Docker容器技术(上) 6,Docker容器 6.1 创建并启动容器 docker run [OPTIONS] IMAGE [COMMAND] [ARG...] --na ...

  7. 三文搞懂学会Docker容器技术(下)

    接着上面一篇:三文搞懂学会Docker容器技术(上) 三文搞懂学会Docker容器技术(中) 7,Docker容器目录挂载 7.1 简介 容器目录挂载: 我们可以在创建容器的时候,将宿主机的目录与容器 ...

  8. 一文搞懂所有Java集合面试题

    Java集合 刚刚经历过秋招,看了大量的面经,顺便将常见的Java集合常考知识点总结了一下,并根据被问到的频率大致做了一个标注.一颗星表示知识点需要了解,被问到的频率不高,面试时起码能说个差不多.两颗 ...

  9. 一文搞懂 js 中的各种 for 循环的不同之处

    一文搞懂 js 中的各种 for 循环的不同之处 See the Pen for...in vs for...of by xgqfrms (@xgqfrms) on CodePen. for &quo ...

随机推荐

  1. 896.Montonic Array - LeetCode

    Question 896. Monotonic Array Solution 题目大意: 类似于数学中的减函数,增函数和物理中的加速度为正或为负 思路: 先比较前两个是大于0还是小于0,如果等于0就比 ...

  2. CA周记 - Build 2022 上开发者最应关注的七大方向主要技术更新

    一年一度的 Microsoft Build 终于来了,带来了非常非常多的新技术和功能更新.不知道各位小伙伴有没有和我一样熬夜看了开幕式和五个核心主题的全过程呢?接下来我和大家来谈一下作为开发者最应关注 ...

  3. pandas:聚合统计、数据分箱、分组可视化

    1.聚合统计 1.1描述统计 #df.describe(),对数据的总体特征进行描述 df.groupby('team').describe() df.groupby('team').describe ...

  4. 面试突击55:delete、drop、truncate有什么区别?

    在 MySQL 中,删除的方法总共有 3 种:delete.truncate.drop,而三者的用法和使用场景又完全不同,接下来我们具体来看. 1.delete detele 可用于删除表的部分或所有 ...

  5. 安装ImageMagick7.1库以及php的Imagick扩展

    由于ImageMagick7以下不支持heic等图片格式,所以重新安装了ImageMagick7.1版本支持heic格式,并写此文章记录一下. 如果安装过程中遇到一些未知的错误,https://ima ...

  6. UiPath存在文本Text Exists的介绍和使用

    一.Text Exists的介绍 检查是否在给定的UI元素中找到了文本,输出的是一个布尔值 二.Text Exists在UiPath中的使用 1. 打开设计器,在设计库中新建一个Sequence,为序 ...

  7. 端口被占用的问题解决 Web server failed to start. Port ×× was already in use

    出现此问题是端口被占用了,只需要关闭正在使用的端口就行 解决思路: 1.在服务器中更改port端口号,改为不冲突,没有被占用的端口. 2.找出被占用的端口,结束被占用的端口 解决结束被占用的端口的方法 ...

  8. 【摸鱼神器】UI库秒变低代码工具——表单篇(一)设计

    前面说了列表的低代码化的方法,本篇介绍一下表单的低代码化. 内容摘要 需求分析. 定义 interface. 定义表单控件的 props. 定义 json 文件. 基于 el-form 封装,实现依赖 ...

  9. Android Studio 的初次使用

    记录我第一次使用Android Studio时遇到的问题以及一些简单的笔记. 我所使用的是Android Studio 2.2版本 遇到的问题 创建一个Hello World!项目无疑是相当简单的,我 ...

  10. wsl2安装百度apollo及其基本配置

    一. wsl2的开启 首先 WSL2 gui 需要Windows 11 Build 22000版本以上才支持 利用管理员权限打开PowerShell 执行 dism.exe /online /enab ...