一、容器和虚拟化之间的区别
1、由于docker不需要虚拟管理程序和虚拟机操作系统,运行的只是应用,所以占用资源少。电脑同时开几个虚拟机就跑不动了。
二、k8s和docker的关系
docker主要是通过dockerfile来生产镜像,而k8s 用于关联和编排在多个主机上运行的容器
三、kube-proxy ipvs和 iptables的异同
iptables和 ipvs 如何选择
- IPVS 支持更多的负载均衡策略,如轮询(Round Robin)、最少连接(Least Connections)和基于源 IP 的哈希(Source Hashing)等。
iptables 主要支持简单的轮询负载均衡。- 对于大规模集群,IPVS 模式由于其 O(1) 的复杂度,提供了更高效的连接处理,而 iptables 模式是 O(n) 算法,随着服务和后端 Pod 数量的增加,性能可能下降
对于大型集群或需要高性能网络的环境,IPVS 通常是一个更好的选择。
对于小型或中等规模(10 到 50 台节点)的集群,iptables 可能足够使用,并且配置起来更简单。- 如果安全性是一个关键考虑因素,并且您需要利用 iptables 的高级过滤功能,可能会倾向于使用 iptables 模式。
最后还是要根据实际测试结果定
1、kube-proxy默认是iptables,因为系统们自带这个,ipvs就不一定自带。但是ipvs性能好很多,特别是容器特别多的时候
Netfilter 是一个在 Linux 操作系统上实现网络包过滤和处理的框架。它允许用户空间程序拦截、修改或丢弃进出网络接口的数据包。Netfilter 的核心组件是 iptables,它是一个命令行工具和内核模块,用于配置 Netfilter 规则。iptables 允许管理员定义各种规则,以确定如何处理不同类型的网络流量。
2、相同在于都基于netfilter转发
iptables是为防火墙而设计的管理工具
ipvs专门用于高性能LB集群-LVS
LVS(Linux Virtual Server)是一个用于构建高可用性、高性能和可伸缩性的 Linux 负载均衡解决方案。它允许将网络流量分发到多个后端服务器上,从而提高系统的可用性和性能。LVS 在 Linux 内核中实现,提供了几种负载均衡算法和调度器来分发流量。
LVS提供了负载均衡和故障转移功能,使得多个服务器可以作为一个单一的逻辑服务器向用户提供服务
LVS的主要组件:
-
Director:LVS运行的核心节点,负责处理客户端请求并根据配置的规则将流量分发到后端的真实服务器(Real Server)。
-
Real Server:实际处理业务请求的服务器,可以是Web服务器、数据库服务器等。
-
IP Virtual Server (IPVS):LVS的核心模块,运行在Director上,负责实现负载均衡的算法。
LVS的工作模式:
-
NAT(网络地址转换)模式:Director修改请求包的目标IP地址,将其转发到后端服务器,服务器响应后再由Director将响应包发送回客户端。
-
DR(直接路由)模式:Director直接将请求转发到后端服务器,后端服务器将响应直接发送给客户端,Director在此过程中充当路由器的角色。
-
TUN(隧道)模式:适用于跨越不同网络的场景,Director将请求隧道到远程的Director,然后由远程Director转发到后端服务器。
配置LVS:
- 在Director上配置LVS规则,包括虚拟IP地址、后端服务器列表、负载均衡算法(如轮询、最少连接等)。
举例来说,假设你有一个网络应用,它需要处理大量的 HTTP 请求。为了确保应用的高可用性和性能,你可以使用 LVS 来构建一个负载均衡集群。你可以将 LVS 配置为监听进入的 HTTP 请求,并根据一定的算法将这些请求分发给后端的多个 web 服务器。
例如,你可以使用 LVS 中的最常用的负载均衡算法之一:Round Robin(轮询)。在这种情况下,LVS 将按照轮询的方式将每个新的 HTTP 请求分发给下一个后端服务器。这样一来,所有的后端服务器都会接收到大致相等数量的请求,从而实现负载均衡。
另外,LVS 还支持其他的负载均衡算法,如 Least Connections(最少连接)、Weighted Round Robin(加权轮询)和 Source Hashing(源地址哈希)等。这些算法可以根据不同的需求和场景进行选择和配置,以实现更精细化的流量分发。
3、iptables
- 优点:灵活,添加规则立即生效。
可以根据tcp不同阶段进行控制
iptables 可以根据 TCP 协议中不同的阶段(如连接建立阶段、数据传输阶段和连接关闭阶段)来控制网络流量。这意味着你可以在不同的 TCP 阶段上实施不同的规则,以实现特定的网络行为。
举例说明:
- 连接建立阶段:在 TCP 连接建立时,你可以使用 iptables 来控制哪些连接可以被接受,哪些应该被拒绝。例如,你可以允许特定 IP 地址范围的连接进入你的服务器:
iptables -A INPUT -p tcp --syn -s 192.168.1.0/24 -j ACCEPT
- 数据传输阶段:在 TCP 连接建立之后,数据开始传输时,你可以使用 iptables 来控制数据包的转发、修改或丢弃。例如,你可以允许特定端口的数据流通过:
iptables -A FORWARD -p tcp --dport 80 -j ACCEPT
- 连接关闭阶段:
这条 iptables
命令用于防止特定类型的 TCP 数据包(即带有 RST 标志的数据包)从系统中发出。具体说明如下:
iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP
参数解析
iptables
:这是一个用户空间工具,用于配置 Linux 内核的内置防火墙(即 netfilter)。-A OUTPUT
:表示将规则添加到OUTPUT
链中。OUTPUT
链处理所有从本地系统发出的数据包。-p tcp
:指定协议为 TCP。--tcp-flags RST RST
:匹配 TCP 数据包的标志位。--tcp-flags
后面的第一个RST
表示要检查的标志位,第二个RST
表示标志位应设定为 RST(复位)。-j DROP
:表示对匹配的数据包执行DROP
操作,即丢弃数据包,不进行进一步的处理或转发。
整体作用
这条命令的作用是:所有出站的 TCP RST(复位)数据包将被防火墙丢弃,不会离开本地系统。
应用场景
阻止 TCP RST 数据包通常用于以下几种情况:
- 防止连接被意外关闭:某些调试或网络测试场景中,可能需要保持 TCP 连接,即使对方发送了 RST 数据包。例如,在使用 Wireshark 等工具抓包分析时,可能希望保持连接打开,以便持续观察数据流。
- 避免干扰:某些情况下,网络设备或中间设备可能会发送 RST 数据包以终止连接,这条规则可以防止本地系统发送 RST,从而避免连接被中断。
举例说明
假设我们在一个测试环境中,需要测试一个客户端和服务器之间的长连接。为了确保在测试过程中,即使有异常数据包出现也不会导致连接被断开,我们可以在客户端机器上添加这条 iptables
规则。
# 添加防止 RST 包发出的规则
iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP
这样一来,即使客户端因为某些原因试图发送 RST 数据包,这些数据包也会被本地防火墙丢弃,连接可以继续保持。
- 缺点:表规则太多时,响应变慢,线性延迟。因为它是自上而下执行的
4、ipvs
1)优点:支持哈希,转发效率高, 调度算法丰富
假设我们有一个网络应用,它提供了用户登录服务。为了实现负载均衡,我们使用 IPVS 将登录请求分发到多个后端服务器上。
现在,我们可以使用哈希算法基于客户端 IP 地址来分发请求。这意味着相同的客户端 IP 地址将始终被映射到同一台后端服务器上。这样做的好处是,如果同一个用户多次登录,他们的请求将始终被发送到同一台服务器上,从而提高了缓存的利用率和请求处理的效率。
因此,IPVS 支持哈希算法,通过哈希算法进行转发可以提高转发效率,并且可以根据不同的需求选择不同的哈希算法,例如基于源 IP 地址、目标 IP 地址、源端口、目标端口等。
2)缺点。老旧内核不支持。升级下内核到最少5.0
四、kube-proxy如何切换 ipvs
在 Kubernetes 中,将 kube-proxy
的模式从 iptables
切换到 ipvs
可以通过以下步骤实现。ipvs
模式相对于 iptables
模式具有更高的性能和更多的负载均衡算法。
步骤 1:确保系统支持 IPVS
首先,需要确保 Kubernetes 节点的操作系统支持 IPVS 并加载了所需的内核模块。
检查内核模块
使用以下命令检查所需的 IPVS 内核模块是否已加载:
lsmod | grep ip_vs
如果没有看到输出,需要加载这些模块:
modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_sh
modprobe nf_conntrack_ipv4
确保这些模块在系统重启后仍然加载,可以将这些命令添加到 /etc/modules
文件中。
安装 IPVS 工具
安装 ipvsadm
工具以管理 IPVS 配置:
# 对于 Debian/Ubuntu 系统
sudo apt-get install -y ipvsadm
# 对于 CentOS/RHEL 系统
sudo yum install -y ipvsadm
步骤 2:配置 kube-proxy 使用 IPVS 模式
修改 kube-proxy
的配置以使用 IPVS 模式。可以通过修改 kube-proxy
的配置文件或使用命令行参数实现。
通过配置文件修改
找到 kube-proxy
的配置文件(通常是 kube-proxy-config.yaml
),然后修改或添加以下内容:
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
通过命令行参数修改
如果 kube-proxy
是通过命令行参数启动的,可以在启动命令中添加 --proxy-mode=ipvs
参数。例如,如果你使用的是 kubeadm
部署的集群,可以通过以下步骤修改:
- 编辑
kube-proxy
的 ConfigMap:
kubectl edit configmap -n kube-system kube-proxy
- 找到
config.conf
中的mode
字段,将其值设置为ipvs
:
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
- 保存并退出编辑器。
步骤 3:重启 kube-proxy
应用配置更改后,重启 kube-proxy
以使配置生效:
kubectl delete pod -n kube-system -l k8s-app=kube-proxy
这将删除所有 kube-proxy
Pod,Kubernetes 将自动根据新的配置重新创建它们。
验证 IPVS 模式
最后,验证 kube-proxy
是否正在使用 IPVS 模式:
kubectl get pods -n kube-system -l k8s-app=kube-proxy -o wide
登录到其中一个 kube-proxy
Pod 所在的节点,并检查 IPVS 规则:
ipvsadm -L -n
如果输出中显示 IPVS 规则,说明 kube-proxy
已成功切换到 IPVS 模式。
五、蓝绿发布
只有它用于测试环境,其他金丝雀,灰度,滚动啥的发布都是交互场景了,特点是升级,回退切换速度非常快
不足:全量切换,不能控制百分之几的流量到哪个
过程:
就是运行蓝绿的yaml,同时有v1,v2两个pod【镜像内容和version不同】,通过edit service,把seletor的version改成v2,然后就切换过来了
其实不止两个版本,5个版本都能切换
六、静态pod
由kubelet创建
静态pod是把yaml放到 /etc/kubernetes/manifests/ 这里,就会自动产生pod. 只有删除掉yaml,pod才能消失
静态 Pod 的 YAML 文件放在哪个节点上,只有那个节点会运行该 Pod
七、k8s持久化
- emptydir 临时存储
- hostpath 挂载宿主机目录
( 使用 hostPath 卷可以将节点的特定日志目录挂载到 Pod 中,以便 Pod 可以访问和存储日志。) - pv 有很多种形式 nfs gfs ceph
local 和 hostpath的区别
StorageClass 的 Local 类型
项目示例
示例 1:本地 MySQL 数据库
在本地磁盘上运行 MySQL 数据库,以利用本地存储的高性能。
- 创建 StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
- 创建 PersistentVolume
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
local:
path: /mnt/disks/ssd1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node1
- 创建 PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
storageClassName: local-storage
- 部署 MySQL Pod
apiVersion: v1
kind: Pod
metadata:
name: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: mysql-pvc
HostPath
项目示例
示例 1:Nginx 访问宿主机静态文件
使用 Nginx 服务器直接访问宿主机上的静态文件目录。
- 创建 Pod
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
hostPath:
path: /data/nginx
type: Directory
示例 2:收集宿主机日志文件
使用 Fluentd 容器收集宿主机上的日志文件。
- 创建 Pod
apiVersion: v1
kind: Pod
metadata:
name: fluentd
spec:
containers:
- name: fluentd
image: fluent/fluentd
volumeMounts:
- name: varlog
mountPath: /var/log
volumes:
- name: varlog
hostPath:
path: /var/log
type: Directory
总结
-
StorageClass 的 Local 类型:
- 适用于需要持久化存储和高 I/O 性能的应用。
- 例如:本地数据库存储、大数据处理任务。
-
HostPath:
- 适用于需要直接访问宿主机文件系统的应用。
- 例如:调试和开发阶段的文件访问、静态数据共享、宿主机日志收集。
根据项目的具体需求和数据存储要求选择合适的存储类型,可以有效提升应用的性能和数据管理效率。
storageclass都有哪些类型
Kubernetes 中的 StorageClass
是一个用于动态提供 PersistentVolume
的 API 对象。StorageClass
定义了存储的供应商、类型和相关的参数,它允许用户在不直接管理 PersistentVolume
的细节的情况下请求存储资源。StorageClass
可以与不同的存储系统提供商集成,以下是一些常见的 StorageClass
类型:
- 云提供商的存储服务:
- AWS Elastic Block Store (EBS):适用于 Amazon Web Services,提供块存储服务。
- Azure Disk:适用于 Microsoft Azure,提供块存储服务。
- Azure File:适用于 Microsoft Azure,提供文件存储服务。
- Google Persistent Disk (GPD):适用于 Google Cloud Platform,提供块存储服务。
- DigitalOcean Volumes:适用于 DigitalOcean,提供块存储服务。
- 开源存储解决方案:
- Ceph RBD:基于 Ceph 分布式存储系统,提供高性能块存储。
- GlusterFS:一个开源的分布式文件系统,提供可扩展的存储解决方案。
- NFS:网络文件系统,适用于共享文件存储。
- 商业存储解决方案:
- Portworx:提供跨云的持久化存储和数据管理。
- VMware vSphere:适用于 VMware 环境的存储解决方案。
- CSI(Container Storage Interface):
- CSI 是 Kubernetes 中的一个标准接口,允许存储提供商以插件的形式集成到 Kubernetes 中。许多存储提供商都提供了 CSI 驱动,如 CSI 提供的 AWS EBS、Azure Disk、GPD 等。
- 本地存储:
- Local:用于将本地存储暴露给 Pods,通常用于开发和测试环境。
- 其他:
- Static Provision:静态提供的
PersistentVolume
,不通过StorageClass
动态创建。
- Static Provision:静态提供的
NFS 和 ClusterFS
在使用 NFS 和 GlusterFS 作为 StorageClass 时,必须提前部署好 NFS 和 GlusterFS 服务器
数据共享:NFS 存储可以在多个 Pod 之间共享数据,非常适合需要共享数据的应用场景,例如 Web 服务器集群共享相同的静态内容。
持久化存储:数据可以持久化保存在 NFS 服务器上,即使 Pod 重启或迁移,数据仍然存在。
ClusterFS
分布式存储:数据分布在多个节点上,具有高可用性和弹性扩展能力。
高可用性:提供数据冗余,防止单点故障。
横向扩展:可以通过添加节点轻松扩展存储容量和性能。
八、Dockerfile中 copy和add 的区别
copy 把宿主机文件或目录复制到容器内
add 把宿主机文件或目录复制到容器内 并且 还可以自动解压缩压缩文件(如 .tar, .tar.gz, .tgz, .bzip2, .bz2, .xz, .tar.xz, .zip 等格式),并且可以指定远程 URL 进行下载和添加到容器中
九、k8s都有哪些组件,作用分别是什么?
Kubernetes(简称K8s)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。Kubernetes集群由多个组件组成,这些组件可以分为以下几个主要类别:
- 控制平面组件(Master Components):
- kube-apiserver:作为Kubernetes控制平面的前端,提供RESTful API,用于集群的各类操作。
当你使用 kubectl apply -f deployment.yaml 命令来部署这个应用时,以下过程会发生:
1)请求发送:kubectl 客户端将该请求发送给 kube-apiserver。
2)验证和认证:kube-apiserver 验证请求的格式,并对请求进行认证和授权。
3)数据存储:验证通过后,kube-apiserver 将该 Deployment 对象存储在 etcd 中。
4)调度和管理:kube-apiserver 将 Deployment 的信息传递给 kube-scheduler 和 kube-controller-manager,它们会调度 Pod 到合适的节点,并监控和管理 Deployment 的状态。 - etcd:一个高可用的键值存储系统,持久化存储集群的所有状态和配置信息。维护集群的当前状态。
- kube-scheduler:负责分配Pods到合适的节点上。
- kube-controller-manager:运行控制器进程,包括节点控制器、副本控制器、端点控制器等。
- kube-apiserver:作为Kubernetes控制平面的前端,提供RESTful API,用于集群的各类操作。
- 节点控制器(Node Controller):
负责节点的注册、健康检查和故障处理。
确保集群节点的健康和可用性。- 副本控制器(Replication Controller):
确保指定数量的 Pod 副本在集群中运行。
提供高可用性和负载均衡,自动修复 Pod 故障。- 端点控制器(Endpoint Controller):
将服务与实际的 Pod 关联起来,维护 Endpoints 对象。
确保服务能够正确负载均衡地访问到相应的 Pod。
- cloud-controller-manager(可选):与云服务提供商的API交互,管理云资源。
- 节点组件(Node Components):
- kubelet:在每个节点上运行的代理,确保Pods的容器运行正常。
- kube-proxy:负责维护节点上的网络规则,实现服务抽象。
- 容器运行时(如Docker、containerd):负责运行容器的软件。
- 插件(Plugins):
- DNS:集群内的DNS服务器,用于服务发现。
- Web界面(如Dashboard):提供集群状态的图形化界面。
- 网络插件:如Calico、Flannel等,负责实现集群内部的网络通信。
- 核心概念(Core Concepts):
- Pod:Kubernetes的基本工作单元,一个或多个容器的集合,共享网络和存储资源。
- Service:定义一组Pod的访问策略,通常是通过标签选择器来指定。
- Volume:用于存储的抽象,可以被Pod中的容器访问。
- Namespace:用于实现多租户的资源隔离。
- Deployment、StatefulSet、DaemonSet等:用于部署和管理Pod的控制器。
这些组件共同工作,提供了一个平台,使得容器化应用程序可以在物理机或虚拟机上以集群的方式运行。Kubernetes确保应用程序的稳定性、可伸缩性和高可用性,同时也简化了容器化应用程序的部署和运维工作。
十、kube-proxy和calico,fannel之间的关系是什么?
Flannel 和 Calico 主要工作在网络层面,负责 Pod 网络的创建和流量的路由。而 kube-proxy 工作在应用层面,负责服务的访问和负载均衡
Calico 和 Flannel 提供基础网络设施,kube-proxy 利用这些设施实现服务的访问和负载均衡。
十一、kubectl 和kubelet
kubectl 通过 API 服务器发送命令,API 服务器将命令传递给 kubelet,kubelet 在节点上执行实际操作。
kubelet 知道当前节点上运行的所有 Pod 的状态,但它并不知道整个集群中的 Pod 状态。kubelet 通过向 API 服务器汇报节点和 Pod 状态,并接收调度指令。
kubectl 和 API 服务器通信的配置文件 — ~/.kube/config
kubelet 使用 /etc/kubernetes/kubelet.conf 配置文件来配置与 API 服务器的通信和认证信息
十二、如何为移除,添加节点
kubeadm 创建的token 的默认有效时间是24h
-
创建token
kubeadm token list 查看 -
移除之前先排干节点上的pod drain
-
delete node
-
把里面的数据清空
-
服务器修好了拿回来,再kubeadm join加进去
十三、svc端口
kubeadm安装的k8s 集群默认的 svc的端口范围是 30000-32767
使用上面的是因为此时kubectl连不上了apiserver了。
执行之后要把kube-system里的apiserver删掉,让其自己重新生成就好了
十四、常见控制器和特点
- deployment启动pod是无顺序的,这样对于mysql这种不能辅助pod先启动。pod的名字是随机的
deployment的后端存储是共享。多个节点同时写入,会出事。所以适用于只读的 - statefulSet主要用于数据库
- ds主要用于日志收集和数据监控的pod, 强制每个节点都有
十五、k8s 拉伸收缩副本失效
- 自动拉伸 autoscale和 HPA
- 在你给出的命令
kubectl autoscale deployment nginx --min=4 --max=15 --cpu-percent=80
中:
kubectl autoscale
:这是用于自动扩展资源的命令。deployment nginx
:指定要自动扩展的 Kubernetes 部署对象,这里是名为nginx
的部署。--min=4
:设置自动扩展的最小副本数为 4。这意味着即使负载很低,也会至少有 4 个 Pod 运行。--max=15
:设置自动扩展的最大副本数为 15。这意味着即使负载很高,也不会超过 15 个 Pod。--cpu-percent=80
:设置触发自动扩展的 CPU 使用率阈值为 80%。当 Pod 的平均 CPU 使用率超过 80% 时,自动扩展器会尝试增加 Pod 的数量。
这个命令会创建或更新一个水平 Pod 自动缩放器(Horizontal Pod Autoscaler,HPA),它将根据 CPU 使用率自动调整 nginx
部署的 Pod 数量,以确保系统的性能和资源利用率。
3. 设置了自动拉伸,即使你手动设置 replicas=2,但是它还是会到4个就是这个原因
十六、
- 一个svc,多个pod,那么curl ip:port, 这几个pod是被平均负载的,这个过程是通过iptables或者ipvs实现的。
- tolerationSeconds:300 300秒,这个是pod所在的机器node2挂掉后,pod存在的时间,5分钟后,k8s自动把node2上的pod迁移到node1上,并且标注node2 挂掉了。node2上面的pod terminating
- 如果使用iptables,那么就会有一部分用户访问失败,因为iptables不知道svc后面的 pod 不能用了。ipvs可以感知后面的pod 已经死掉,就不去负载
- 或者讲tolerationSeconds改成比如100秒。即如何修改node 故障pod迁移的收敛时间 300. 不宜改到太小,因为一网络波动就换位置对资源消耗太大。
修改300到100 改 deployment 就行,两个地方unreachable和 not-ready 那里
十七、deployment 升级和回滚 (版本不同,就是换镜像版本)
在yaml中添加记录多少版本
revisionHistoryLimit: 5
kubectl apply -f v1.yaml --record --record: 在 Kubernetes 的变更历史记录中添加注释,记录这次变更的执行命令
kubectl rollout history deployment -n test my-nginx
这条命令用于查看指定 namespace 中某个 Deployment 的滚动更新历史。下面是对命令各部分的详细解释:
kubectl
: Kubernetes 命令行工具,用于与 Kubernetes 集群交互。rollout history
: 查看资源(如 Deployment)滚动更新的历史记录。deployment
: 指定要查看历史记录的资源类型是 Deployment。-n test
: 指定命名空间(namespace)为test
。如果不指定,默认为default
命名空间。my-nginx
: 指定要查看历史记录的 Deployment 名称为my-nginx
。
具体含义
-
kubectl:
Kubernetes 的命令行工具,用于管理 Kubernetes 集群中的资源。 -
rollout history:
查看指定 Deployment 的滚动更新历史。滚动更新是指在更新 Deployment 时,以滚动方式逐个替换 Pod。 -
deployment:
指定要查看历史记录的资源类型是 Deployment。 -
-n test:
指定命名空间test
。Kubernetes 资源是在不同命名空间中隔离的,通过指定命名空间,可以查看特定命名空间中的资源。如果不指定命名空间,默认查看default
命名空间中的资源。 -
my-nginx:
指定要查看滚动更新历史的 Deployment 名称是my-nginx
。
示例输出
运行 kubectl rollout history deployment -n test my-nginx
可能会得到类似以下的输出:
REVISION CHANGE-CAUSE
1 kubectl apply --filename=my-nginx-deployment.yaml
2 kubectl apply --filename=my-nginx-deployment-v2.yaml
每一行表示一次更新,其中:
REVISION
表示更新的版本号。CHANGE-CAUSE
表示更新的原因或变更命令,如果你在kubectl apply
命令中使用了--record
选项,就会记录下变更的命令。
应用场景
通过查看滚动更新历史,你可以了解 Deployment 的变更过程,排查问题或回滚到之前的版本。例如:
kubectl rollout undo deployment -n test my-nginx --to-revision=1
这条命令将把 my-nginx
Deployment 回滚到第一个修订版本。
十八、存储卷类型
十九、kubectl 不能自动补全
yum install bash-completion
二十、防止自动更新k8s
都给hold住,解锁就用unhold
centos的这样
三十、k8s的备份和还原。配合ceph
将所有有状态服务的存储数据存储在另一个地方是一种备份数据的方法,但仅仅删除 Kubernetes 并重新安装并不能完全恢复之前的服务状态。下面是一些你需要考虑的因素:
-
配置数据备份:除了有状态服务的存储数据外,你还需要备份配置数据,如 ConfigMap 和 Secrets。这些数据包含了应用程序配置和敏感信息,对于完全恢复服务非常重要。
-
集群配置备份:Kubernetes 集群的配置信息,例如节点配置、网络配置等,也需要备份。如果你重装 Kubernetes,你需要确保在重装之前保存这些信息,以便在新的 Kubernetes 集群中恢复。
-
应用程序镜像和部署描述:如果你的服务依赖于特定的容器镜像和部署描述(如 Deployment、StatefulSet),你需要确保这些镜像和描述也能被恢复或者重新创建。
-
数据迁移和恢复:在重新安装 Kubernetes 后,你需要将之前备份的数据和配置重新导入到新的 Kubernetes 集群中。这可能需要一些手动操作或者使用自动化工具来帮助你完成。
总之,虽然备份有状态服务的存储数据是恢复服务的重要一部分,但你还需要备份和恢复其他关键数据和配置信息才能确保完全的恢复。因此,在执行这样的操作之前,请确保你有一个全面的备份和恢复计划,并测试这个计划以确保它可以按预期工作。
31、keepalived和 haproxy
apiserver负载均衡: 在Kubernetes集群中,HAProxy可以部署在apiserver前面,作为负载均衡器使用,负责将来自客户端(如kubectl命令行工具或其它组件)的请求均匀地分发到多个apiserver实例上,提高系统的整体吞吐量和响应速度。
在构建Kubernetes多Master节点的高可用集群时,Keepalived可以用于管理kube-apiserver的VIP。如果有任何一个Master节点故障,Keepalived会自动将VIP切换到另一个健康的Master节点,确保API服务不间断。
32、静态pod
kubeshpere自带etcd,静态pod的形式
静态 Pod 是 Kubernetes 中一种特殊的 Pod 实现方式,与通过控制器(如 Deployment、StatefulSet 或 DaemonSet)动态管理的 Pod 不同,静态 Pod 是直接由节点上的 kubelet 进程管理的,并且仅存在于创建它的那个节点上。这意味着静态 Pod 不是由 Kubernetes API 服务器管理的,你不能通过 API 对它们进行修改、删除或查询操作,也无法与副本控制器(ReplicationController)或其他高级资源对象相关联。
静态 Pod 的用武之地包括:
-
系统服务或基础设施组件:
- 在一些场景下,你可能希望在每个节点上运行一些基础服务,如监控代理(Prometheus Node Exporter)、日志收集器(Fluentd)或节点级别的监控工具,这些服务不需要水平扩展,也不需要复杂的管理逻辑,静态 Pod 很适合这类应用。
-
测试和开发环境:
- 在本地开发或测试环境中,可能不需要复杂的部署管理流程,直接通过静态 Pod 快速部署应用可以简化开发流程,加快迭代速度。
-
高度定制化的应用部署:
- 当应用有非常特定的部署需求,不适用于标准的控制器模式时,静态 Pod 提供了一种灵活的部署方式。例如,某些应用可能需要直接与宿主机系统服务紧密集成,或者有严格的节点亲和性需求。
举例说明:
假设你在一个 Kubernetes 集群中,想要确保每个节点上都运行一个日志收集代理,而且这个代理不需要根据负载自动扩缩容,也不需要复杂的更新策略。这时,就可以使用静态 Pod 来部署这个日志收集代理。
操作步骤如下:
-
准备 Pod 配置文件:首先,在每个节点的
/etc/kubernetes/manifests/
目录下创建一个 YAML 文件,定义日志收集代理的 Pod 规格,包括容器镜像、端口映射、资源请求等信息。 -
kubelet 自动创建 Pod:当 kubelet 在节点上启动时,它会自动检查这个目录下的所有文件,并根据这些文件的定义创建对应的静态 Pod。
-
监控与管理:由于静态 Pod 是由 kubelet 直接管理的,如果 Pod 出现故障,kubelet 会自动尝试重启它。但是,要查看 Pod 的状态或对其进行修改,就需要直接操作节点上的配置文件。
通过这种方式,每个节点上都会有一个独立的日志收集代理运行,且其生命周期直接与节点绑定,无需额外的管理开销。
33. 什么是网桥
网桥(Bridge)是一种网络设备或软件功能,用于连接和管理不同网络段之间的数据流量。它的主要作用是将两个或多个网络段连接在一起,使得这些网络段可以作为一个单一的网络来运行
在现代网络中,物理网桥已经被交换机所取代,因为交换机提供了更高的端口密度和更先进的流量管理功能。然而,网桥的概念仍然在虚拟网络和软件定义网络(SDN)中存在,例如Linux网桥就是一个软件实现的网桥,它可以在Linux系统中模拟物理网桥的行为,用于连接不同的虚拟网络接口。
34. 什么是overlay
Overlay 网络是在现有网络之上构建的虚拟网络。它通过将容器网络的报文封装在底层网络报文中,实现跨物理主机的容器间通信。这种封装可以是基于 UDP 的(如 VXLAN),也可以是基于其他协议的。封装后的报文可以在物理网络上传输,到达目标主机后,再由目标主机上的网络栈解封,将报文转发给目标容器。
35. Fannel
物理机 A 上的容器如何访问到物理机 B 上的容器呢?
Fannel使用 UDP 实现 Overlay
流程
在物理机 A 上的容器 A 里面,能看到的容器的 IP 地址是 172.17.8.2/24,里面设置了默认的路由规则 default via 172.17.8.1 dev eth0。
如果容器 A 要访问 172.17.9.2,就会发往这个默认的网关 172.17.8.1。172.17.8.1 就是物理机上面 docker0 网桥的 IP 地址,这台物理机上的所有容器都是连接到这个网桥的。
在物理机上面,查看路由策略,会有这样一条 172.17.0.0/24 via 172.17.0.0 dev flannel.1,也就是说发往 172.17.9.2 的网络包会被转发到 flannel.1 这个网卡。
这个网卡是怎么出来的呢?在每台物理机上,都会跑一个 flanneld 进程,这个进程打开一个 /dev/net/tun 字符设备的时候,就出现了这个网卡。
物理机 A 上的 flanneld 会将网络包封装在 UDP 包里面,然后外层加上物理机 A 和物理机 B 的 IP 地址,发送给物理机 B 上的 flanneld。
在大规模的 Kubernetes 集群中,每个节点之间都需要通信。如果使用 TCP,每两个节点之间都需要建立和维护一个连接。这意味着在 N 个节点的集群中,需要管理 N*(N-1)/2 个连接,这带来了巨大的复杂性和开销。
物理机 B 上的 flanneld 收到包之后,解开 UDP 的包,将里面的网络包拿出来,从物理机 B 的 flannel.1 网卡发出去。
在物理机 B 上,有路由规则 172.17.9.0/24 dev docker0 proto kernel scope link src 172.17.9.1。
这条信息是关于网络接口配置的记录,通常出现在 Linux 系统中,特别是在使用了 Docker 的环境中。具体来说,这条记录表示:
172.17.9.0/24
:这是一个 IP 地址和网络掩码的表示,其中172.17.9.0
是网络的 IP 地址,/24
表示网络掩码是 255.255.255.0,即这个网络中有 256 个 IP 地址,从172.17.9.0
到172.17.9.255
。dev docker0
:指定这个 IP 地址配置在名为docker0
的网络设备上。docker0
是 Docker 默认创建的网桥接口,用于连接 Docker 容器和服务主机。proto kernel
:表示这个网络配置是由内核协议栈管理的,而不是用户空间的程序。scope link
:表示这个 IP 地址的范围是链接本地(link-local),即这个 IP 地址只在当前的物理网络链接上是有效的,不会被路由到其他网络。src 172.17.9.1
:指定这个网络接口的源 IP 地址是172.17.9.1
,即这个网络接口的本地 IP 地址。
综上所述,这条记录说明了在 Linux 系统中,Docker 容器使用的docker0
网桥接口被配置了 IP 地址172.17.9.1
,属于172.17.9.0/24
这个子网,且这个地址是用于本地链接的。这意味着 Docker 容器可以通过这个接口与宿主机或其他容器在这个子网内进行通信。
将包发给 docker0,docker0 将包转给容器 B。通信成功。
上面的过程连通性没有问题,但是由于全部在用户态,所以性能差了一些。
用户态(User Space)和内核态(Kernel Space)是操作系统中的两种运行模式:
用户态:应用程序运行的空间。在这个空间内,程序不能直接访问系统资源,如网络接口卡或内存管理单元,而必须通过系统调用(system call)来请求内核提供服务。
内核态:操作系统内核运行的空间。内核可以直接访问硬件资源,执行特权指令,并管理系统资源。系统调用处理程序、设备驱动程序和其他核心操作系统功能都在内核态运行。
通过VXLAN(就是不用udp封装,用vxlan的 VTEP)
VXLAN
VXLAN通过在第三层(Layer 3)网络之上构建一个虚拟的第二层(Layer 2)网络,使得不同地理位置的设备能够像在同一个局域网内一样进行通信。
VXLAN使用24位的VNI(VXLAN Network Identifier)作为网络标识,理论上可以支持多达16M(2^24)个独立的虚拟网络,这远远超过了传统VLAN的4K限制。
由于VNI是一个24位的数字,它的取值范围从0到2^24 - 1
(即,从0到16777215)。这意味着理论上可以有多达1600万个(16M)不同的VXLAN网络段。这与只有4000个(2^12)VLAN ID的传统VLAN相比,提供了极大的扩展性。
传统VLAN ID只有12位,只能支持最多4096个VLAN。而VXLAN的24位VNI可以支持多达1600万个网络段
VXLAN允许虚拟机(VM)在不同物理服务器之间迁移时,保持其二层网络属性不变,即虚拟机的MAC地址和IP地址在迁移过程中保持稳定。
VXLAN使用隧道技术,将二层数据帧封装在UDP包中,通过IP网络进行传输,到达目的地后再进行解封装,恢复原始的以太网帧。
VXLAN的工作原理
- 封装:VXLAN 将原始的 Layer 2 以太网帧封装到 Layer 3 IP 数据包中。这是通过在原始以太网帧前添加一个 VXLAN 头和一个 UDP 头来完成的。VXLAN 头包含一个24位的虚拟网络标识符(VNI),用于区分不同的虚拟网络。
- 隧道:封装后的数据包通过底层 IP 网络进行传输,这个 IP 网络可以是数据中心内部网络,也可以是广域网。VXLAN 隧道使得跨不同网络设备和域的虚拟网络成为可能。
- 解封装:在目标设备上,VXLAN 数据包被解封装,恢复为原始的 Layer 2 以太网帧,然后根据以太网帧的目的 MAC 地址进行转发。
VTEP负责封装和解封装VXLAN 帧。
VXLAN 封装提供了更好的性能,因为它避免了用户空间和内核空间之间的上下文切换
在使用VXLAN时,为什么还需要源MAC和目标MAC:
VXLAN是一种封装协议,它将原始的以太网帧封装在UDP包中,以便在三层网络中传输二层网络流量。尽管VXLAN工作在网络层,但它传输的是二层以太网帧,因此保留了原始以太帧的头部,包括源MAC地址和目标MAC地址。
这些MAC地址对于封装和解封装过程非常重要,因为它们决定了数据包在二层网络中的最终目的地。当VXLAN封装的数据包到达目的节点时,VXLAN隧道终端(VTEP)会解开封装,并根据目标MAC地址将原始的以太帧转发到正确的内部目的地。源MAC地址用于识别发送设备的身份,以便于响应或反馈。
以太帧(Ethernet Frame):
以太帧是IEEE 802.3标准定义的一种数据链路层的数据结构,用于局域网中传输数据。一个典型的以太帧包括以下几个部分:
目的MAC地址:帧的接收方的硬件地址。
源MAC地址:帧的发送方的硬件地址。
类型/长度:指示数据字段的类型或者长度。
数据:传输的数据负载,最大长度为1500字节。
校验序列:用于错误检测。
vxlan流程
通过 netlink 通知内核建立一个 VTEP 的网卡 flannel.1。在我们讲 OpenvSwitch 的时候提过,netlink 是一种用户态和内核态通信的机制。
当网络包从物理机 A 上的容器 A 发送给物理机 B 上的容器 B,在容器 A 里面通过默认路由到达物理机 A 上的 docker0 网卡,然后根据路由规则,在物理机 A 上,将包转发给 flannel.1。这个时候 flannel.1 就是一个 VXLAN 的 VTEP 了,它将网络包进行封装。
内部的 MAC 地址这样写:源为物理机 A 的 flannel.1 的 MAC 地址,目标为物理机 B 的 flannel.1 的 MAC 地址,在外面加上 VXLAN 的头。
外层的 IP 地址这样写:源为物理机 A 的 IP 地址,目标为物理机 B 的 IP 地址,外面加上物理机的 MAC 地址。
这样就能通过 VXLAN 将包转发到另一台机器,从物理机 B 的 flannel.1 上解包,变成内部的网络包,通过物理机 B 上的路由转发到 docker0,然后转发到容器 B 里面。通信成功。
36. Calico
Calico 利用了三层网络的路由转发机制,而不是引入额外的网络封装来处理容器间的流量。这样做的好处是可以避免 Overlay 网络可能带来的性能损耗
现在,让我们用一个比喻来理解Calico网络是如何工作的:
想象你有一个大型的邮局,邮局内部有很多不同的房间(这就像是容器),每个房间都有一个邮箱(容器的网络接口)。在传统的Overlay网络中,每个房间的邮件都需要通过一个中央的邮件分发中心(Docker0)来转发,这就像是在邮局内部增加了一个额外的步骤,可能会降低邮件分发的效率。
Calico网络的工作方式是,我们去掉了这个中央邮件分发中心,直接在每个房间的邮箱上贴上了地址标签(路由规则),这样邮件可以直接通过邮局的直接邮递系统(物理网络)来分发,而不需要经过额外的步骤。
具体来说,Calico网络做了以下几件事情:
- 去掉Docker0:每台机器不需要有一个Docker0来作为容器网络的中心,这样可以节省IP地址资源。
- 使用Veth Pair:容器和宿主机之间通过Veth pair连接,这样容器的网络流量可以直接通过宿主机的物理网络接口来转发,提高了效率。
- 设置路由规则:在宿主机上设置路由规则,使得宿主机知道如何将流量转发到正确的容器。同时,在容器内部也设置路由规则,使得容器知道如何将流量发送到外部网络。
物理机化身为路由器,通过路由器上的路由规则,将包转发到目的地。在这个过程中,没有隧道封装解封装,仅仅是单纯的路由转发,性能会好很多
一台物理机上,每创建一个容器,也需要多配置一条指向这个容器的路由。如此复杂,肯定不能手动配置,需要每台物理机上有一个 agent,当创建和删除容器的时候,自动做这件事情。这个 agent 在 Calico 中称为 Felix。
在 Calico 中,每个 Node 上运行一个软件 BIRD,作为 BGP 的客户端,或者叫作 BGP Speaker,将“如何到达我这个 Node,访问我这个 Node 上的容器”的路由信息广播出去。所有 Node 上的 BGP Speaker 都互相建立连接,就形成了全互连的情况,这样每当路由有所变化的时候,所有节点就都能够收到了
Calico 中还实现了灵活配置网络策略 Network Policy,可以灵活配置两个容器通或者不通。
只有六个节点,BGP 的互连已经如此复杂,如果节点数据再多,这种全互连的模式肯定不行,到时候都成蜘蛛网了。于是多出了一个组件 BGP Route Reflector,它也是用 BIRD 实现的。有了它,BGP Speaker 就不用全互连了,而是都直连它,它负责将全网的路由信息广播出去。
想象一下,你有一个数据中心,它由多个机架组成,每个机架上有多台服务器。每台服务器上运行着多个容器,这些容器需要相互通信,同时也需要与数据中心外的网络进行通信。
机架内的通信
在每个机架上,我们有一台服务器作为 BGP Router Reflector(BGP 路由反射器)。这个路由反射器就像是一个中心点,负责收集和分发机架内所有服务器上的路由信息。
- BGP Speaker:每台服务器上都有一个 BGP Speaker(BGP 发言人),它负责将服务器上的容器路由信息告诉给机架上的 BGP Router Reflector。这就像是每个服务器都有一个代表,他们会将服务器的地址信息告诉给路由反射器。
- iBGP 协议:服务器与 BGP Router Reflector 之间的通信使用的是内部 BGP(iBGP)协议。这就像是机架内部的通讯语言,用于在服务器和路由反射器之间交换路由信息。
机架间的通信
机架之间也需要交换路由信息,这样才能让一个机架上的容器与另一个机架上的容器进行通信。
- 接入交换机:每个机架都有一个接入交换机,负责连接机架内的服务器。这些交换机之间会建立 BGP 连接,通过外部 BGP(eBGP)协议交换路由信息。这就像是机架之间的信使,他们负责传递不同机架的路由信息。
- 核心或汇聚交换机:如果数据中心的核心或汇聚交换机实现的是三层路由功能,那么路由信息需要通过这些交换机来告知其他机架。这就像是城市中的主要道路,负责将不同地区的地址信息传递给整个城市。
假设你有一个由两台物理机(物理机 A 和物理机 B)组成的网络,它们之间通过一个路由器连接。每台物理机上运行着多个容器,这些容器属于不同的虚拟网络。
问题:物理机间容器通信
物理机 A 上的容器想要与物理机 B 上的容器通信。但是,物理机 A 不知道如何到达物理机 B 上的容器,因为它只知道自己直接连接的网络,而不知道物理机 B 的内部网络结构。
解决方案:Calico 的 IPIP 模式
Calico 使用 IPIP 模式在物理机之间建立一个隧道,这个隧道就像是一个虚拟的直连线路,使得物理机 A 和物理机 B 上的容器看起来像是直接连接在同一个网络上。
- 隧道建立:在物理机 A 和物理机 B 上,Calico 会创建一个 IPIP 隧道接口。这个隧道接口在物理机的网络命名空间中,但它实际上是用来封装容器流量的。
- 封装流量:当物理机 A 上的容器想要发送数据到物理机 B 上的容器时,数据包会被封装在另一个 IP 数据包中,外层的源 IP 是物理机 A 的 IP,目标 IP 是物理机 B 的 IP。内层的源 IP 和目标 IP 是容器的 IP 地址。这样,封装后的数据包就可以通过物理网络传输了。
- 路由器的工作:路由器看到的是外层的 IP 数据包,它会根据外层的 IP 地址进行路由,将数据包发送到物理机 B。路由器不需要知道容器的 IP 地址,它只需要知道如何到达物理机 B。
- 解封装流量:物理机 B 收到封装的数据包后,会解开外层的封装,根据内层的 IP 地址将数据包发送到相应的容器。
总结
通过这种方式,Calico 的 IPIP 模式允许物理机上的容器跨物理网络进行通信,而不需要中间的路由器了解容器的内部网络。物理机 A 和物理机 B 之间的通信就像是它们通过一个虚拟的直连线路连接在一起,这个线路就是 IPIP 隧道。这样,容器就可以在不同的物理机上无缝通信,就像它们在同一个网络上一样。