一、容器基本概念
容器运行时,多种虚拟化技术,runC、kata、gVisor等。containerd -shim不是个lib,是个守护进程,管理容器生命周期,可被containerd动态接管。
(可以从containerd中脱离出来,插件化管理)
容器引擎架构
有状态数据不能随容器删除丢失,挂在卷来持久化。
二、K8S核心概念
1、K8S——自动化容器编排平台:部署、弹性、管理。
核心功能:服务发现与负载均衡、容器自动装箱、存储编排、自动容器恢复、自动发布与回滚、配置与密文管理、
批量执行、水平伸缩。
调度:调度器(组件)将容器装到集群的某一台机器上
2、K8S架构
k8s中所有的内容都抽象为资源, 资源实例化之后,叫做对象。在k8s中,一般使用yaml格式的文件来创建符合我们预期期望的pod,这样的yaml文件我们一般称为资源清单
- Master
用户不会直接与Node交互,通过master
master主要4个组件
api server:所有组件都跟api server进行连接,组件间一般不独立连接,通过api server传送消息 。本身可以水平扩展
控制器:集群状态的管理,自动修复、水平扩张。可以热备
调度器:完成调度操作。只有一个active,可以热备。
分布式存储:etcd本身是高可用系统。
- Node
运行pod的组件是Kublet,Node中最关键的组件。每个node都会运行这几个组件:
通过api sever接收到需要pod运行状态的指令 ,提交到container runtime组件中,在OS中创建容器运行所需的环境,把容器运行起来。
kubelet不会直接对网络、存储进行操作,靠插件进行操作,厂商写网络插件、存储插件,真正进行操作。
在kubernetes中也有它自己的network,为提供service network进行组网。真正完成service组网的组件是kube-proxy。
一次调度pod执行操作
3、K8S核心概念与API
- pod:最小调度及资源单元,一个多个容器组成。
定义容器运行的方式(Command、环境变量等),提供给容器共享的运行环境(网络、进程空间)
- Volume(管理K8S存储)
声明在Pod中的容器可访问的文件目录。一个卷可被挂载在pod中一个或多个容器的指定路径下。
(是个抽象的概念)支持多种后端存储的抽象:本地存储、分布式存储、云存储。
- Deployment
pod上层的抽象,定义一组pod的副本数目、版本等。一般用deployment做应用的管理。
通过控制器维持pod的数目(自动恢复失败的pod)
通过控制器以指定的策略 控制版本(版本升级、重新生成、回滚等)
- Service
提供访问一个或多个pod实例的稳定访问地址。(用户想访问一个固定 的VIP,而不像要各容器的IP。负载均衡)
实现service有多种方式:ClusterIP,NodePort,LoadBalancer
- Namespaces
一个集群内部的逻辑隔离机制(鉴权、资源额度)每个资源pod,deployment、service都属于一个namespace。
三、pod与容器设计模式
所有“设计模式”的本质都是:解耦和重用。
容器本质是一个视图被隔离、资源首先的进程。
容器里PID=1的进程就是应用本身。(管理虚拟机= 管理基础设施;管理容器 = 直接管理应用本身)
K8S——云时代操作系统,容器镜像——软件安装包。容器——进程,pod——进程组。
1、pod设计的原因
亲密关系- 调度解决
两个应用需要运行在同一台宿主机上
超亲密关系-Pod 解决
会发生直接的文件交换
使用localhost或者Socket文件进行本地通信
会发生非常频繁的RPC调用
会共享某些Linux Namespace(比如,一个容器要加入另一个容器的Network Namespace)
pod概念的设计,解决两个问题:①怎么描述超亲密关系 ②怎么对超亲密关系的容器做统一调度。
2、pod如何设计
(1)共享网络
容器A和B
通过 Infra Container 的方式共享同一个 Network Namespace
直接使用localhost进行通信
看到的网络设备跟Infra容器看到的完全一样
一个Pod只有一个IP地址,也就是这个Pod的NetworkNamespace对应的IP地圳
所有网络资源,都是一个Pod一份,并且被该Pod中的所有容器共享
(2)共享存储
volume,容器可以声明挂载同一个卷
3、容器设计模式
Sidecar
在pod里定义专门容器,执行主业务容器需要的辅助工作。
原本需要SSH进去执行的脚本
日志收集
Debug 应用
应用监控
优势:
将辅助功能同主业务容器解耦,实现独立发布和能力重用
(1)sidecar:应用于日志收集
业务容器将日志写在 Volume 里
日志容器共享该 Volume 从而将日志转发到远程存储当中
Fluentd等
(2)sidecar:代理容器
代理容器对业务容器屏敞被代理的服务集群,简化业务代码的实现逻辑
容器之间通过 localhost 直接通信
代理容器的代码可以被全公司重用
(3)适配器容器
适配器容器将业务容器暴露出来的接口转换为另一种格式。
四、应用编排与管理核心原理
1、kubernetes资源对象
Spec:期望的状态
Status:观测到的状态
Metadata
Labels:标识型的Key:Value元数据
Annotations (注解) 存储资源的非标识性信息
OwnerReference(所有者引用) “所有者”即集合类资源
五、应用编排与管理:Deployment
1、管理模式
deployment只负责管理不同版本的ReplicaSet,由ReplicaSet管理Pod副本数。
每个ReplicaSet对应了Deployment template的一个版本,一个ReplicaSet下的pod都是相同的版本。
deployment控制器
ReplicaSet控制器
六、应用编排与管理:Job和Daemon
我们可以通过Pod 来直接运行任务进程吗?
如果这样做,以下的问题有什么方式来解决?
1.如何保证Pod内进程正确的结束?
2.如果进程运行失败,如何重试?
3.如何管理多个任务且任务之间有互相依赖关系?
4.如何并行运行任务并管理他们的队列大小?
Job能帮助我们做什么事情?
1.创建一个或多个Pod确保指定数量的Pod可以成功地运行终止
2.跟踪Pod状态,根据配置及时重试失败的 Pod
3.确定依赖关系,保证上一个任务运行完毕后再运行下一个任务
4.控制任务并行度,并根据配置确保Pod 队列大小
1、管理模式
Job Controller 负责根据配置创建Pod
Job Controller 跟踪Job 状态,根据配置及时重试Pod或者继续创建
Job Controller 会自动添加label 来跟踪对应的pod,并根据配置并行或者串行创建 Pod
2、Job控制器
3、DaemonSet:守护进程控制器
DaemonSet 能帮助我们做什么事情?
保证集群内每一个(或者一些)节点都运行一组相同的Pod
跟踪集群节点状态,保证新加入的节点自动创建对应的Pod
跟踪集群节点状态,保证移除的节点删除对应的Pod
跟踪Pod状态,保证每个节点Pod 处于运行状态
适用场景
集群存储进程: glusterd, ceph
日志收集进程: fluentd,logstash
需要在每个节点运行的监控收集器
管理模式
1.DaemonSet Controller 负责根据配置创建Pod
2. DaemonSet Controller 跟踪Job 状态,根据配置及时重试Pod或者继续创建
3.DaemonSet Controller 会自动添加affinity&label来跟踪对应的pod,并根据配置在每个节点或者适合的部分节点创建 Pod
daemonSet控制器
七、应用配置管理
1、需求背景
除依托镜像来定义运行的Container,Pod还需要解决以下问题:
1.不可变基础设施(容器)的可变配置
可变配置不能放到景象中,配置变化,需要重新编一次镜像。
2.敏感信息的存储和使用(如: 密码,token等)
3.集群中Pod自我的身份认证
4.容器运行资源的配置管理
5.容器的运行安全管控
6.容器启动前置条件校验等
DNS是否正常,网络是否联通等
- Pod的配置管理
八、应用存储与持久化数据卷
1、K8S Volume类型:
本地存储:emptydir/hostpath
网络存储:
in-tree:实现的代码放在K8S代码仓库中
out-of-tree:代码实现与K8S解耦,主推
Projected Volume:配置信息以卷的形式挂载在容器中(secret、configmap等)
PVC与PV体系
2、Persistent Volumes(PV)
使用Pod Volumes无法准确表达数据volume复用/共享语义,新功能扩展很难实现。所以引入PV。
如果能将存储与计算分离,使用不同的组件(Controllers)管理存储与计算资源,解耦 Pod 与Volume的生命周期关联,可以很好的解决这些场景下的问题。
3、Persistent Volumes Claim(PVC)
有了PV,为什么又设计了PVC?(类似于面向对象,接口与实现的关系)
(1)职责分离,PVC中只用声明自己需要的存储size、access mode(单node独占还是多node共1享?只读还是读写访问?等业务真正关心的存储需求(不用关心存储实现细节),PV和其对应的后端存储信息则由交给cluster admin统一运维和管控,安全访问策略更容易控制。
(2)PVC简化了User对存储的需求,PV才是存储的实际信息的承载体,通过kube-controller-manager中的PersisentVolumeController将PVC与合适的PV bound到一起,从而满足User对存储的实际需求。
(3)PVC像是面向对象编程中抽象出来的接口,PV是接口对应的实现
动态分配存储空间(云盘为例)
StorageClass就是创建PV的模板,它包含了创建某种具体类型PV所需的参数信息,User无需关心这些PV 的细节。而 K8s 则会结合PVC和SC两者的信息动态创建PV对象。
Static Volume Provisioning(NAS为例)
- K8S对PV+PVC体系的完整处理流程
CSI - Container Storage Interface(容器存储接口) K8S对存储插件实现的推荐方式。分为两部分,csi-provisioner、csi-attacher是社区实现通用部分,csi-controller-server是云存储厂商实现,对接厂商云存储服务(create、delete、mount等)。
三个阶段:(1)create创建存储
(2)attached阶段 存储挂载到node
(3)mount阶段 将对应存储挂载到pod可以使用的路径
5、存储快照与拓扑调度
如何保证重要数据在误操作之后可以快速恢复,以提高数据操作容错率?
如何能够快速进行复制,迁移重要数据的动作?如进行环境复制与数据开发等。
存储快照接口——snapshot
与PV和PVC理念类似:
九、可观测性:应用健康
当迁移应用到Kubernetes后,要如何保障应用健康稳定?
提高应用的可观测性,提高应用的可恢复能力。
应用出现问题需降低影响范围,进行问题调试、诊断。
应用出现问题可以通过自愈机制恢复。
1、Liveness与Readiness
探测方式
httpGet 通过发送http GET请求返回200-399状态码则表明容器健康。
Exec 通过执行命令来检查服务是否正常,命令返回值为0则表示容器健康。
tcpSocket 通过容器的IP和Port执行TCP检查,如果能够建立TCP连接则表明容器健康
探测结果
Success Container通过了检查
Failure Container未通过检查
Unknown 未能执行检查,不采取任何动作
重启策略
Always 总是重启
OnFaliure 失败才重启
Never 永不重启
应用问题诊断的三个步骤
1.通过describe查看状态,通过状态判断排查方向
2.查看对象的event事件,获取更详细的信息。
3.查看Pod的日志确定应用自身的情况。
十、可观测性:监控与日志
在K8S中,监控和日志属于生态的一部分,并非核心组件。因此大部分能力依赖上层的云厂商适配。K8S定义了接入的接口标准和规范。
1、监控类型
资源监控
CPU、内存、网络等资源类的指标。常以数值、百分比为单位进行统计,是最常见的资源监控方式。
性能监控
(api的监控 )应用的内部监控,通常是通过Hook的机制在虚拟机层、字节码执行层隐式回调,或者在应用层显示注入,获取更深层次的监控指标,常用来应用诊断与调优。
安全监控
针对安全进行的一系列监控策略,如越权管理、安全漏洞扫描。
事件监控
K8S中一种另类的监控方式,紧密贴合K8S设计理念,补充常规监控方案的欠缺。
2、Prometheus——开源社区的监控“标准”
CNCF原生,许多开源项目使用。
简洁强大的接入标准
多种数据采集、离线方式
Kubernetes的兼容
丰富的插件机制与生态
Prometheus Operator的助力
左侧:数据采集方式(push、pull)。 右侧(上)告警的方式 (下)消费的方式。
2、日志的场景
主机内核的日志
主机内核的日志可以协助开发者诊断如:网络栈异常,驱动异常,文件系统异常,影响节点(内核)稳定的异常。
Runtime的日志
最常见的运行时是Docker,可通过Docker的日志排查例如删除pod Hang等问题。
核心组件的日志
APIServer日志可以用来审计,Scheduler日志可以诊断调度,etcd日志可以查看存储状态,Ingress日志可以分析接入层流量。
部署应用的日志
可通过应用日志分析查看业务层的状态,诊断异常。
3、日志采集
从采集位置上划分,需支持三种:
Fluented日志采集方案(社区推荐)
十一、K8S网络概念及策略控制
1、“约法三章+四大目标”
Kubernetes对于Pod 间的网络没有任何限制,只需满足如下[三个基本条件]
所有 Pod 可以与其他 Pod 直接通信,无需显式使用 NAT
所有Node可以与所有 Pod 直接通信,无需显式使用NAT
Pod 可见的IP 地址确为其他 Pod 与其通信时所用,无需显式转换
基于以上准入条件,我们在审视一个网络方案的时候,需要考虑如下[四大目标]
容器与容器间的通信
Pod 与 Pod 之间的通信
Pod 与 Service 间的通信
外部世界与 Service 间的通信
容器与其宿主存在寄生关系,从而在实现上,容器网络方案可分为 Underlay/Overlay 两大派别,其主要的差异在于是否与 Host 网络同层,这样对于微服务发现及治理、容器可访问方式都造成很大的差异。
Underlay 的标准是它与 Host 网络是同层的,从外在可见的一个特征就是它是不是使用了 Host 网络同样的网段(subnet)、输入输出基础设备、容器的 IP 地址是不是需要与 Host 网络取得协同(来自同一个中心分配或统一划分)。这就是 Underlay;
Overlay 不一样的地方就在于它并不需要从 Host 网络的 IPM 的管理的组件去申请 IP,一般来说,它只需要跟 Host 网络不冲突,这个 IP 可以自由分配的。 原贴
所以社区以 perPodperIP 这种简单武断的模型,弃了显示端口映射等NAT配置,统一了容器网络对外服务的视角。
2、Netns
Network namespace 是实现网络虚拟化的内核基础,创建了隔离的网络空间
拥有独立的附属网络设备(lo、veth 等虚设备/物理网卡)
独立的协议栈,IP 地址和路由表
iptables 规则
ipvs等
3、pod与Netns的关系
每个Pod 拥有独立的 Netns 空间,Pod 内的 Container 共享该空间,可通过 Loopback 接口实现通信,或通过共享的 Pod-IP 对外提供服务。别忘记,宿主上还有个 Root Netns,可以看做一个特殊的容器空间。
4、典型容器网络实现方案
容器网络可能是 Kubernetes 领域最为百花齐放的一个领域,依照laaS 层的配置、外部物理网络的设备、性能or 灵活优先,可以有不同的实现。
Flannel,最为普遍的实现,提供多种网络 backend 实现,覆盖多种场景
Calico,采用 BGP 提供网络直连,功能丰富,对底层网络有要求
Canal(Flannel for network + Calico for firewalling),嫁接型创新项目
Cilium,基于eBPF和XDP的高性能Overlay 网络方案
Kube-router,同样采用BGP 提供网络直连,集成基于 LVS 的负载均衡能力
Romana,采用 BGPor OSPF 提供网络直连能力的方案
WeaveNet,采用UDP 封装实现 L2 Overlay,支持用户态(慢,可加密)/内核态(快,不能加密)两种实现。
比较主要的方案:分别是 Flannel、Calico、Canal ,最后是 WeaveNet,中间的大多数方案都是采用了跟 Calico 类似的策略路由的方法。
Flannel 方案是目前使用最为普遍的。如上图所示,可以看到一个典型的容器网方案。它首先要解决的是 container 的包如何到达 Host,这里采用的是加一个 Bridge 的方式。它的 backend 其实是独立的,也就是说这个包如何离开 Host,是采用哪种封装方式,还是不需要封装,都是可选择的。
现在来介绍三种主要的 backend:
一种是用户态的 udp,这种是最早期的实现;
然后是内核的 Vxlan,这两种都算是 overlay 的方案。Vxlan 的性能会比较好一点,但是它对内核的版本是有要求的,需要内核支持 Vxlan 的特性功能;
如果你的集群规模不够大,又处于同一个二层域,也可以选择采用 host-gw 的方式。这种方式的 backend 基本上是由一段广播路由规则来启动的,性能比较高。
5、Network Policy 的用处
Kubernetes 网络的基本模型是需要 pod 之间全互联,这个将带来一些问题:可能在一个 K8s 集群里,有一些调用链之间是不会直接调用的。比如说两个部门之间,那么我希望 A 部门不要去探视到 B 部门的服务,这个时候就可以用到策略的概念。
基本上它的想法是这样的:它采用各种选择器(标签或 namespace),找到一组 pod,或者找到相当于通讯的两端,然后通过流的特征描述来决定它们之间是不是可以联通,可以理解为一个白名单的机制。
在使用 Network Policy 之前,如上图所示要注意 apiserver 需要打开一下这几个开关。另一个更重要的是我们选用的网络插件需要支持 Network Policy 的落地。大家要知道,Network Policy 只是 K8s 提供的一种对象,并没有内置组件做落地实施,需要取决于你选择的容器网络方案对这个标准的支持与否及完备程度,如果你选择 Flannel 之类,它并没有真正去落地这个 Policy,那么你试了这个也没有什么用。
6、总结
在 pod 的容器网络中核心概念就是 IP,IP 就是每个 pod 对外通讯的地址基础,必须内外一致,符合 K8s 的模型特征;
影响容器网络性能最关键的就是拓扑。要能够理解你的包端到端是怎么联通的,中间怎么从 container 到达 Host,Host 出了 container 是要封装还是解封装?还是通过策略路由?最终到达对端是怎么解出来的?
十二、K8S service
1、为什么需要服务发现
Kubernetes应用应如何相互调用?
Pod生命周期短暂,IP地址随时变化
Deployment等的Pod组需要统一访问入口和做负载均衡
应用间在不同环境部署时保持同样的部署拓扑和访问方式
service:K8S中的服务发现与负载均衡
(1)集群内访问Service
通过Service的虚拟IP
访问服务名,依靠DNS解析
通过环境变量访问
(2)向集群外暴露Service