kubernetes底层原理
K8S基本组件及实现容器编排调度原理介绍
一、基本组件
-
etcd:一种的分布式存储机制,底层采用 Raft 协议,k8s 集群的状态数据包括配置、节点等都存储于 etcd 中,它保存了整个集群的状态。
-
API server:对外提供操作和获取 k8s 集群资源的的 API,是唯一操作 etcd 的组件,其他的组件包括管理员操作都是通过 API server 进行交互的,可以将它理解成 etcd 的 “代理人”。
-
Scheduler:在 k8s 集群中做调动决策,负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上。
-
Controller Manager:相当于集群状态的协调者,观察着集群的实际状态,与 etcd 中的预期状态进行对比,如果不一致则对资源进行协调操作让实际状态和预期状态达到最终的一致,维护集群的状态,比如故障检测、自动扩展、滚动更新等。
-
Controller Runtime:下载镜像和运行容器的组件,负责镜像管理以及 Pod 和容器的真正运行(CRI)
-
Pod:k8s 中特有的概念,可以理解为对容器的包装,是 k8s 的基本调度单位,实际的容器时运行在 Pod 中的,一个节点可以启动一个或多个 Pod。
-
kubelet:负责管理 worker 节点上的组件,与 master 节点上的 API server 节点进行交互,接受指令执行操作。
-
kube-proxy:负责对 Pod 进行寻址和负载均衡
1、pod创建过程
①用户通过kubectl或其他api客户端提交需要创建的pod信息给apiserver
②apiserver生成pod对象的信息(yaml文件),并将信息以键值对的方式存入etcd,然后返回确认信息至客户端
③apiServer开始反映etcd中pod对象信息的变化,其他组件使用watch机制来跟踪检查apiserver上的变动
④scheduler发现有新的pod对象需要创建,开始为pod分配主机并将结果信息更新至apiserver
⑤node节点上的kubectl发现有pod调度到当前节点,开始调用CRI启动容器(需要网络时调用CNI,需要存储时调用CSI),并状态结果信息返回至apiserver
⑥apiserver将接收到的pod状态信息存入etcd中
2、pod的终止过程
①用户向apiserver发送给删除pod对象的命令
②apiserver中的pod对象随时间推移而更新,在宽限期内(默认30s),pod被视为dead
③将pod标记为terminating状态
④kubelet在监控到pod对象转为terminating状态的同时启动pod关闭过程
⑤节点控制器监控到pod对象的关闭行为时,将其从所有匹配到此节点的service资源的节点列表中移除
⑥如果当前pod对象定义了prestop钩子处理器,则在其标记为terminating后会立即以同步的方式启动执行
⑦pod对象中的容器进程收到停止信号
⑧宽限期结束之后,若pod中还存在仍运行的进程,则pod对象会收到立即终止信号
⑨kubelet请求apiserver将此pod资源的宽限期设置为0从而完成删除操作,此时pod对于用户已不可见
二、ETCD介绍
1、功能
-
数据TTL(保持存活时间)失效
-
数据改变监视
-
多值
-
目录监听
-
分布式锁原值操作
2、 特点
-
键值对存储:将数据存储在分层组织的目录中
-
监测变更:检测特定的值或目录以进行更改,并对值的更改做出反应
-
简单:curl可访问用户的api
-
安全:可选的ssl客户端证书认证
-
快速:单实例每秒1000次写操作,2000次读操作
-
可靠:使用raft算法保持一致性
-
etcd进程默认监听2379端口
3、操作命令
- 列出节点集群成员
etcdctl --endpoints=localhost:2379 member list --write-out=table
- 写入数据
etcdctl --endpoints=localhost:2379 put /key1 vaule1
- 读取数据
etcdctl --endpoints=localhost:2379 get /key1
- 按key的前缀查询数据
etcdctl --endpoints=localhost:2379 get --prefix /
- 只显示键值
etcdctl --endpoints=localhost:2379 watch --prefix /
4、Etcd备份存储
etcd默认工作目录下会生成两个子目录:wal和snap
-
wal目录:存放预写式日志
- 作用:记录整个etcd内数据变化的全部历程,所有数据的修改前都要先写入wal中
-
snap目录:存放快照数据
- 作用:防止wal中文件过多,etcd定期创建快照,然后将wal中已被快照的数据删除
(1)数据恢复方法
数据遭到破坏或错误修改需要回滚到之前的某个状态
-
方法一:从快照中回复数据主体,但是未被排入快照的数据会丢失
-
方法二:执行所有wal中记录的修改操作,从最原始的数据恢复到数据损坏之前的状态,但是恢复时间较长
(2)灾备命令
- 备份命令
export ETCDCTL_API=3
ENDPOINTS=localhost:2379
mkdir /data/etcd_backup_dir
etcdctl --endpoints=${ENDPOINTS} snapshot save /data/etcd_backup_dir/etcd-snapshot.db
- 恢复命令
etcdctl --endpooints=${ENDPOINTS} snapshot restore snapshot.db
5、k8s对象在etcd中的存储位置
export ETCDCTL_API=3
./etcdctl --endpoints https://localhost:2379 --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key --cacert /etc/kubernetes/pki/etcd/ca.crt get --keys-only --prefix /
./etcdctl --endpoints https://localhost:2379 --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key --cacert /etc/kubernetes/pki/etcd/ca.crt get --keys-only --prefix /registry/statefulsets/default/redis-sts
./etcdctl --endpoints https://localhost:2379 --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key --cacert /etc/kubernetes/pki/etcd/ca.crt get /registry/statefulsets/default/redis-sts
./etcdctl --endpoints https://localhost:2379 --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key --cacert /etc/kubernetes/pki/etcd/ca.crt get /registry/configmaps/default/info
6、Etcd备份脚本
#!/bin/bash
ETCDCTL_PATH='/usr/local/bin/etcdctl'
ENDPOINTS='https://192.168.200.153:2379'
ETCD_DATA_DIR="/var/lib/etcd"
BACKUP_DIR="/var/backups/kube_etcd/etcd-$(date +%Y-%m-%d-%H-%M-%S)"
KEEPBACKUPNUMBER='5'
ETCDBACKUPPERIOD='30'
ETCDBACKUPSCIPT='/usr/local/bin/kube-scripts'
ETCDBACKUPHOUR=''
ETCDCTL_CERT="/etc/ssl/etcd/ssl/admin-master1.pem"
ETCDCTL_KEY="/etc/ssl/etcd/ssl/admin-master1-key.pem"
ETCDCTL_CA_FILE="/etc/ssl/etcd/ssl/ca.pem"
[ ! -d $BACKUP_DIR ] && mkdir -p $BACKUP_DIR
export ETCDCTL_API=2;$ETCDCTL_PATH backup --data-dir $ETCD_DATA_DIR --backup-dir $BACKUP_DIR
sleep 3
{
export ETCDCTL_API=3;$ETCDCTL_PATH --endpoints="$ENDPOINTS" snapshot save $BACKUP_DIR/snapshot.db \
--cacert="$ETCDCTL_CA_FILE" \
--cert="$ETCDCTL_CERT" \
--key="$ETCDCTL_KEY"
} > /dev/null
sleep 3
cd $BACKUP_DIR/../;ls -lt |awk '{if(NR > '$KEEPBACKUPNUMBER'){print "rm -rf "$9}}'|sh
if [[ ! $ETCDBACKUPHOUR ]]; then
time="*/$ETCDBACKUPPERIOD * * * *"
else
if [[ 0 == $ETCDBACKUPPERIOD ]];then
time="* */$ETCDBACKUPHOUR * * *"
else
time="*/$ETCDBACKUPPERIOD */$ETCDBACKUPHOUR * * *"
fi
fi
crontab -l | grep -v '#' > /tmp/file
echo "$time sh $ETCDBACKUPSCIPT/etcd-backup.sh" >> /tmp/file && awk ' !x[$0]++{print > "/tmp/file"}' /tmp/file
crontab /tmp/file
rm -rf /tmp/file
三、kube-scheduler(调度器)
1、功能:
- 负责集群资源调度,按照预订的调度策略将pod调度到相应的node节点上
2、调度原理
-
nodeSelector:将pod约束调度到具有特定标签的节点上
-
nodeAffinity:节点亲和性,根据节点上的标签来约束pod可以调度到哪些节点上
-
requiredDuringSchedulingIgnoredDuringExecution:硬亲和,调度器只有在规则完全满足的时候才能执行调度。(required affinity硬亲和)
-
preferredDuringSchedulingIgnoredDuringExecution:软亲和,调度器会尝试寻找满足对应规则的节点,如果找不到匹配的节点,调度器会调度该pod到某一节点。(preferred affinity软亲和)
-
-
podAffinity(pod亲和性):pod亲和性,可以基于已经在节点上运行的pod的标签,若满足亲和规则设定标签,则将pod调度到该节点。
-
requiredDuringSchedulingIgnoredDuringExecution:硬亲和,调度器只有在规则完全满足的时候才能执行调度。(required affinity硬亲和)
-
preferredDuringSchedulingIgnoredDuringExecution:软亲和,调度器会尝试寻找满足对应规则的节点,如果找不到匹配的节点,调度器会调度该pod到某一节点。(preferred affinity软亲和)
-
-
podAntiAffinity(pod反亲和性):pod反亲和性,基于节点上运行的pod标签,若满足反亲和规则设定的标签,则不会调度到该节点上。
-
requiredDuringSchedulingIgnoredDuringExecution:硬亲和,调度器只有在规则完全满足的时候才能执行调度。(required affinity硬亲和)
-
preferredDuringSchedulingIgnoredDuringExecution:软亲和,调度器会尝试寻找满足对应规则的节点,如果找不到匹配的节点,调度器会调度该pod到某一节点。(preferred affinity软亲和)
pod间亲和性与反亲和性的规则格式为“如果X上已经运行了一个或多个满足规则Y的pod,则这个pod应该运行在X上”,X可以是节点、机架、云提供商可用区或地理区域或类似的拓扑域,Y是K8S尝试满足的规则
-
-
污点(taint):应用于nod节点,使节点可以排斥特定的pod,特定pod无法分配调度到该节点
-
容忍度(toleration):应用于pod上,允许调度器调度带有对应污点的pod到节点上
污点和容忍度相互配合,用来避免pod分配到不合适的节点上,每个节点上都可以应用一个或多个污点,表示对于不能容忍这些污点的pod,不会被该节点接受
-
topologyKey:指定调度作用域
- topology.kubernetes.io/zone=R #zone R区域
(1)nodeSelector使用方法
- nodeSelector相关模板文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-cache
spec:
selector:
matchLabels:
app: redis
replicas: 1
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis-server
image: redis:5-alpine
nodeSelector:
disktype: ssd #指定调度到具有disktype=ssd标签的节点上
于容器模板中的spec.template.spec中添加nodeSelector字段以及disktype:ssd的key:value键值对
- 作用过程:调度器调度pod时会检查节点是否有Tag:disk:ssd的标签,若没有则调度pod失败,pod会进入pending状态
- 相关命令
kubectl get pods #查看pod状态
kubectl describe pods pod-name #查看pod事件日志
kubectl label nodes node-name disktype=ssd #给节点打上标签
(2)nodeAffinity
- 支持的操作符(通用)
操作符 | 行为 |
---|---|
In | 标签值key=value存在于提供的字符串集中 |
NotIn | 标签值不包含在提供的字符串集中 |
Exists | 对象上存在具有此键key的标签 |
DoesNotExist | 对象上不存在具有此键可以的标签 |
- 以下操作符只能与nodeAffinity 一起使用
操作符 | 行为 |
---|---|
Gt | 提供的值将被解析为整数,并且该整数小于通过解析此选择算符命名的标签的值所得到的整数 |
Lt | 提供的值将被解析为整数,并且该整数大于通过解析此选择算符命名的标签的值所得到的整数 |
(3)nodeAffinity-required aFFinity(节点硬亲和)
- 模板yaml文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-cache
spec:
selector:
matchLabels:
app: redis
replicas: 1
template:
metadata:
labels:
app: redis
spec:
affinity: #亲和性设置
nodeAffinity: #设置node亲和性
requiredDuringSchedulingIgnoredDuringExecution: #硬
nodeSelectorTerms: #硬限制选项
- matchExpressions: #设置标签的key为disktype,且value是ssd的节点,匹配规则为包含key=value
- key: disktype
operator: In
values:
- ssd
containers:
- name: redis-server
image: redis:5-alpine
nodeSelector:
disktype: ssd
注意:使用字段为spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms
(4)nodeAffinity-preferred affinity(节点软亲和)
- 模板yaml文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-cache
spec:
selector:
matchLabels:
app: redis
replicas: 5
template:
metadata:
labels:
app: redis
spec:
affinity: #亲和性设置
nodeAffinity: #设置node亲和性
preferredDuringSchedulingIgnoredDuringExecution: #软限制
- weight: 1 #倾向权重为1
preference: #软限制选项
matchExpressions: #匹配标签key值为disktype,value值为ssd的
- key: disktype #标签key值
operator: In #匹配符
values: #标签value值
- ssd
containers:
- name: redis-server
image: redis:5-alpine
resources:
limits:
memory: 1Gi
cpu: 1
requests:
memory: 256Mi
cpu: 100m
注意:使用字段为spec.template.spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution.preference
(5)podAffinity和podAntiAffinity(pod反亲和性)
- 模板yaml文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector: #标签选择器
matchExpressions: #按节点标签列出的节点选择器要求列表
- key: app
operator: In
values:
- redis
topologyKey: "kubernetes.io/hostname"
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 10 #倾向权重,在范围1-100
podAffinityTerm: #选项
labelSelector:
matchExpressions:
- key: app
operator: In #关系符,支持ln,Notln,Exists,DoesNotExist
values:
- nginx
topologyKey: "kubernetes.io/hostname" #指定调度作用域
containers:
- name: nginx
image: nginx
resources:
limits:
memory: 1Gi
cpu: 1
requests:
memory: 256Mi
cpu: 100m
注意:使用字段为spec.template.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution.labelSelector
spec.template.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution.podAffinityTerm.labelSelector
(6)taint和toleration
- 相关命令
#为节点添加污点
kubectl taintnode node-name nodetype=gpu:NoSchedule
#删除污点
kubectl taint node node-name
# 查看节点污点
kubectl get nodes
kubectl describe nodes master-01 | grep -i taint
kubectl taint node xxx-nodename node-role.kubernetes.io/master- #将 Master也当作 Node 使用
kubectl taint node xxx-nodename node-role.kubernetes.io/master="":NoSchedule #将Master恢复成Master Only状态
- 完全匹配的yaml文件模板
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
tolerations:
- key: "nodetype"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
- 匹配任意taint value的toleration容忍yaml文件模板
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
tolerations: #添加容忍
- key: "nodetype" #要容忍的污点的key
operator: "Exists" #污点key+value的操作符
value: "" #匹配任意污点的value值
effect: "NoSchedule"
- 匹配任意taint effect的toleration容忍yaml文件模板
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
tolerations: #添加容忍
- key: "nodetype" #要容忍的污点key值,空意味着匹配所有的键
operator: "Equal" #key-vaule的运算符,支持equal和exists
value: "gpu" #容忍的污点的value
effect: "" #添加容忍的规则,这里必须和标记的污点规则相同,空以为着匹配所有影响
## 四、kube-controller-manager(控制器)
功能:通过它来实现对pod的管理,比如启动pod、停止pod、伸缩pod的数量等,所有控制器一起统称为kube-controller-manager
### 1、通用控制器
| Job Controller | 处理 job |
| --- | --- |
| Pod AutoScaler | 处理Pod的自动缩容/扩容 |
| ReplicaSet | 依据Replicaset Spec 创建Pod |
| Service Controller: | 为LoadBalancer type 的 service 创建 LB VIP |
| ServiceAccount Controller | 确保serviceaccount 在当前namespace 存在 |
| StatefulSet Controller | 处理 statefulset 中的Pod |
| Volume Controller | 依据PV spec 创建 volume |
| Resource qutoa Controller | 在用户使用资源之后,更新状态 |
| Namespace Controller | 保证namespace删除时,该namespace下的所有资源都先被删除 |
| Replication Controller | 创建RC后,负责创建 Pod |
| Node Controller | 维护node状态,处理 evict请求等 |
| Daemon Controller | 依据 daemonset 创建 Pod |
| Deployment Controller | 依据 deployment spec 创建 replicaset |
| Endpoint Controller | 依据service spec创建 endpoint,依据 podid 更新 endpoint |
| Garbage Controller | 处理级联删除,比如删除deployment的同时删除replicaset 以及 Pod |
| CronJob Controller | 处理cronjob |
## 五、kubelet
* 作用:负责维护容器的生命周期,即通过控制CRI来创建、更新、销毁容器
* 功能:
* **接收并执行master发来的指令**
* **管理pod以及pod中的容器**
* **每个kubelet进场会在apiServer上注册节点自身信息,定期向master节点汇报节点资源使用情况,并通过cAdvisor监控去监控节点和容器的资源**
* **资源回收、镜像回收**
**每个节点上都会运行一个kubelet服务进程,默认监听10250端口,10248端口为health监控使用**
## 六、容器接口
### 1、CRI(容器运行时接口)(container runtime interface)
* 功能:运行于kubernetes集群的每个节点上,负责容器的整个生命周期
#### (1)CRI的组成
#### (2)OCI(开放容器计划)
定义了两个核心规范:
* **容器运行时规范**:定义了容器的生命周期,描述了容器与操作系统、文件系统和网络之间的交互方式
* **容器镜像规范**:定义了容器镜像的结构、格式、和元数据,描述了容器镜像如何被打包、分发和存储,并提供了容器运行时使用的标准接口
### 2、CNI(容器网络接口)
#### (1)kubernetes网络基础
* IP地址分配
* 路由
#### (2)网络模型设计基础原则
* 所有pod能不通过NAT就能互相访问
* 所有节点能够不通过NAT就能互相访问
* 容器内看见的IP地址和外部组件看到的容器IP是一样的
#### (3)CNI(容器网络接口)的作用
* 用于设置和删除容器的网络连通性,容器运行时通过调用CNI网络插件来完成容器的网络设置
#### (4)CNI插件分类和常见插件
* **分类**:
* IPAM类:IP地址分配
* 主插件类:网卡设置
* **常见插件**:
* Bridge:创建一个网桥,并将主机端口和容器端口接入网桥
* IPvlan:为容器添加ipvlan网口
* loopback:设置loopback网口
* **附加功能**
* portmap:设置主机端口和容器端口间的映射
* bandwidth:利用linux Traffic control限流
* firewall:通过iptables或firewalld为容器设置1防火墙规则
#### (5)CNI插件运行机制
* 作用:把容器加入网络或把容器从网络中删除
容器运行时在启动时会从CNI的配置目录中读取JSON格式的配置文件,文件后缀为“.conf”、".conflist"、".json"。如果配置目录中包含多个文件,一般情况下会议名字排序选用第一个文件作为默认的网络配置,并加载获取其中指定的CNI插件名称和配置参数。
#### (6)CNI运行机制
* **运行机制**:kubectl使用docker作为容器运行时的时候,是有kubectl查看CNI插件,并运行插件来为容器内设置网络,容器运行时通过kubelet加载的参数-cni-bin-dir和-cni-conf-dir
cni-bin-dir:网络插件的可执行文件所在目录。默认是/opt/cni/bin
cni-conf-dir:网络插件的配置文件所在目录。默认是 /etc/cni/net.d
不使用docker时,参数配置在容器运行时
* **运行流程:Kubernetes 使用 CNI网络插件的工作流程**
* Kubelet 调用 CRI 创建 pause 容器,生成对应的 network namespace;
* 调用网络 driver ;
* CNI driver 根据配置调用具体的 CNI 插件;
* CNI 插件给 pause 容器配置正确的网络, Pod 中的其他容器都是用 pause 容器的网络栈 。
ContainerNetworking组维护了一些CNI插件,包括网络接口创建的bridge、ipvlan、loopback、macvlan、ptp、host-device等,IP地址分配的DHCP、host-local和static,其他的Flannel、tunning、portmap、firewall等
#### (7)flannel插件
##### 工作模式
* **UDP模式**:使用设备网桥flannel.0,通过**flanneld进程**进行头部UPD封包解包
* 特点:不适内核原生支持,频繁的在内核态和用户态之间切换,性能非常差
* **VXLan模式**:使用网桥flannel.1在**内核中**进行UDP的封包解包,VXLAN本质上是一种 tunnel(隧道)协议,基于三层网络实现虚拟的二层网络
* 特点:内核原生支持,性能较强
* **host-GW模式**:无需网桥flannel这样的中间设备,通过在node 节点上创建到达各目标容器地址的路由表而完成报文的转发,因此这种方式要求各 node 节点本身必须处于同一个局域网
* 特点:直接通信,不经过中间设备,性能最强
#####
##### UDP模式
##### 使用方式
* flannel通过在每一个节点上启动一个叫 flanneld 的进程,负责每一个节点上的子网划分,并将相关的配置信息(如各个节点的子网网段 、外部 IP 等)保存到etcd 中,而具体的网络包转发交给具体的 backend 实现 。
* flannel的安装:①删除本机上的calico插件Kubectl delete -f californians.aml②删除cni配置文件Rm -rf /etc/cni/net.d/10-calico.conflist #删除master和work节点上的③重启master和work节点服务器④work和master节点上加载镜像⑤master节点上安装flannelKubectl apply -f flannel.yaml
```yaml
* Backend: UDP模式的yaml模板
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "udp"
}
}
securityContext:
capabilities:
add:
- NET_ADMIN
- NET_RAW
privileged: true
* Backend: VXLAN模式的yaml模板
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
flannel UDP模式跨主机通信过程
- 容器 A 发出 ICMP 请求报文,通过IP封装为10.244.0.6 (源)→ 10.244.1.4 ( 目的 )。 此时通过容器 A 内的路由表匹配到应该将 IP 包发送到网关 10.244.0.1 ( cni0 网桥)。
- 到达 cni0 的 IP 包目的地 IP 10.244.1.4 ,匹配到节点 A 上第一条路由规则( 10.244.0. 0 ) , 内核通过查本机路由表知道应该将 IP 包发送给 flannel0 接口 。
- 发送给 flannel0 接口的 IP 包将被 flanneld 进程接收, flanneld 进程接收 IP 包后在原有的基础上进行 UDP 封包, UDP 封包的形式为 172.16.66.30:8285 → 172.16.66.31:8285 。
- flanneld 将封装好的 UDP 报文经 eth0 发出,从这里可以看出网络包在通过 eth0 发出前先是加上了 UDP 头( 8 个字节),再加上 IP 头( 20 个字节)进行封装,这也是 flannel0 的 MTU 要比 eth0 的 MTU 小 28 个字节的原因,即防止封包后的以太网帧超过 eth0 的 MTU,而在经过 eth0 时被丢弃。
- 网络包经过主机网络从节点 master-01 到达节点 worker-01。
- 主机 worker-01 收到 UDP 报文后, Linux 内核通过UDP端口号 8285 将包交给正在监听的 flanneld 。
- 运行在 worker-01 中的 flanneld 将 UDP 包解封包后得到 IP 包:10.244.0.6 → 10.244.1.4。
- 解封包后的 IP 包匹配到主机 worker-01 上的路由规则 ( 10.244.1.0 ),内核通过查本机路由表知道应该将 IP 包发送到 cni0 网桥 。
- cni0 网桥将 IP 包转发给连接在该网桥上的容器 B ,至此整个流程结束 。 回程报文将按上面的数据流原路返回 。
基于底层物理网络设备通过flannel 等软件定义网络技术构建的上层网络称之为 overlay 网络 。
(8)calico插件
网络模式
-
BGP模式:使用BGP路由协议,在主机之间路由数据包
- 特点:将主机看作路由,数据包直接在主机间传输,不需要再进行包装
-
IPIP模式:基于IP in IP使用虚拟网卡设备tun10,用一个IP数据包封装另一个IP数据包,外层IP数据包包头的源地址为隧道入口设备的IP地址,目标地址为隧道出口设备的IP地址
- 特点:在数据包IP的头部再进行一层IP数据包封装,修改源地址以及目标地址
-
BGP Route Reflector:在BGP Client之间加入RR节点(路由反射器)互联,并做路由同步,减少大规模网络下的连接数
(9)POD出站流量方式
- pod到pod
k8s集群中,每个pod都有自己的IP地址,运行在pod中的应用都可以使用标准的端口号,不需要重新映射到随机端口号,所有pod之间保持三层网络的连通性,互相发送TCP/UDP/SCTP数据包。
- pod到service
Service相当于pod前面的4层负载均衡器,service总共有四种类型,最常用的是cluster类型(集群类型),这种类型的service会自动分配一个仅集群内部可以访问的虚拟IP(类似于service通过虚拟IP代理后端pod中的应用,后端pod成一个内网)
通过kube-proxy组件实现的,通过iptables/IPVS规则在pod和service之间进行各种过滤和NAT
- pod到集群外
从pod内部到集群外部的流量,kubernetes通过SNAT来处理,修改数据包源IP,把pod内部的IP:port替换为宿主机IP:port。数据包返回是从宿主机的IP:port替换为pod内部的IP:port,然后发送给POD
即为SNAT和DNAT实现源地址和目标地址转换
k8s网络架构:集群内访问 Pod ,会经过 Service;集群外访问 Pod,经过的是 Ingress
(10)主机内组网方式
k8s经典主机内组网模型是veth pair+bridge的方式。
-
过程原理:
-
pod内容器相互访问:k8s调度pod到某个节点上运行时,会在该节点linux内核中为pod创建network namespaces,给pod内所有容器使用。容器通过localhost访问同一个pod内的其他容器
-
节点上pod之间互相访问:k8s使用veth pair将容器与主机网络协议栈连接,使数据包可以进出pod 。容器放在主机跟network namespace中veth pair的一段连接到linux网桥,使同一节点上的各个pod之间相互通信
-
3、CSI(容器存储接口)
(1)功能
-
为节点、pod、pod内容器的等提供抽象化存储接口
-
将目录、文件、网络存储、云存储等抽象为卷,调用接口进行挂载
(2)存储卷插件分类
-
in-tree:在K8S内部代码上支持
-
out-of-tree:通过接口支持
(3)存储使用
- 临时存储
emptyDir设计为给应用充当缓存空间或存储中间数据
emptyDir空间位于系统根目录下(默认位置:/var/lib/kubelet/pods/),空间被所有容器共享,磁盘使用较高时会触发pod的eviction操作,影响业务的稳定
- 半持久化存储
常见半持久化存储主要是hostPath卷(本地卷),能将会节点上文件系统上的文件或目录挂载到指定的pod中,使用同一个目录的pod可能会由于调度到不同节点,导致目录中内容不同,k8s调度时无法顾及由hostPath使用的资源,pod被删除后,为做其他处理时,hostPath上写的数据遗留到节点上,占用磁盘空间
- 持久化存储
k8s中引入storageclass、Volume、PVC、pv的概念,将存储独立于pod生命周期外来管理
主流持久化存储设备(块存储和文件存储):Cephfs、Iscsi、Nfs、Hostpath
更多推荐
所有评论(0)