K8S学习笔记之Service和kube-proxy
Service关键概念
为了方便访问Pod资源,k8s
定义了一个统一访问入口:service资源对象。service是一个固定接入层,客户端可以通过访问service的IP和端口访问到service关联的后端pod。
为什么定义service对象?
1、pod ip经常变化,service是pod的代理,我们客户端访问,只需要访问service,就会把请求代理到Pod
2、pod ip在k8s集群之外无法访问,所以需要创建service,这个service可以在k8s集群外访问的。
Service对象解读
1.DNS插件(coreDNS):service的名称解析是依赖于dns附件的
2.网络插件(calico):kubernetes要想给客户端提供网络功能,需要依赖第三方的网络插件
3.kube-proxy组件:
始终监视着apiserver中有关service资源的变动信息,需要跟master之上的apiserver交互,随时连接到apiserver上获取任何一个与service资源相关的资源变动状态。
这种是通过kubernetes中固有的一种请求方法watch(监视)来实现的,一旦有service资源的内容发生变动(如创建,删除),kube-proxy都会将它转化成当前节点之上的能够实现service资源调度,把我们请求调度到后端特定的pod资源之上的规则,这个规则可能是iptables,也可能是ipvs,取决于service的
工作原理
1.k8s在创建Service时,会根据标签选择器selector(lable selector)来查找Pod,据此创建与Service同名的endpoint对象。
2.当Pod 地址发生变化时,endpoint也会随之发生变化。
3.service接收前端client请求的时候,就会通过endpoint,找到转发到哪个Pod进行访问的地址。(至于转发到哪个节点的Pod,由负载均衡kube-proxy决定)
资源清单解释
# kubectl explain service.spec
allocateLoadBalancerNodePorts <boolean>
clusterIP <string> #动态分配的地址,也可以自己在创建的时候指定,创建之后就改不了
clusterIPs <[]string>
externalIPs <[]string>
externalName <string>
externalTrafficPolicy <string>
healthCheckNodePort <integer>
ipFamilies <[]string>
ipFamilyPolicy <string>
loadBalancerIP <string>
loadBalancerSourceRanges <[]string>
ports <[]Object> #定义service端口,用来和后端pod建立联系
publishNotReadyAddresses <boolean>
selector <map[string]string> #通过标签选择器选择关联的pod有哪些
sessionAffinity <string>
sessionAffinityConfig <Object>
#service在实现负载均衡的时候还支持sessionAffinity,sessionAffinity
什么意思?会话联系,默认是none,随机调度的(基于iptables规则调度的);如果我们定义sessionAffinity的client ip,那就表示把来自同一客户端的IP请求调度到同一个pod上
topologyKeys <[]string>
type <string> #定义service的类型# kubectl explain service.spec.type
【四类service】
ExternalName, ClusterIP, NodePort, and LoadBalancer# kubectl explain service.spec.ports
appProtocol <string>
name <string> #定义端口的名字
nodePort <integer> #宿主机上映射的端口,比如一个Web应用需要被k8s集群之外的其他用户访问,那么需要配置type=NodePort,若配置nodePort=30001,那么其他机器就可以通过浏览器访问scheme://k8s集群中的任何一个节点ip:30001即可访问到该服务,例如http://192.168.1.63:30001。如果在k8s中部署MySQL数据库,MySQL可能不需要被外界访问,只需被内部服务访问,那么就不需要设置NodePort
port <integer> -required- #service的端口,这个是k8s集群内部服务可访问的端口
protocol <string> #协议(TCP默认、UDP、SCTP)
targetPort <string> #需要绑定的pod的端口
service的四种类型
## ExternalName
适用于k8s集群内部容器访问外部资源,它没有selector,也没有定义任何的端口和Endpoint。
以下Service 定义的是将prod名称空间中的my-service服务映射到my.database.example.com
kind: Service
apiVersion: v1
metadata:name: my-servicenamespace: prod
spec:type: ExternalNameexternalName: my.database.example.com
当查询主机 my-service.prod.svc.cluster.local 时,群集DNS将返回值为my.database.example.com的CNAME记录。
## ClusterIP
通过k8s集群内部IP暴露服务,选择该值,服务只能够在集群内部访问,这也是默认的ServiceType。
## NodePort
通过每个Node节点上的IP和静态端口暴露k8s集群内部的服务。通过请求<NodeIP>:<NodePort>可以把请求代理到内部的pod。Client----->NodeIP:NodePort----->Service Ip:ServicePort----->PodIP:ContainerPort。
## LoadBalancer
使用云提供商的负载均衡器,可以向外部暴露服务。外部的负载均衡器可以路由到NodePort服务和ClusterIP 服务。
字段详述
类型是ClusterIP
## 使用Deployment创建Pod,副本数是2,通过Pod的IP访问资源
vim deploy-test-myapp.yaml
# curl <pod-ip>:<80>## 创建service,通过ClusterIP访问资源
vim svc-test-myapp.yaml
kubectl apply -f svc-test-myapp.yaml
# curl <cluster-ip>:<80># 查看详细信息,看到EndPoints有两个IP(对应副本数)
kubectl describe svc my-nginx
kubectl get ep my-nginx
apiVersion: v1
kind: Service
metadata:name: my-nginxlabels:run: my-nginx
spec:type: ClusterIPports:- port: 80 #service的端口,暴露给k8s集群内部服务访问protocol: TCPtargetPort: 80 #pod容器中定义的端口selector:run: my-nginx #选择拥有run=my-nginx标签的pod 【VIP】
## 资源转发流程
1.service可以对外提供统一固定的ip地址,并将请求重定向至集群中的pod。2.其中“将请求重定向至集群中的pod”就是通过endpoint与selector协同工作实现。3.selector是用于选择pod,由selector选择出来的pod的ip地址和端口号,将会被记录在endpoint中。endpoint便记录了所有pod的ip地址和端口号。4.当一个请求访问到service的ip地址时,就会从endpoint中选择出一个ip地址和端口号,然后将请求重定向至pod中。(具体把请求代理到哪个pod,需要的就是kube-proxy的轮询实现的)5.service不会直接到pod,service是直接到endpoint资源,就是地址加端口,再由endpoint再关联到pod。
类型是NodePort
## 创建Pod资源## 创建service资源,允许宿主机访问
vim svc-test-NodePort.yaml##【验证】
通过宿主机浏览器访问myapp的接口资源:<ip>:<30380>/path
apiVersion: v1
kind: Service
metadata:name: my-nginx-nodeportlabels:run: my-nginx-nodeport
spec:type: NodePortports:- port: 80protocol: TCPtargetPort: 80nodePort: 30380selector:run: my-nginx-nodeport
服务请求走向:
Client-node ip:30380->service ip:80-pod ip:container port Client ->192.168.1.63:30380->10.100.156.7:80->pod ip:80
类型是ExternalName
## 跨名称空间访问
#default名称空间下的client 服务想要访问nginx-ns名称空间下的nginx-svc服务## 创建名称空间test
kubectl create ns test## 创建第一个Pod资源
vim deploy-test-busybox.yaml
## 创建第一个service资源
# 该文件中指定了到 nginx-svc 的软链,让使用者感觉就好像调用自己命名空间的服务一样。
vim svc-test-ExternalName.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: client
spec: replicas: 1selector:matchLabels:app: busyboxtemplate:metadata:labels:app: busyboxspec:containers:- name: busyboximage: busyboxcommand: ["/bin/sh","-c","sleep 36000"]
---
apiVersion: v1
kind: Service
metadata:name: client-svc
spec:type: ExternalNameexternalName: nginx-svc.test.svc.cluster.localports:- name: httpport: 80targetPort: 80
## 创建第二个Pod资源
vim deploy-test-nginx.yaml
## 创建第二个service资源
vim svc-test-normal.yaml## 【验证】下面两个请求结果一致,说明client-svc已经将请求转到了nginx-svc
kubectl exec -it client-76b6556d97-xk7mg -- /bin/sh
wget -q -O - client-svc.default.svc.cluster.local
wget -q -O - nginx-svc.test.svc.cluster.local
apiVersion: apps/v1
kind: Deployment
metadata:name: nginxnamespace: test
spec:replicas: 1selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:name: nginx-svcnamespace: test
spec:selector:app: nginxports:- name: httpprotocol: TCPport: 80targetPort: 80
实践案例:引用外部MySQL
## 安装MySQL
yum install mariadb-server.x86_64 -y
systemctl start mariadbvim svc-mysql.yaml
vim ep-mysql.yaml
apiVersion: v1
kind: Service
metadata:name: mysql
spec:type: ClusterIPports:- port: 3306---
apiVersion: v1
kind: Endpoints
metadata:name: mysql
subsets:
- addresses:- ip: 10.11.2.58ports:- port: 3306
# kubectl describe svc mysql
Name: mysql
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"mysql","namespace":"default"},"spec":{"ports":[{"port":3306}],"ty...
Selector: <none>
Type: ClusterIP
IP: 10.97.86.201
Port: <unset> 3306/TCP
TargetPort: 3306/TCP
Endpoints: 10.11.2.58:3306
Session Affinity: None
三种IP
【1】Node Network(节点网络):物理节点或者虚拟节点的网络,如ens33接口上的网路地址
【2】Pod network(pod 网络),创建的Pod具有的IP地址Node Network和Pod network这两种网络地址是我们实实在在配置的,其中节点网络地址是配置在节点接口之上,而pod网络地址是配置在pod资源之上的,因此这些地址都是配置在某些设备之上的,这些设备可能是硬件,也可能是软件模拟的
【3】Cluster Network(集群地址,也称为service network),这个地址是虚拟的地址(virtual ip),没有配置在某个接口上,只是出现在service的规则当中。
kube-proxy了解
Service只是将应用对外提供服的方式做了抽象,真正的应用跑在Pod中,我们的请求转发到NodePort
上,然后kube-proxy
解析存储在iptables
或者IPVS
中的规则,来实现负载均衡。kube-proxy
实现了内部从pod到service和外部的从node port向service的访问。
1、kube-proxy其实就是管理service的访问入口,包括集群内Pod到Service的访问和集群外访问service。
2、kube-proxy管理sevice的Endpoints,该service对外暴露一个Virtual IP,也可以称为是Cluster IP, 集群内通过访问这个Cluster IP:Port就能访问到集群内对应的serivce下的Pod。
kube-proxy三种工作模式
【Userspace方式】
Client Pod要访问Server Pod时,它先将请求发给内核空间中的service iptables规则,由它再将请求转给监听在指定套接字上的kube-proxy的端口,kube-proxy处理完请求,并分发请求到指定Server Pod后,再将请求转发给内核空间中的service ip,由service iptables将请求转给各个节点中的Server Pod。
【iptables方式】
客户端IP请求时,直接请求本地内核service ip,根据iptables的规则直接将请求转发到到各pod上,因为使用iptable NAT来完成转发,也存在不可忽视的性能损耗。另外,如果集群中存上万的Service/Endpoint,那么Node上的iptables rules将会非常庞大,性能还会再打折
【ipvs方式】
客户端请求时到达内核空间时,根据ipvs的规则直接分发到各pod上。kube-proxy会监视Service对象和Endpoints,调用netlink接口以相应地创建ipvs规则并定期与Service对象和Endpoints对象同步ipvs规则,以确保ipvs状态与期望一致。访问服务时,流量将被重定向到其中一个后端Pod。与iptables类似,ipvs基于netfilter的hook功能,但使用哈希表作为底层数据结构并在内核空间中工作。这意味着ipvs可以更快地重定向流量,并且在同步代理规则时具有更好的性能。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wtCfxFt7-1658732730761)(./pic/kube-proxy-01.png)]
[1]kube-proxy都通过watch的方式监控着apiserver写入etcd中关于Pod的最新状态信息。
[2]它一旦检查到一个Pod资源被删除了或新建了,它将立即将这些变化,反应再iptables或ipvs规则中。
[3]以便iptables和ipvs在调度Clinet Pod请求到Server Pod时,不会出现Server Pod不存在的情况。
[4]自k8s1.11以后,service默认使用ipvs规则,若ipvs没有被激活,则降级使用iptables规则。
iptables规则分析
在k8s创建的service,虽然有ip地址,但是service的ip是虚拟的,不存在物理机上的,是在iptables或者ipvs规则里的。通过上面可以看到之前创建的service,会通过kube-proxy
在iptables
中生成一个规则,来实现流量路由,有一系列目标为 KUBE-SVC-xxx
链的规则,每条规则都会匹配某个目标 ip 与端口。也就是说访问某个 ip:port
的请求会由 KUBE-SVC-xxx
链来处理。这个目标 IP 其实就是service ip。
# 查看ClusterIP
kubectl get svc
# 根据IP查找
iptables -t nat -L | grep 10.111.145.211KUBE-MARK-MASQ tcp -- !10.244.0.0/16 10.111.145.211 /* default/springboot:server cluster IP */ tcp dpt:tproxy
KUBE-SVC-N6LLN4RK7MJQ5NNI tcp -- anywhere 10.111.145.211 /* default/springboot:server cluster IP */ tcp dpt:tproxy# 根据上述信息继续查询
iptables -t nat -S | grep KUBE-SVC-N6LLN4RK7MJQ5NNI-N KUBE-SVC-N6LLN4RK7MJQ5NNI
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/springboot:server" -m tcp --dport 31180 -j KUBE-SVC-N6LLN4RK7MJQ5NNI
-A KUBE-SERVICES -d 10.111.145.211/32 -p tcp -m comment --comment "default/springboot:server cluster IP" -m tcp --dport 8081 -j KUBE-SVC-N6LLN4RK7MJQ5NNI
-A KUBE-SVC-N6LLN4RK7MJQ5NNI -m comment --comment "default/springboot:server" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-YG5CH4BKPZQUH2S6
-A KUBE-SVC-N6LLN4RK7MJQ5NNI -m comment --comment "default/springboot:server" -j KUBE-SEP-WVMWCPQS2EJEYDWI# 查找出对应Pod的端口和IP
iptables -t nat -S | grep KUBE-SEP-WVMWCPQS2EJEYDWI
iptables -t nat -S | grep KUBE-SEP-YG5CH4BKPZQUH2S6-N KUBE-SEP-YG5CH4BKPZQUH2S6
-A KUBE-SEP-YG5CH4BKPZQUH2S6 -s 10.244.30.91/32 -m comment --comment "default/springboot:server" -j KUBE-MARK-MASQ
-A KUBE-SEP-YG5CH4BKPZQUH2S6 -p tcp -m comment --comment "default/springboot:server" -m tcp -j DNAT --to-destination 10.244.30.91:8081
-A KUBE-SVC-N6LLN4RK7MJQ5NNI -m comment --comment "default/springboot:server" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-YG5CH4BKPZQUH2S6
coreDNS了解
属于k8s的一个DNS插件服务,是一种常见的服务发现手段。
验证coredns
# 安装dig
vim pod-dig.yaml
# 解析dns,如有以下返回说明dns安装成功
kubectl exec -it dig -- nslookup kubernetesServer: 10.96.0.10
Address: 10.96.0.10#53
Name: kubernetes.default.svc.cluster.local
Address: 10.96.0.1
apiVersion: v1
kind: Pod
metadata:name: dignamespace: default
spec:containers:- name: digimage: xianchao/dig:latestcommand:- sleep- "3600"imagePullPolicy: IfNotPresentrestartPolicy: Always
K8S学习笔记之Service和kube-proxy相关推荐
- K8S 学习笔记三 核心技术 Helm nfs prometheus grafana 高可用集群部署 容器部署流程
K8S 学习笔记三 核心技术 2.13 Helm 2.13.1 Helm 引入 2.13.2 使用 Helm 可以解决哪些问题 2.13.3 Helm 概述 2.13.4 Helm 的 3 个重要概念 ...
- k8s学习笔记一集群部署
k8s安装笔记 基础环境配置 修改主机名: 修改hosts配置文件 安装依赖包 关闭防火墙并未Iptables设置空规则 关闭swap分区和linux虚拟内存 调整内核参数 调整系统时区 关闭系统不需 ...
- docker,k8s学习笔记汇总
整理了下博客里关于docker和k8s的文章,方便查看 docker学习笔记(一)docker入门 docker学习笔记(二)创建自己的镜像 docker学习笔记(三)docker中的网络 docke ...
- k8s组件说明:kubelet 和 kube proxy
k8s的node节点需要安装三个组件:docker/kubelet/kube proxy pod是存储容器的容器,但容器不止docker一种. CRI:container runtime interf ...
- 最详细的 K8S 学习笔记总结(2021最新版)
虽然 Docker 已经很强大了,但是在实际使用上还是有诸多不便,比如集群管理.资源调度.文件管理等等.那么在这样一个百花齐放的容器时代涌现出了很多解决方案,比如 Mesos.Swarm.Kubern ...
- k8s学习笔记(一)
第一章 kubernetes介绍 本章节主要介绍应用程序在服务器上部署方式演变以及kubernetes的概念.组件和工作原理. 应用部署方式演变 在部署应用程序的方式上,主要经历了三个时代: 传统部署 ...
- k8s学习笔记- 部署prometheus
1.Prometheus概述 Prometheus是一个开源监控系统,它前身是SoundCloud的警告工具包.从2012年开始,许多公司和组织开始使用Prometheus. 该项目的开发人员和用户社 ...
- [k8s 学习笔记]
摘自知乎: k8s入门及实践 一. k8s简介 K8S 是Kubernetes的全称,官方称其是: Kubernetes is an open source system for managing c ...
- k8s学习笔记(10)--- kubernetes核心组件之controller manager详解
kubernetes核心组件之controller manager详解 一.Controller Manager简介 1.1 Replication Controller 1.2 Node Contr ...
最新文章
- 给自己的程序添加BugReport
- Cannot connect to the Docker daemon. Is the docker daemon running on this host?
- Collect proper diagnostic data is very important
- 转 框架页有Frame、Iframe、Frameset 3个标记,初学者容易将三者混淆,下面分别讲解三者的区别。...
- SAP全球技术研发者大会上海站电子票欣赏
- 点击事件为什么会失效_1917年的法蒂玛事件,为什么会被称为最为惊悚的UFO目击事件?...
- 技术动态 | 67 亿美金搞个图,创建知识图谱的成本有多高你知道吗?
- 解决PowerPoint英语课件配音难同步的问题
- 为了离去的纪念——google
- 控制器(下) -运维笔记
- 虚拟电脑键盘app_App发布倒计时
- android后台倒计时,android倒计时封装(活动进入后台,倒计时依然能正常计时)...
- Hive grouping sets 多维度交叉清洗数据
- 期刊级别应该是怎样划分的呢?
- 时间序列分析 | 相似性度量基本方法
- 2017年全球IDC、光器件、100G及400G数通模块市场预测
- cuda 原子锁多线程操作通用原子操作
- 山东省农商行计算机真题,2018山东农商行招聘考试题库:计算机试题三
- 浪潮m6智能服务器,浪潮全新M6服务器满足智慧时代算力需求
- TCP/IP协议栈Lwip的设计与实现:之三