关于容器方面的知识大全
容器和虚拟机的区别:
1、虚拟化级别:
容器是一种操作系统级的虚拟化,它共享主机操作系统的内核,是在用户空间中提供隔离,每个容器都运行在一个独立的用户空间实例中,但与主机系统共享内核,这使得容器相对轻量,启动速度快
虚拟机是一种硬件级的虚拟化,它在主机上运行完整的操作系统,包括独立的内核,每个虚拟机都有自己的虚拟硬件,通过虚拟机监视程序(Hypervisor)与主机通信,虚拟机启动较慢,因为需要加载完整的操作系统
2、资源消耗:
由于容器共享主机系统的内核,所以它们通常占用更少的资源
虚拟机需要独立的操作系统和内核,因此通常比容器占用更多的资源
3、隔离性:
容器之间是共享主机内核的所以在安全性和隔离性上不如虚拟机
虚拟机都有独立的内核和用户空间,所以它的隔离性更加强大
4、启动时间:
容器只需要启动应用程序及其运行环境,不需要加载整个操作系统,所以启动更快
虚拟机需要加载整个的操作系统,所以启动时间较长
docker总结:
docker是什么
docker是一种轻量级的容器化技术,其主要原理是利用linux操作系统的cgroups、namespace和AUFS等特性来虚拟化系统资源,使得应用程序可以被封装成一个可移植的、可靠的、可复制的容器,在不同的环境中运行且无需担心环境差异导致的兼容性问题
解释Cgroups和AUFS
Cgroups是linux内核的一个功能,用来限制、控制与分离一个进程组的资源(如:CPU、内存、磁盘输入输出等)
AUFS是用于为linux文件系统实现联合挂载
overlayFS:
docker的核心:
1、image(镜像):可以理解为一个静态的只读文件,除了提供容器运行时所需的程序,库,资源,配置文件,还包含了一些为运行时准备的配置参数
2、containers(容器):容器是镜像创建的应用运行实例,可以将其启动,开始,停止,删除,所有的容器都是相互隔离的,镜像是只读的,容器从镜像启动的时候,在镜像的最上层创建了一个可写层,镜像本身保持不变
3、reposity(仓库):类似与代码库,用于存储和分发镜像
docker的四种网络模式:
1、bridge:默认网络,此网络和物理交换机类似,从docker0上分配一个IP给容器使用,并设置docker0的地址为默认网关。
2、Host:使用这个模式,容器不会获得一个独立的network namespace,而是和宿主机共享一个network namespace,容器不会虚拟出自己的网卡和IP,但是容器的其他方面,如文件系统,进程列表等还是和宿主机隔离的。
3、None:使用这个模式,容器没有网卡,IP路由等信息,需要我们自己为容器添加这些信息,但是None模式有助于容器的安全
4、Container:这种模式适合其他容器共用network namespace,和指定的容器共享IP、端口范围等,当然,除了这几方面之外,两个容器的文件系统,进程列表等还是相互隔离的,他们是通过容器的lo网卡(回环接口)设备通信
docker的bridge(桥接模式)的网络实现:
同一台服务器上的容器进行通信
在bridge模式下,Docker Deamon在启动时会创建一个虚拟网桥docker0,会给这个网桥分配一个子网,针对docker创建的每一个容器都会创建一个虚拟的以太网设备(veth设备对),这个设备是成对出现的,其中一端连接到docker0网桥上,另一端使用linux网络命名空间技术,映射到容器内的eth0上,然后从docker0网桥的地址段上给eth0分配一个IP地址,同时容器内也会根据IP地址生成一个MAC地址,确保不会有ARP冲突,这样可以确保同一台服务器上的容器间可以相互通信
不同服务器之间容器进行通信
为了跨节点互相通信,就必须在主机上分配端口,这样可以通过端口路由到容器上
docker的存储:
1、默认存储:运行在容器中,随着容器的删除而删除
2、bind mount:绑定挂载,使用docker run 参数进行绑定到本地的
3、volume数据卷:先创建一个数据卷,再绑到容器中
4、tmpfs mount:使用tmpfs挂载创建容器
dockerfile的指令:
FROM:非注释行的首行,标注以哪个镜像为基础镜像
LABEL:标签
WORKDIR:工作目录
RUN:docker build时所运行的命令,有三种格式:
1、RUN <command> 2、RUN "/bin/sh -c command" 3、RUN ["/bin/sh -c command"]
CMD:此指令和RUN大致一样,不同之处在于CMD是当docker run时运行的命令,CMD的参数可以提供给ENTRYPOINT docker run 添加参数时会覆盖
COPY:根据上下文,拷贝文件到镜像中具体路径下
ADD:根据上下文,拷贝文件到镜像中具体的路径,此指令和COPY大致一样,但是ADD能根据URL地址进行添加,同时如果是压缩文件,拷贝到镜像中时,具有解压功能。当是RUL下载时没有解压功能
EXPOSE:容器暴露的端口
VOLUME:容器的挂载的逻辑卷,docker run 可以覆盖掉
ENV:环境变量 docker run 可以覆盖
USER:用户
ONBUILD:依靠上一个镜像为基础镜像,运行时所走的指令
ENTRYPOINT:配置容器启动后执行的命令,不可被docker run 提供的参数覆盖
CMD和ENTRYPOINT的区别和联系:
1、CMD在docker run的时候是可以被覆盖掉的,而ENTRYPOINT则不会,只有使用--entrypoint时才会覆盖掉ENTRYPOINT的
2、CMD也可以作为ENTRYPOINT的参数,同时在执行docker run 时添加参数也会能覆盖掉CMD的
RUN和CMD的区别:
RUN和CMD都是用于执行命令,区别在与这两个指令的运行时机不同,RUN是在docker build是运行的,CMD是在docker run时运行的,同时CMD在docker run时是可以被覆盖的
docker的两种登录方式:
docker exec 此命令有两个重要的参数-i和-t,不会像attach退出时会导致容器停止,和正常console窗口操作一样
docker attach 退出容器时,会导致容器停止,同时登录到同一个容器上,如果一个窗口出现阻塞,其它窗口也会出现阻塞
dockerfile构建多镜像
要在单个dockerfile中构建多个镜像,可以使用dockerfile的多阶段构建特性,多阶段构建允许在同一个Dockerfile中定义多个构建阶段,每个阶段生成一个镜像,然后可以选择性的从一个阶段复制文件到下一个阶段
阶段1、使用FROM指令声明一个基础镜像,并使用AS定义一个阶段名称,在这个阶段中你可以执行一些编译和构建操作
如果有多个阶段,除最终阶段之外,基本上何阶段1的操作一样
最终阶段,在这个阶段中,可以从之前的构建阶段中复制生成的结构到该阶段指令为COPY --from=“之前阶段的名称”,最终镜像通常只包含应用程序的可以执行文件和运行环境
k8s的总结:
k8s的安装方式:使用的是kubeadm
什么是k8s
k8s是一个可移植,可扩展的用于管理容器化的工作负载和服务,可促进声明式配置和自动化,且拥有庞大且快速的生态系统
k8s集群有什么优点
k8s集群的注意事项:
每个node节点的pod数量不超过110,可以使用--max-pods设置pod的最大数量
node节点数不超过5千
pod总数不超过15万
容器总数不超过30万
k8s集群的优化:
etcd优化:
快照调优:
使用 V2 后端创建快照可能会很昂贵,因此只有在对 etcd 进行给定数量的更改后才会创建快照。默认情况下,每 10,000 次更改后将创建快照。如果etcd的内存使用率和磁盘使用率过高,请尝试通过在命令行中设置以下内容来降低快照阈值:
etcd --snapshot-count=5000
ETCD_SNAPSHOT_COUNT=5000 etcd
以上两种方式都可以
心跳间隔和选举超时时间调优:
heartbeat-interval:心跳间隔时间
election-timeout:选举超时时间
etcd --heartbeat-interval=100 --election-timeout=500
ETCD_HEARTBEAT_INTERVAL=100 ETCD_ELECTION_TIMEOUT=500 etcd
以上两种方法都可以修改
磁盘IO调优:
一个ETCD群集对磁盘潜伏期非常敏感。由于ETCD必须坚持其日志提案,因此来自其他过程的磁盘活动可能会导致较长的FSONC潜伏期。结果是,等等可能会错过心跳,导致要求超时和临时领导者损失。当给出高磁盘优先级时,ETCD服务器有时可以稳定地与这些过程一起运行。
提高存储限制,默认是2G
kube-apiserver的优化参数:
--enable-priority-and-fairness :如果为 true,则使用增强的处理程序替换 max-in-flight 处理程序, 以便根据优先级和公平性完成排队和调度。
--max-mutating-requests-inflight :默认值为200,如果 --enable-priority-and-fairness 为 true,那么此值和 --max-requests-inflight 的和将确定服务器的总并发限制(必须是正数)。 否则,该值限制同时运行的变更类型的请求的个数上限。0 表示无限制。
--max-requests-inflight:默认值为400,如果 --enable-priority-and-fairness 为 true,那么此值和 --max-mutating-requests-inflight 的和将确定服务器的总并发限制(必须是正数)。 否则,该值限制进行中非变更类型请求的最大个数,0表示无限制。
kube-controller-manager的优化参数:
--kube-api-qps:默认值是20,与API服务通信时每秒请求数(QPS)的限制
--kube-api-burst:默认值30,与 Kubernetes API 服务器通信时突发峰值请求个数上限
调整controller-manager同步资源的周期,避免过多的资源同步导致集群资源的消耗,所有带--concurrent前缀的参数
kube-scheduler参数:
--kube-api-qps:默认值50,与 kubernetes apiserver 通信时要使用的 QPS 如果 --config 指定了一个配置文件,那么这个参数将被忽略
根据现有的调度策略进行调度
1、对apiserver进行高可用搭建,结合keepalived和haproxy
2、对资源管理和调度策略进行优化,设置合理的资源限制和资源请求,结合调度策略:如node亲和性,pod亲和性、污点和容忍度等,对资源进行调度
3、网络优化,使用合适的网络插件,启用IPVS来代替iptables来提高大规模集群下的网络性能
4、设置合理的更新策略,实现平滑升级尽量不影响业务的正常运行
5、持久化存储,根据不同的业务使用不同持久化存储方案
6、使用网络安全策略,提高集群内部的安全隔离性
7、一些监控设置,自动扩容机制的设置,健康检查的设置等一些举措,来提高集群的稳定性
k8s集群的架构:
一个k8s集群至少包含一个控制平面(control plane),以及一个或多个工作节点(work node),控制平面(control plane)负责管理工作节点和维护集群状态,所有任务的分配都来自于控制平面,工作节点(work node)负责执行由控制平面分配的请求任务,运行实际的应用和负载,控制平面(control plane)又包含了apiserver、scheduler、controller manager和etcd四个核心组件,而controller manager 又包含了节点控制器,任务控制器,端点分片控制器和服务账号控制器等,工作节点(node work)节点上运行着kubelet、kube-proxy和container runtime三个核心组件
k8s的核心组件:
- Etcd:存储了整个集群的数据和信息状态
- kube-apiServer:操作集群的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制,集群的各组件间都是通过api server进行通信的
- kube-scheduler:资源调度,按照预定的调度策略进行资源调度
- kube-controller Manager:负责维护集群的状态,比如故障检测、自动扩容,自动更新等
controller manager又包含了:
节点控制器(node controller):负责在节点出现故障时,进行通知和响应
任务控制器(Job Controller):监测代表一次性任务的Job对象,然后创建Pods来运行这些任务直到完成
端点分片控制器(EndpointSlice Controoler):填充端点分片对象(以提供Service和Pod间的连接)
服务帐号控制器(ServiceAccount Contoller):为新的命名空间创建默认的服务账号(Service Account)
- Kubelet:负责维护容器的生命周期,同时也负责Volume和网络的管理
- Container Runtime:负责镜像管理以及Pod和容器的真正运行
- Kube-proxy:负责为Service提供集群内部的服务发现和负载均衡(根据linux内核的iptables转发实现的)
- CoreDNS:负责k8s集群内部的服务发现和域名解析功能
解析过程:当一个pod或其它服务访问k8s集群中的另一个service时,它会使用目标service的名称作为域名解析传递给CoreDNS,CoreDNS收到DNS请求后,k8s插件会根据请求中的域名查找对应的service,并将其解析为对应的podIP地址,然后CoreDNS将解析结果返回给发起请求的pod或service
- cloud-controller-manager:
k8s集群的存储挂载方式:
configmap、secrets、hostpath、emptydir(空目录,用于临时存储数据),pv、pvc、storageclass(动态存储类)
k8s的高可用集群(使用二进制安装)
使用keepalived+haproxy+kube-apiserver 6443端口
自建etcd存储集群,自建容器引擎(docker或containerd),使用kubeadm进行安装
k8s的资源清单:
pod、node、daemonset、deployment、ReplicationController、replicaset、statefulset、ConfigMap、ingress、service、pv、pvc、storage class、Secret
deployment更新策略
recreate:重新创建策略,在创建新的pod之前,所有现有的pod会被杀死
rollingupdate:滚动更新策略,
maxunavailable:最大不可用,用来指定在更新过程中不可用的pod的个数上限,该值是绝对数和百分比,此值不能为0,如:设置30%,当更新开始时会立即缩容到期望pod个数的70%,新pod准备就绪之后,继续缩容就有的replicaset,然后对新的replicaset扩容,确保更新期间pod的数在任何时候都至少保持在70%
maxsurge:最大峰值,用来指定可以创建的超出期望pod个数的pod数量,此值是绝对数或百分比,此值不能为0,如,设置30%,代表会对replicaset扩容,同时保证pod的总数不超过pod总数的130%,一旦旧pod被杀死,新的replicaset可以进一步扩容,同时确保更新期间的任何时候运行中的pod总数量最多为所需pod总数的130%
pod的访问过程或者是客户端怎么访问到后端的pod上
这会产生两个资源对象:service和endpoints
pod是应用的载体,我们通过pod的ip访问应用是不现实的,因为pod的IP地址是不固定的,每次重启或重建pod,IP地址都会改变,所以k8s引用了service资源,service会把同一个服务的多个pod进行聚合,并且提供了一个统一的入口地址,通过访问Service的入口地址就能访问后面的pod服务,同时Service资源是通过selecter的标签选择器和pod的selecter进行关联。
Endpoints是k8s的一个资源对象,存储在etcd中,用来记录一个service对应的所有pod的访问地址,它是根据service配置文件中的selecter标签选择器产生的,一个service由一组pod组成,这些pod通过Endpoints暴露出来,实际上它也是实现service服务端点的集合,换句话就是service和pod之间的联系是通过endpoints实现的
k8s的service资源的会话粘连性
sessionAffinity:确保来自特定客户端的连接每次都传递给同一个pod,默认为none
sessionAffinityConfig.clientIP.timeoutSeconds:会话粘连性超时,默认是3个小时,10800分钟
k8s的kube-proxy支持的三种工作模式:1、userspace(用户空间)2、Iptables,3、Ipvs
kube-proxy是基于linux内核的iptables进行工作的
简述kube-proxy的作用:
kube-proxy运行在所有的节点上,它是通过apiserver接口监控Service和endpoint的变化,创建路由规则以提供服务IP和负载功能,简单理解就是此进程是Service的透明代理兼负载均衡器,其核心功能是将到某个Service的访问请求转发到后端的多个Pod资源上
简述kube-proxy的iptables的原理:
从1.2版本开始,iptables作为kube-proxy的默认模式,iptables模式下的kube-proxy不再起到proxy作用,其核心功能,通过API Service的Watch接口实时跟踪Service和endpoint的变更信息,并更新对应的iptables规则,Client的请求流量则通过iptables的NAT机制直接路由到目标Pod上
简述kube-proxy的ipvs的原理:(需要安装ipvadm、ipset)
ipvs在k8s的1.11版本中升级为GA稳定版,IPVS则专门用于高性能负载均衡,并使用更高效的数据结构(hash表),允许几乎无限的规模扩张,因此被kube-proxy采纳为最新模式
在IPVS模式下,使用iptables的扩展ipset,而不是直接调用iptables来生成规则链,iptables规则链是一个线性的数据结构,ipset则引入了带索引的数据结构,因此当规则很多时,也可以很高效地查找和匹配
可以将ipset简单理解为一个IP(段)的集合,这个集合的内容可以是IP地址,IP网段,端口等,iptables可以直接添加规则对这个"可变的集合"进行操作,这样的好处就是可以大大减少iptables的规则数量
简述Iptables和IPVS的异同点:
iptables和IPVS都是基于linux的Netfilter实现的,但定位不同,二者有着本质上的区别,iptables是为防火墙而设计的,ipvs则是专门用于高性能负载均衡,并使用高效的数据结构(Hash表),允许几乎无限的规模扩张
与iptables相比,ipvs的优势:
1、为大型集群提供了更好的可扩展性和性能
2、支持比iptables更复杂的负载均衡算法
3、支持服务器健康检查和连接重试等功能
4、可以动态的修改ipset集合,即使iptables的规则正在使用这个集合
k8s中负载均衡的策略:
轮询、最少连接、iphash等
k8s的service中的四种服务类型:
1、ClusterIP:在集群内部通讯
2、NodePort:可以和集群外部通讯
3、ExternalName:表示把集群外部的服务引入到进群内部来,实现集群内部pod和集群外部进行通讯
4、LoadBalancer:这个表示我可以把k8s部署在虚拟机上,自动在外部创建负载均衡,比如在阿里云上,底层是LBAAS
Pod的生命周期:
简述一下Pod的生命周期
pod的生命周期是指,pod资源从创建到终止运行的这段时间范围,包含了pod的创建、运行初始化容器过程、运行主容器过程和pod的终止过程,而在这段时间中又分为了两个阶段,一是初始化阶段,二是主容器运行阶段,初始化阶段可以理解为是对pod的运行环境进行初始化,当初始化结束之后才开始进入到主容器运行阶段,当运行主容器时会产生容器启动后钩子,当容器终止时,会有容器结束前钩子,而在主容器运行阶段,又会有两种健康检查,就绪性检查和存活性检查,在整个pod的生命周期内会产生五种状态:
Pending(挂起):Pod已经被k8s接受,但有一个或多个容器尚未创建亦未运行,此阶段包括等待Pod被调度和镜像下载的时间
Running(运行):Pod已经绑定到了某个节点,Pod中的容器已经被创建,至少有一个容器在运行,或正处于启动或重启状态
Succeeded(成功):Pod中的容器都已成功终止,并且不会被重启
failed(失败):Pod中所有的容器已被终止,并且至少有一个容器是因为失败终止,也就是说,容器以非0状态退出或者被系统终止
unkown(未知):因为某些原因无法获得Pod的状态,这种情况通常是因为与Pod所在的主机通信失败
同时还有两个过渡状态:ContainerdCreating和terminating
pod的创建过程:
1、客户端将创建Pod的请求发送给Api Server
2、apiserver将Pod信息写入到Etcd中,etcd将结果响应给apiserver,apiserver将创建结果响应给客户端(此时pod处于pending状态)
3、scheduler通过apiserver的watch接口,获取到有未调度的Pod的通知,根据调度策略选择一个node节点,告诉apiserver这个Pod应该运行于哪个node节点
4、Apiserver将这个Pod和node的绑定信息更新到etcd中,etcd将写入结果响应给Apiserver
5、kubelet通过apiserver的watch接口,获取到当前节点有创建pod的通知,kubelet调用docker创建容器,kubelet将pod运行状态发送给apiserver
6、apiserver将pod状态信息更新到etcd
pod的初始化过程:
1、初始化容器阶段,会初始化Pod中每个容器,容器是串行执行的
2、启动main container,在main container刚刚启动后就可执行postStart指令(容器启动后钩子)
3、在整个main container运行周期中做了两类健康探测:liveness probe(存活探测)和readiness probe(就绪性探测)
4、在main container结束前可以执行preStop命令(容器结束前钩子)
pod的终止过程:
1、用户向apiserver发送删除pod对象的命令
2、apiserver中的pod对象信息会随着时间的推移而更新,在宽限期内(默认30s),pod被视为dead
3、将pod标记为terminating状态
4、kubelet在监控到pod对象转为terminating状态的同时启动pod关闭进程
5、(entpoint)端点控制器监控到pod对象的关闭行为时将其从所有匹配到此端点的service资源的endpoints列表中移除
6、如果当前pod对象定义了prestop钩子处理器,则在其标记为terminating后即会以同步的方式启动执行
7、pod对象中的容器进程收到停止信号
8、宽限期结束后,若pod中还存在仍在运行的进程,那么pod对象会收到立即终止的信号
9、kubelet请求apiserver将此pod资源的宽限期设置为0从而完成删除操作,此时pod对于用户已不可见
当apiserver接受到用户删除指令,默认有30s等待优雅退出,超过30s就会被标记为死亡状态,此时pod的状态为terminating,kubelet看到pod标记为terminating状态之后就开始了关闭pod的工作
1、pod从service的endpoint列表中被移除
2、如果该pod定义了一个停止前的钩子,其会在pod内部被调用,停止钩子一般定义了如何优雅的结束进程
3、进程被发送TERM信号(kill -14)
4、当超过优雅退出的时间后,pod中的所有进程都会被发送sigkill信号(kill -9)
Pod生命周期中常见的五种状态:
1、挂起(pending):Pod已被k8s系统接受,但是有一个或多个容器尚未创建亦未运行,此阶段包括等待Pod被调度或镜像正被下载的时间
2、运行中(running):Pod已经绑定到某个节点上,Pod中的容器都已被创建,至少有一个容器仍在运行,或正处于启动或重启状态
3、成功(succeeded):Pod中的所有容器都被成功终止,并且不会再重启
4、失败(failed):Pod中的所有容器都已终止,并且至少有一个容器是因为失败终止,容器以非0状态退出或被系统终止
5、未知(unknown):因为某些原因无法获取pod的状态,通常是因为与pod所在主机通信失败
6、complete的状态:通常表示该pod的主要容器已经成功完成其工作并正常退出,这通常用于运行一次性任务或作业(CronJob)
Deployment创建流程:
客户端将创建deployment的请求发送给Apiserver组件
1、Apiserver组件将Deployment信息写入etcd中,etcd将写入结果响应给api server,api server将结果响应给客户端
2、controller manager组件通过api server的watch接口,获取到新增的deployment资源,deployment contoller向api server发送创建replica set的请求,api server 将replica set 信息写入etcd中
3、controller manager 通过api server的watch接口获取到新增的replica set资源,replica set向api server发送创建pod的请求,api server将pod的信息写入etcd
4、scheduler 通过api server 的watch接口获取到未调度的pod通知,根据调度算法选择一个node节点,告诉api server这个pod应该运行在那个node节点上
5、api server将这个pod和node的绑定信息更新到etcd中,etcd将写入结果响应给api server
6、kubelet 通过api server的watch接口获取到当前node节点有创建pod的通知,kubelet调用docker创建容器,kubelet将pod的运行状态发送给api server
7、api server将pod的信息更新到etcd中
k8s容器探针:
livenessProbe(存活性探针):用于判断容器是否正在运行,如果不满足健康条件,那么kubelet将根据pod中设置的重启策略来判断pod是否需要重启,livenessProbe按照配置进行探测来判断容器是不是正常,如果探测不到,代表容器不健康,则kubelet会杀掉容器(不是pod资源)并根据容器的重启策略进行相应的处理,如果没有配置探针,则默认容器启动为Success状态,即探针返回的值永远是Success,即Success后pod的状态是RUNNING
readinessProbe(就绪行探针):用于指示容器是否准备好为请求提供服务,只有程序正常,容器开始对外提供网络访问,当程序没有问题时,容器的状态是Success,pod的READY状态为true,从0/1变为1/1,如果不正常一直是0/1,状态为false,如果readinessProbe正常,则此pod关联的Service资源。EndPoint的列表也将基于pod的ready状态进行设置,如果运行中ready状态变为false,则系统自动把pod从service资源关联的EndPoint列表中移除,此时kube-proxy将不再把流量引入到这个pod上,kube-proxy通过这种机制能够防止将流量转发到不可用的pod上,如果pod恢复为ready状态,将会被加回到EndPoint列表中,kube-proxy也将通过负载机制引入流量到此pod上
startupProbe(启动性探针):用于容器中的应用是否已经启动,在复杂的程序中readinessProbe和livenessProbe不能更好的判断程序是否启动和存活,这时就可以使用startupProbe,当三种探针都存在时,先执行startupProbe,其它两个探针将会被暂时禁用,直到pod满足startupProbe配置的条件,其它两个探针才运行
startupProbe(启动性探针)只是在容器启动后按照配置满足一次后,不再后续进行探测,而其它两种探针则会一直存在,直到容器消亡才停止探测
探针的四种方式:
tcpSocket:通过TCP连接检测容器内的端口是否通,如果远程系统(容器)在打开连接后立即将其关闭,算作健康
httpGet:通过应用程序暴漏的API地址检查程序是否正常,返回状态码大于等于200且小于400,则诊断成功
exec:在容器中执行一条命令
grpc:使用grpc执行一个远程过程调用,目标应该实现grpc健康检查,如果响应的状态是'SERVING',则认为诊断成功
探测结果显示的三种状态:
Success:表示检测通过
Failure:表示检测未通过
Unknow:表示检测没有正常进行
探针参数:
initialDelaySeconds:
periodSeconds:
timeoutSeconds:
successThreshold:
failureThreshold:
terminationGracePeriodSeconds:
k8s的存储卷(PV、PVC、StorageClass)
PV:持久化存储卷,是实际的存储资源,由管理员创建,定义了存储容量、访问模式、存储类别等,一旦绑定到PVC,就不能再被其它PVC使用
PVC:存储卷声明,是Pod请求使用PV的抽象,定义了Pod所需存储资源的属性,如:大小,访问模式,存储类别
StorageClass:动态存储,k8s使用StorageClass创建PVC,并根据StorageClass的规则动态分配PV,满足PVC的需求
PV与PVC的关系:
PVC是PV的请求,定义了Pod需要的存储资源的属性,PVC可以绑定到PV,前提是PV满足PVC的请求需求,PV是实际的存储资源,一旦绑定,K8S会自动将PVC映射到相应的PV上
k8s的资源限制:
limits:约束,分为内存、CPU和hugepages
spec.containers[].resources.limits.cpu
spec.containers[].resources.limits.memory
spec.containers[].resources.limits.hugepages-<size>
requesets:请求,分为内存、CPU和hugepages
spec.containers[].resources.requests.cpu
spec.containers[].resources.requests.memory
spec.containers[].resources.requests.hugepages-<size>
资源限制和请求设置的好处
当出现资源抢占的时候,按照优先级的不同,对pod进行驱逐,
驱逐策略为:
优先驱逐没有设置资源请求和限制的,其次驱逐的是limit和request不相等的pod,最后驱逐的是limit和request设置相等值的pod
QoS(服务质量等级)
1、高优先级(Guaranteed):Pod中的每个容器同时设置了CPU和内存的requests和limits,而且值必须相等
注意:如果container指定了自己内存限制,但没有指定内存请求,k8s会自动为它指定与内存限制相等的内存请求,同样,如果容器指定了自己的CPU限制,但没有指定CPU请求,k8s会自动为它指定与CPU限制相等的CPU请求
2、中优先级(Burstable):Pod中至少有一个容器设置了cpu或内存的requests和limits,但不满足Guaranteed等级的要求
3、低优先级(BestEffort):没有一个容器设置CPU和内存的requests和limits值
k8s的有状态服务和无状态服务
无状态服务:运行的pod不需要持久化存储数据,并且多个pod对于同一个请求是相同的,多个实例可以共享相同的持久化数据,相关的资源:deployment replicaset 等
有状态服务:每个pod都具有唯一的标识,该标识包括顺序标识,稳定的网络标识和稳定的存储,该标识和pod是绑定的,每个pod都有自己独立的持久化存储,并且在k8s中是通过申明模板来进行定义的。相关资源为:statefulset
无头服务属于有状态服务的一种,可以根据DNS名称访问pod,DNS名称组成,pod名称+service名称+命名空间名称+svc.cluster.local
deployment、daemonset、statefulset的区别
在k8s中,deployment、daemonset、statefulset是三种不同类型的控制器,用于管理容器化应用程序的部署和运行,他们之间的只要区别在于它们管理pod的方式以及它们适用场景不同,总的来说,deployment使用于无状态服务,statefulset适用于有状态服务,daemonset则用于在集群每个节点上运行特定的后台服务
1、deployment是k8s中常见的控制器之一,用于管理无状态应用程序,负责创建和管理pod的副本,确保定义的副本数与期望的副本数一致,支持滚动更新,主要用于web服务,api服务等不需要持久化的应用程序
2、statefulset用于管理有状态的服务,这些服务需要稳定的唯一的网络标识和持久化存储,与deployment的不同在于statefulset创建的pod具有固定的身份,即使重启和迁移它们的标识也不会改变,还支持有序部署和扩展,常用于数据库、缓存系统等需要持久化存储和唯一网络标识的应用
3、daemonset用于确保集群中的每个节点都运行一个或多个副本,通常用于部署在每个节点上运行的后天服务、日志收集等,与deployment和statefulset不同之处在于daemonset不会自动扩缩容,它会在每个节点上创建一个副本,并在节点加入或移除集群时,自动调整pod的数
k8s集群的configmap和secrets的区别:
configmap:用来将非机密性数据保存到键值对中,可以用于环境变量、命令行参数和管理配置文件
secret:用于保存包含敏感信息的数据,是加密性的
k8s的ingress和ingress controller
Ingress:
ingress:是反向代理规则,一种管理进入集群的HTTP/HTTPS流量的资源对象,用来规定HTTP/S请求应该被转发到哪个service上,比如根据请求中的不同host和url路径请求落到不同的service,
ingress controller:是一个反向代理程序,它负责解析ingress的反向规则,如果有增删改的变动,所有的ingress controller都会及时更新自己相应的转发规则,当ingress controller收到请求后就会根据这些规则将请求代理到对应的service
ingress的工作原理:
1)Ingress controller通过与Kubernetes api进行交互,动态的感知集群中Ingress规则的变化;
2)然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置;
3)再写到nginx-ingress-controller的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中;
4)然后reload一下使配置生效。以此达到域名分别配置和动态更新的问题;
ingress解决的问题:
1、减少不必要的端口映射
2、动态配置服务
kuebernetes更新证书:
备份原来的证书和etcd数据目录
修改kubeadm的原代码中关于证书时长的信息,进行build代码,得到新的kubeadm命令,替换原来集群中的kubeadm命令,使用kubeadm certs 命令进行更换证书,如果是高可用集群,则每个master节点都需要执行kubeadm certs renew all
Pod的重启策略:
Never:当容器终止退出,从不重启容器
OnFailure:当容器异常退出(退出状态码非0)时,重启容器
Always:当容器终止退出后,总是重启容器,默认策略
Pod中镜像的更新策略
Always:总是去镜像仓库拉去镜像
Never:从不拉去镜像,只用本地镜像
IfNotPresent:如果本地有需要的镜像就不会进行拉去,如果没有就去仓库拉去镜像
Pod中的pause容器:
Pause容器又叫infra容器(基础设施容器)是一种特殊类型的容器,是k8s自动生成并且注入到每个pod中,主要是为其它容器提供一个可靠的、隔离的运行环境,本身不包含任何业务逻辑,可以在创建其它容器之前将其加载到pod中,以确保Pod中的其它容器在Pause容器的基础上运行;
Pause容器的主要作用:
网络命名空间隔离
容器间通信
共享存储卷
生命周期管理
1、为其它容器提供生命周期的隔离和协调,它可以帮助管理员确保pod中各个容器的启动顺序和依赖关系,避免容器间的相互干扰和冲突;
2、为Pod中的容器提供一个稳定的网络环境,确保容器网络的连接可靠性
Pod资源中针对容器提供网络命名空间等共享机制的是底层基础容器pause,它就是为了管理pod容器的共享操作,也能管理容器的生命周期,这个pause的容器有两个核心功能:1、它提供了整个pod的linux命名空间的基础,2、启动PID命名空间,它在每个pod中都作为PID为1的进程(init进程),并收回僵尸进程
pause容器的工作原理:
1、与k8s其它组件进行交互:
Pause容器作为Pod中的一个组件,与k8s的其他组件进行交互,当pod被创建时,API服务将Pause容器的配置信息存储在etcd中,并通知Contoller manager对Pod进行处理,Contoller manager将Pause容器与Pod中的其它容器一起调度到节点上运行
2、管理容器的生命周期:
Pause容器通过使用名为cri-pause的进程来管理其它容器的生命周期,当pod中的其它容器启动时,cri-pause进程会将这些容器的启动信息记录在特定的文件中,当pod被删除时,cri-pause进程会检测到该文件并停止记录,以确保Pod中的容器在Pause容器的基础上一致地执行生命周期操作
3、实现容器间的协调合作
Pause容器通过使用cni网络插件来实现容器间的协调合作,当Pod中的其它容器启动时,cni网络插件将为这些容器分配IP地址,并设置网络连接,确保Pod中的各个容器可以相互通信,实现协调合作
Pod中的init containers:
init容器与其它普通容器非常像,但是有两点是不一样的,1、它必须在应用容器启动前运行完成,2、一个init容器必须在下一个init容器运行前完成运行,是有执行顺序的,同时init容器不支持lifecyle、livenessProbe、readinessProbe和startupProbe,因为它们必须在pod就绪前运行完成。
k8s的网络模型:
k8s的网络模型的目标是:每个一个pod都拥有一个扁平化共享网络命名空间的IP,称为podIP,通过podIP,pod能够跨网络与其他物理机和pod进行通信,一个pod一个IP的(IP-per-IP)模型创建一个干净、反向兼容的模型,在该模型中,从端口、网络、域名解析、服务发现、负载均衡、应用配置和迁移等角度,pod都能被看成虚拟机或物理机,这样就能够平滑的从一个非容器环境迁移到同一个pod内的容器环境
为了实现这个模型,在k8s中需要解决:容器间的通信,pod间的通信(同一个node上pod间和不同node上的pod间的通信),pod和service间的通信
Pod间的通信:
1、容器之间的通信
同一个Pod中的容器,共享同一个网络命令空间,共享同一个linux协议栈,容器间的通信是可以通过localhot进行相互通信的
2、同一个node节点上的Pod间的通信
主要依赖两个主要设备,一个是虚拟网络设备(veth pair),veth pair每次都是生成一对,一端连接的是pod,一端连接的宿主机上的网络命名空间上,然后在宿主机这边又接入到了一个网桥设备(cni0),通过网桥设备把报文等发送到相对应pod的虚拟网络设备(veth pair)上,再通过虚拟网络设备连接到相连的pod上
3、不同node节点上的Pod间的通信
这需要通过网络组件进行实现,如flannel,calico
4、Pod和Service间的通信
通过iptables的路由过滤转发
flannel网络:
Flannel是一种覆盖网络,它能够给每一个node节点上的容器分配一个互不冲突的IP地址,在这些IP地址之间建立一个覆盖网络,也就是将TCP数据包封装在另一种网络包里面进行路由转发和通信,网络信息都会存储在etcd中
flannel的网络模式:
UDP:
host-gw:
VXLAN:
calico网络:
calico是基于BGP的纯三层网络,calico在每个节点上利用Linux Kernel实现了一个高效的虚拟路由器vRouter来负责数据转发的,每个vRouter都是通过BGP协议把本节点上运行的容器的路由信息向整个calico网络广播,并自动设置到达其他节点的路由转发规则,calico保证所有的容器之间的数据流量都是通过IP路由的方式完成互联互通,calico节点组网是直接利用数据中心的网络结构,不需要额外的NAT、隧道或覆盖网络(overlay network),没有额外的解包封包
calico的网络模式:
IPIP:
BGP:
flanel和calico网络插件的区别:
网络拓扑:
Flannel:通过创建虚拟网络层来实现容器之间的通信,通常使用Overlay网络技术(VXLAN或UDP封装)将容器的IP地址映射到节点的物理IP地址,然后路由数据包以实现容器之间的通信
Calico:使用BGP路由协议来实现容器间的通信,每个节点在Calico网络中有唯一的IP地址,并使用BGP来交换路由信息,从而实现容器间的直接路由
性能和效率:
Flannel:使用Overlay网络技术,引入了一些额外的封装和解封装,可能会对性能产生一些微弱的负担
Calico:直接路由方法更高效,减少了一些封装和解分装的操作,减少了额外的网络开销
网络策略:
Fannel:本身不提供网络策略,但是可以和k8s的网络策略相结合
Calico:允许定义复杂的网络策略,如,允许\拒绝流量
部署复杂性:
Flannel:部署简单,用于小型的集群
Calico:用于大中规模的集群,提供更多的配置和管理
k8s集群的RBAC授权
RBAC是k8s集群基于Role(角色)的访问控制,是一种基于组织中用户的角色来调节控制计算机或网络资源的访问方法
Role:
ClusterRole:
RoleBinding:
ClusterRoleBinding:
Kubernetes集群外部如何访问集群内的服务:
对于kubernetes,集群外部的客户端默认是无法通过pod的IP和Service的虚拟IP,虚拟端口号访问的,通常需要使用四种方式进行访问
1、映射pod到宿主机
2、映射Service到宿主机
3、映射Service到LoadBalancer
4、通过ingress进行访问
k8s的pod调度策略:
默认的调度策略
定向调度(强制调度)
nodeName:根据node节点的名称选择调度到哪个节点上,创建pod时,指定nodeName的名称
nodeSelector:根据node节点的lable进行选择调度到那个节点上
实现方式:1、给node节点打标签,kubectl lable nodes node01 disktype=ssd
2、创建pod时,指定nodeselector
亲和性调度
nodeAffinity:以node为目标,根据node的标签来解决pod可以调度到哪些node上的问题
podAffinity:以pod为目标,根据pod的标签来解决pod可以和哪些已存在的pod部署到同一个拓扑域中的问题
podAntiAffinity:以pod为目标,根据pod的标签来解决pod不能和哪些已存在的pod部署到同一个拓扑域中的问题
亲和性和反亲和性的使用场景说明:
亲和性:如果两个应用频繁交互,那就有必要利用亲和性让两个应用尽可能的靠近,这样就可以减少网络通信带来的性能耗损
反亲和性:当应用采用副本部署时,有必要采用反亲和性让各个应用实例打散分布在各个node上,这样可以提高服务的高可用性
亲和性调度的调度策略又分为:preferredDuringSchedulingIgnoredDuringExecution、requiredDuringSchedulingIgnoredDuringExecution
软亲和性:尽量调度到满足亲和性策略的节点上,如果策略得不到满足时,也可以调度到其它节点上
硬亲和性:只能调度到符合亲和性策略的节点上
污点和容忍度
污点:node通过污点拒绝pod调度到上面
NoSchedule:k8s不会把pod调度到具有该污点的node上,但不会影响当前node上已经存在的pod
PreferNoSchedule:k8s将尽量避免把pod调度到具有该污点的node上,除非没有其它节点可以调度
NoExecute:k8s将不会把pod调度到具有该污点的node上,同时也会把该node上已存在的pod驱离
容忍度:pod通过设置容忍度忽略node上的污点,把pod调度到node上
tolerations:
- key: "key"
operator: "Equal"|"Exists"
effect: "effect"
value: "value"
tolerationSeconds: 3600 #延迟驱逐时间(当容忍度不符合节点定义时,pod在该节点运行超过该时间,会被驱逐)
Equal:与污点信息完全匹配的等之关系,key、value和effect与节点的taint完全一致,才能调度到node上
Exists:存在性匹配方式,会忽略value,只要有key和effect就行,同时,如果不指定key、effect值时,能匹配容忍所有的污点,当不指定effect值时,能匹配污点key与对应的所有effect值
k8s的网络隔离(NetworkPolicy)
三种规则两种匹配
三种规则:
1、对同一个namespace下的pod进行网络隔离
podSelector
2、对不同的namespace下的pod进行网络隔离
namespaceSelector
3、根据CIDR进行隔离
两种匹配:
1、ingress:流入,在该字段下编写的入站策略,也就是被选中的pod允许哪些资源访问
2、egress:流出,在该字段下编写的出站策略,也就是被选中的pod可以访问哪些资源
示例:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: networkpol-01
namespace: default
spec:
podSelector: #pod选择器
matchLabels:
app: canary-nginx #使用标签选中pod,限制被选中的pod的访问
policyTypes:
- "Ingress"
- "Egress"
ingress: #入站白名单(当前被选中的pod允许哪些资源访问)
- from:
- podSelector: #通过pod选择器同命名空间下的运行访问pod
matchLabels:
name: busybox ## busybox 可以得到 canary-nginx 的内容
- namespaceSelector: #通过命名空间选择器选中允许访问的资源有哪些
matchLabels:
kubernetes.io/metadata.name: hello ## 这个hello名称空间的可以访问 canary-nginx 的内容
- ipBlock: #CIDR方式指定允许访问的资源有哪些
cidr: "192.168.0.0/16" ## 默认 从 192.168.0.0 - 192.168.255.255 都能访问这个Pod
except: ## 排除指定范围
- "192.168.1.0/24" ## 192.168.1.0-192.168.1.255 不能访问
### 两个 - ,代表并集(或者)
### 一个 - ,代表交集(且)
ports:
- port: 80 #监听端口
egress: ## 出站白名单,也就是当前通过"canary-nginx"选中的pod能给访问哪些资源
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: hello ## app: canary-nginx 能访问hello名称空间的所有
ports:
- port: 80 #监听端口
ETCD数据的备份和恢复
数据备份:
使用etcdctl进行备份,指定数据库的地址端口,指定ETCD的密钥地址,指定备份方式和数据的备份名称,如:
etcdctl snapshot save etcd.db(数据备份名称) --endpoints=https://127.0.0.1:2379 --cacert=(指定etcd根证书) --cert=(指定etcd客户端数字证书) --key=(指定key)
数据恢复:
需要停止api-server和etcd服务,备份k8s集群的数据和配置,备份etcd的原来数据
etcdctl snapshot restore etcd.db --data-dir=(数据恢复的地址)
api接口的限流:
kong:
sentinel:
维护k8s集群node节点的过程
1、先使用命令使node节点不可调度
kubectl cordon node01
2、使用 drain标记node节点为维护阶段,驱逐该节点上pod
kubectl drain node node01
k8s的污点设置
kubectl taint node k8s-node01 key=value:NoSchedule
pod中出现oom之后怎么dump文件下来
可以使用挂载卷的方式,
或者可以使用kubectl cp把dump文件拷贝出来
当发布的时候还能访问旧有的pod上,该怎么办?
service资源下的sessionAffinity设置为ClusterIP
可以设置会话超时时间
sessionAffinityConfig.clientIP.timeoutSeconds:默认为10800(3小时)
k8s集群的RBAC授权
role(角色)
rolebinding(角色绑定)
clusterrole(集群角色)
clusterrolebinding(集群角色绑定)
k8s的边车容器(cidecar)
边车容器是与主容器在同一个pod中运行的辅助容器,这些容器通过提供额外的服务或功能(如日志,监控、数据同步)来增强或扩展主应用容器的功能,而不需要修改主应用代码