微服务基础&理论
微服务特点
- 一组小的服务
- 独立的进程
- 轻量级通信
- 基于业务能力
微服务利弊
优势
- 强模块化边界:清晰的边界
- 可独立部署:无集中式管理,松耦合
- 技术多样性:可以用不同语言开发
- 故障容忍:错误隔离,自动重启
局限
- 不恰当的设计会增加系统的复杂程度
- 分布式复杂性
- 最终一致性:不同服务对相同数据进行操作时需要注意一致性
- 运维复杂性
- 测试复杂性
康威法则
设计系统的架构受制于产生这些设计的组织的沟通结构。
随着组织扩大,沟通成本越来越大,会降低开发效率,微服务的思路可以应对这种情况。
随着问题负责性增加,单块服务的效率下降更快,而微服务下降较慢,这是微服务的优势;
同时使用微服务有着额外开支(固定成本等);
所以对于小系统更适合单块服务,而高复杂性的系统适合微服务。
中台
服务分层,每一层向上提供支撑;
从低到高包括技术中台、业务中台、业务前台
技术中台包括运维层(IaaS:提供计算、存储、网络、监控等基础设施)和平台层(PaaS:服务框架、资源调度等;大数据/AI平台),运维层向平台层提供支撑。
微服务可以简单分为基础服务和聚合服务,其中基础服务是实现比较底层、公共、核心的功能,聚合服务则主要调用基础服务,向外提供适配服务。
服务治理
- 服务注册、发现
- 服务负载均衡、路由
- 日志
- 监控:调用量、延迟等
- 限流熔断
- 安全控制
- 统一异常处理
- 文档
服务发现
- 消费者通过域名向LB获取生产者服务,要穿透LB效率偏低,LB集中,危险性上升;
- LB集成到消费者中,效率有提升,但每个消费者都建立客户端代价提升;
- 每个主机用一个LB,折中方案。
API网关
对外屏蔽细节、将外部请求转化为具体微服务请求
限定流量
日志监控
微服务通信方式
RPC | REST | |
---|---|---|
耦合性 | 强耦合(服务端与客服端消息格式匹配) | 松耦合 |
消息协议 | 二进制:thrift、protobuf | 文本:xml、json |
通信协议 | TCP | HTTP/HTTP2 |
性能 | 高 | 相对差一些 |
借口契约IDL | thrift、protobuf等的IDL | swagger |
客户端 | 强类型客户端,一般自动生成,支持多语言 | 一般HTTP客户端 |
案例 | dubbo、thrft | spring MVC |
开发者友好 | 客户端使用方便,但二进制不便于调试 | 文本消息可读,浏览器调试 |
对外开放 | 对外转换成REST/文本协议 | 可以直接对外开放 |
微服务监控体系
- 用户体验监控:使用性能、地区等信息
- 业务监控:核心指标
- 应用层监控:URL、服务的可用率、响应时间
- 系统层监控:cpu、内存、硬盘等
- 基础设施监控:网络流量、丢包、错报、连接数
Docker
- 开源的应用容器引擎
- 依赖于已存在并运行的Linux内核环境。实质上是在已经运行的Linux下制造了一个隔离的文件环境,因此它执行的效率几乎等同于所部署的Linux主机。因此,Docker 必须部署在Linux内核的系统上。如果其他系统想部署 Docker 就必须安装一个虚拟Linux环境。
特点
- 解决环境依赖,完全使用沙箱机制,相互之间不会有任何接口
- 轻量、独立、可执行、包含运行应用所需的所有工具
- 带来开发环境的一致性
- 便于多版本混合部署
- 容器是进程,共享OS内核,与虚拟机有本质区别
- 位于容器引擎层,是基于IaaS基础设施层的
- 容器是『单进程』模型,只有PID=1的进程才会被Dockerd控制,即pid=1的进程挂了Dockerd能够感知到,但是其它的进程却不受Dockerd的管理,当出现孤儿进程的时候,管理和调度是个问题。
注意事项
- 仍然有较多开销,不适合把特别轻量的任务都做成微服务
- 更加适合immutable的服务
- 自身不稳定,需要配套的自动恢复功能
组成
- 镜像(Image):相当于是一个root文件系统。比如官方镜像 ubuntu:16.04就包含了完整的一套Ubuntu16.04最小系统的root文件系统。
- 容器(Container):
- 镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。
- 容器可以被创建、启动、暂停、停止、删除等。
- 容器的实质是进程,但有独立的命名空间。因此有自己的root文件系统、网络配置、进程空间,甚至自己的用户ID空间。容器内的进程是运行在一个隔离的环境里,就好像是在一个独立于宿主的系统下操作一样。
- 容器消亡时,容器存储层也随之消亡。因此,容器存储层的信息都会随容器删除而丢失。
- Registry:可以包含多个仓库(Repository)
- <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像
- 仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像,一个仓库会包含同一个软件不同版本的镜像。
- 每个仓库可以包含多个标签(Tag),每个标签对应一个镜像,如果不给出标签,将以latest作为默认标签。
- Docker使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。
- 客户端:通过命令行或者其他工具与Docker的守护进程通信。
- 主机(Host):物理或者虚拟的机器用于执行 Docker 守护进程和容器。
常用命令
- docker pull:拉取镜像
- docker run:运行容器
- it:在终端中交互运行
- d:后台运行
- docker pause/unpause:容器暂停/恢复运行
- docker stop:停止容器
- docker start/restart:启动stop的容器
- docker attach:进入容器,给正在运行的容器分配stdin、stdout 和 stderr,因此退出暂停
- docker exec:进入容器,相当于fork了一个进程,退出不暂停
- docker ps:查看正在运行的容器
- a:所有容器
- docker stats:查看运行容器的资源消耗量
- docker logs:查看容器内的输出
- docker export:导出容器为本地快照,如:docker export f23c03060d4e > ./test/test.tar
- docker import:导入快照为镜像,如:cat test/test.tar |docker import - test/test_image:v1.0
- docker rm:删除容器,docker container prune清理所有处于中止状态的容器
- docker images:本地镜像
- docker search:搜索镜像
- docker rmi:删除镜像
- docker commit:从容器生成新镜像
- docker history:查看镜像的分层
- docker inspect:查看镜像的详细信息
# 启动守护进程
service docker start
# 命令用法
docker pull [OPTIONS] NAME[:TAG|@DIGEST]
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
docker stop [OPTIONS] CONTAINER [CONTAINER...]
docker stats [OPTIONS] [CONTAINER...]
docker logs [OPTIONS] CONTAINER
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
docker history [OPTIONS] IMAGE
Dockerfile
- 构建镜像的文本文件,包含构建镜像所需的指令和说明。
- 首字母必须大写D
- 尽量将Dockerfile放在空目录中。
- 每个容器尽量只有一个功能。
- 执行的命令越少越好。
- FROM:定制的镜像都是基于FROM后面的基础镜像
- RUN:在制作容器即配置环境时8执行的命令,可将多个命令用&&连接、用\换行,以降低镜像层数。
- COPY:从上下文目录中复制文件或者目录到容器里指定路径。
- ADD:和COPY的使用格类似,区别在会对一些压缩文件自动解压
- CMD:类似于RUN指令,用于运行程序。
- CMD在docker run时运行,RUN是在docker build时运行。
- 作用为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。
- 如果Dockerfile中如果存在多个CMD指令,仅最后一个生效。
- CMD指令指定的程序可被docker run命令行参数中指定要运行的程序所覆盖。
- ENTRYPOINT:类似于CMD指令,但不会被docker run的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给ENTRYPOINT指令指定的程序。
- ENV:设置环境变量
- ARG:设置环境变量,作用域只有docker build的过程中
- VOLUME:定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
- WORKDIR:指定工作目录
- LABEL:给镜像添加元数据
- docker build:构建镜像
docker build [OPTIONS] PATH | URL | - # 如:docker build -t test/test_image:v3.0 . COPY [--chown=<user>:<group>] <源路径1>... <目标路径> ENV <key> <value>
基础镜像
- ubuntu、centos相对较大
- BusyBox是一个精简工具集合,非常小,1M多
- Alphine在BusyBox的基础上更加完善,同时保持瘦身,大约5M
隔离技术
- 容器是使用namespace进行隔离,cgroup进行资源限制,并且带有rootfs的进程。
- 启用Linux Namespace配置;
- 设置指定的Cgroups参数;
- 切换进程的根目录(Change Root)。
NameSpace
- Linux同属于一个namespace中进程可以感知到彼此,而对外界的进程一无所知。docker正是使用这个技术实现资源隔离。
- Linux提供了六种隔离:
- IPC:CLONE_NEWIPC,IPC(信号量、消息队列和共享内存等)隔离
- Network:CLONE_NEWNET,网络隔离(网络栈、端口等)
- Mount:CLONE_NEWNS,挂载点(文件系统)
- PID:CLONE_NEWPID,进程编号
- User:CLONE_NEWUSER,用户和用户组
- UTS:CLONE_NEWUTS,主机名和域名
- unshare:可以实现当前进程父进程的隔离
- setns:将进程加入到指定的namespace中
CGroups
- 限制一个进程组能够使用的资源上限,CPU,内存、磁盘、网络带宽等等。docker也是使用CGroups来控制容器的资源使用量。
- cgroup:系统进行限制的一组进程。CGroups中的资源限制都是以进程组为单位实现的,一个进程可以加入到某个进程组,从而受到相同的资源限制。
- task:在CGroups中,task可以理解为一个进程。
- hierarchy:可以理解成层级关系,CGroups的组织关系就是层级的形式,每个节点都是一个cgroup。cgroup可以有多个子节点,子节点默认继承父节点的属性。
- subsystem:更准确的表述应该是resource controllers,也就是资源控制器,cpu子系统负责控制cpu时间的分配。子系统必须应用(attach)到一个 hierarchy上才能起作用。包括:
- cpu:限制进程的cpu使用率;
- cpuacct:统计CGroups中的进程的cpu使用情况;
- cpuset:为CGroups中的进程分配单独的cpu节点或者内存节点;
- memory:限制进程的内存使用;
- devices:可以控制进程能够访问哪些设备;
- blkio:限制进程的块设备IO;
- freezer:挂起或者恢复CGroups中的进程;
- net_cls:标记进程的网络数据包,然后可以使用防火墙或者tc模块(traffic controller)控制该数据包。这个控制器只适用从该cgroup离开的网络包,不适用到达该cgroup的网络包;
- ns:将不同CGroups下面的进程应用不同的namespace;
- perf_event:监控CGroups中的进程的perf事件;
- pids:限制一个cgroup以及它的子节点中可以创建的进程数目;
- rdma:限制cgroup中可以使用的 RDMA 资源。
rootfs
- 通过chroot或pivot_root可以修改进程的根目录,这是文件系统隔离的基础
- 容器镜像rootfs,是包含操作系统所有文件和目录但不包含内核的文件系统
- rootfs是以层的方式增量叠放在一起
- rootfs由只读层、init层、可读写层组成
- 只读层:由若干层增量组成,组成的镜像。不可变,不commit
- 可读写层:存放容器运行后的改变,对只读层的删除操作是在可读写层做了一个whiteout遮盖。可变,commit
- init层:存放一些只在当前容器有效,且不需要commit的内容。可变,不commit
- 容器运行就是在只读层上面加一个可读写层
- 同一个镜像的多个容器底层共享
- 容器删除后,可读写层消失
- 容器commit就是把可读写层存为只读层
- AUFS、OverlayFS等联合挂载技术将各层的文件整合成一个文件系统
- Docker Volume在rootfs准备好之后,在执行chroot之前把宿主机目录挂载到容器目录,可以在保证隔离的情况下使得容器和宿主机之间可以进行文件操作。挂载目录仍然属于宿主机而不在容器的可读写层。
进程回收
- 当父进程没有对子进程进行回收时,Linux将子进程的父进程设为1号进程,并由1号进程进行回收
- 而容器的1号进程entry point并不具备管理多进程、多线程等复杂场景下的能力,因此容器更适合再单进程场景下使用。
- k8s可以给容器提供一个/pause进程来处理僵尸进程
kubernetes
- Kubernetes是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,方便进行声明式配置和自动化。
功能
- 容器集群管理、协调系统,位于容器编排层,基于容器引擎层,在Docker之上
- 编排存储:自动挂载存储系统,例如本地存储、公共云等
- 协助实现大规模云端部署
- 服务发现:对外提供统一入口
- 协调、提供计算资源
- 自动扩缩容
- 自动部署和回滚
- 对失败的容器自动重启
- 单例模式
组成结构
- 由管理节点master和工作节点node组成
- master:接受外部请求;调度
- API Server:统一访问入口,协调其它组件,RESTful API提供接口服务,所有对象资源的增删改查和监听操作都交给API Server处理后再提交给Etcd存储。
- Etcd:一致性、高可用性、分布式键值存储系统,用于保存集群状态数据,如pod、Service等对象信息
- scheduler:对容器运行、节点分布进行调度;根据调度算法为新创建的Pod选择一个Node
- controller-manager:管理各个资源的控制器,负责后台任务的运维、管理、升级、回滚。这些控制器包括:
- 节点控制器(Node Controller):负责在节点出现故障时进行通知和响应
- 任务控制器(Job Controller):监测代表一次性任务的 Job 对象,然后创建 Pods 来运行这些任务直至完成
- 端点控制器(Endpoints Controller):填充端点(Endpoints)对象(即加入 Service 与 Pod)
- 服务帐户和令牌控制器(Service Account & Token Controllers):为新的命名空间创建默认帐户和 API 访问令牌
- node:工作节点
- kubelet:master在每个节点的代理,管理节点的容器
- 通过CRI(Container Runtime Interface)的远程调用接口进行交互,接口定义了容器运行时的各项核心操作
- kube-proxy:负责pod网络代理,确保每个节点都获得其IP地址,实现本地iptables和规则以处理路由和流量负载均衡。
- 第三方容器引擎,如docker
- pod:最小管理单元,可以包含多个容器,类似于进程组
- kubelet:master在每个节点的代理,管理节点的容器
- 插件:实现集群功能
- DNS:为 Kubernetes 服务提供DNS记录
- Web界面(Dashboard):Kubernetes 集群的通用的、基于 Web 的用户界面。 它使用户可以管理集群中运行的应用程序以及集群本身, 并进行故障排除。
- 容器资源监控:将关于容器的一些常见的时间序列度量值保存到一个集中的数据库中, 并提供浏览这些数据的界面
- 集群层面日志:机制负责将容器的日志数据保存到一个集中的日志存储中, 这种集中日志存储提供搜索和浏览接口。
Kubernetes 对象
- Kubernetes对象是持久化的实体。用于表示整个集群的状态。
- 它们描述了如下信息:
- 哪些容器化应用正在运行(以及在哪些节点上运行)
- 可以被应用使用的资源
- 关于应用运行时表现的策略,比如重启策略、升级策略,以及容错策略
- spec:期望状态
- 必须在创建对象时设置其内容。
- 大多数情况下通过.yaml文件为kubectl提供这些信息
- 不同Kubernetes对象的spec是不同的,包含特定该对象的嵌套字段。
- status:当前实际状态
- 由Kubernetes系统和组件设置并更新的。Kubernetes会积极地管理当前实际状态,以使之达成期望状态。如:副本数量
- yaml文件中,需要配置的字段:
- apiVersion:创建该对象所使用的Kubernetes API的版本
- kind:指定要创建的 Kubernetes 对象的类型,例如 Pod、Service、Deployment 等。
- metadata:指定 Kubernetes 对象的元数据,包括对象的名称、命名空间、标签等信息。
- spec:期望的该对象的状态,包括对象的配置信息、参数等。
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: nginx:latest
- 上面的 YAML 文件定义了一个名为 “my-pod” 的 Pod 对象,它包含一个名为 “my-container” 的容器,该容器使用了 “nginx:latest” 镜像。
- 它们描述了如下信息:
- kubectl管理对象
- 指令式命令:作用于活跃对象,直接进行更改
# 通过创建 Deployment 对象来运行 nginx 容器的实例: kubectl create deployment nginx --image nginx
- 指令式对象配置:作用于单个文件
# 创建配置文件中定义的对象: kubectl create -f nginx.yaml # 删除两个配置文件中定义的对象: kubectl delete -f nginx.yaml -f redis.yaml # 通过覆盖活动配置来更新配置文件中定义的对象: kubectl replace -f nginx.yaml
- 指令式命令:作用于活跃对象,直接进行更改
- 每个对象都有name来标识同类资源中的唯一性,和UID来标识在整个集群中的唯一性
- 命名空间(namespace):同一集群中的资源划分为相互隔离的组。
- 适用于存在跨多个团队或项目的场景。小集群一般不需要
- namespace内资源的名称唯一,不同namespace之间可以不唯一
# 列出集群中现存的namespace kubectl get namespace
- 初始namespace:
- default:没有指明使用其它名字空间的对象所使用的默认名字空间
- kube-system:系统创建对象所使用的名字空间
- kube-public:所有用户都可以读取
- kube-node-lease 用于与各个节点相关的租约(Lease)对象。 节点租期允许kubelet发送心跳,由此控制面能够检测到节点故障。
- 创建一个服务时,会创建一个相应的DNS条目 <服务名称>.<名字空间名称>.svc.cluster.local,这意味着如果容器只使用 <服务名称>,它将被解析到本地名字空间的服务。这对于跨多个名字空间(如开发、分级和生产) 使用相同的配置非常有用。跨名字空间访问则需要使用完全限定域名(FQDN)。
- 标签:附加到对象上的键值对
以下是 Kubernetes 中最重要的几种对象:
- Pod:Kubernetes 中最小的可部署对象,通常包含一个或多个容器。Pod是部署和管理应用程序的最小单元。
- Service:用于暴露 Pod 中的应用程序。Service为应用程序提供了一个稳定的IP地址,从而使其他应用程序可以轻松地连接到它。
- ReplicaSet:一种控制器,用于确保在 Kubernetes中运行指定数量的Pod副本。如果Pod数量不足或超过指定数量,ReplicaSet将自动进行缩放。
- Deployment:用于在Kubernetes中部署应用程序。Deployment可以创建和更新 ReplicaSet,以确保在任何时候都可以运行指定数量的Pod副本。
- ConfigMap和Secret:ConfigMap和Secret是用于管理应用程序配置和敏感数据的对象。ConfigMap用于存储非敏感的配置数据,而Secret则用于存储敏感的数据,例如密码或API密钥。
除此之外,还有其他的对象类型,例如StatefulSet、Job和CronJob等,它们都用于在 Kubernetes中实现不同的应用程序管理和部署场景。
作业管理
- 每一个控制器,都以独有的方式负责某种编排功能,
- 控制器都遵循一个通用编排模式:控制循环(control loop);不断将实际状态调整为期望状态
- 控制器的设计原理就是用一种对象管理另一种对象;控制器的yaml定义中上半部分是控制器定义(包括期望状态),上下半部分是被控制对象(pod)的模板;让下面对象的状态达到上面的设定
Pod
尽管容器可以为应用程序提供独立的运行环境,但在某些情况下,它们可能不足以满足特定的需求。这时候,Pod可以为容器提供一个更完整的运行环境,从而使得多个容器可以协同工作。
- 为什么要从容器变为pod?
- 僵尸进程的问题使得容器只适合单进程模式
- 容器的作用是隔离环境,但是隔离得太死了,限制了单进程的发挥
- pod的作用是从容器中拆开一些口,保证容器间必要的交流
- 常见方式:通过让pod中的多个容器共享volume、网络等进行交流
- 常见字段:
- NodeSelector:标签选择器,以便将Pod调度到具有相应标签的节点上
- NodeName:经过了调度后被赋值为节点名
- HostAliases:定义了Pod的hosts文件(比如/etc/hosts)里的内容
- 投射数据卷(Projected Volume):为容器提供预先定义好的数据。
- Secret:把Pod想要访问的加密数据存放到Etcd中,然后通过在Pod的容器里挂载Volume访问
- ConfigMap:不需要加密的、应用所需的配置信息;
- Downward API:让Pod里的容器能够直接获取到这个Pod API对象(YAML文件)本身的信息;
- PodPreset:Kubernetes中的一种资源类型,用于在Pod创建时自动注入一些预设值。它可以通过注入环境变量、挂载卷、设置资源限制等方式,为Pod提供一些自定义的配置,以满足不同的应用场景需求。
Deployment
Deployment是一种控制器对象,它管理着一组Pod的创建、更新和删除。Deployment使用Pod模板来定义所创建的Pod的规范,通过控制器的方式保证这些Pod的副本数一直保持在指定的数量范围内。如果有Pod失败或需要更新,Deployment将会自动重启或升级Pod。
- 功能:
- 以滚动更新(rolling update)的方式实现升级pod,可以控制Pod的更新速度,使得更新过程中不会影响应用程序的可用性。
- 水平扩展/收缩
在创建Deployment时,需要指定一些重要的参数,包括要创建的Pod的镜像、Pod的副本数量、更新策略、Pod的标签等等。
- ReplicaSet:
- Deployment是高级控制器,定义应用程序的期望状态,控制ReplicaSet;ReplicaSet是低级控制器,确保Pod数量与期望状态一致,控制pod;Pod承载应用程序或服务
- 也可以认为,Pod实现程序功能,ReplicaSet加入副本控制,Deployment再加入滚动更新,每一次封装带来更高级更抽象的功能
- 水平扩展/收缩时只需要ReplicaSet改变replicas
- 滚动更新则会新建新的ReplicaSet,逐步实现两个ReplicaSet的此消彼长
- 旧ReplicaSet实现版本控制
Deployment主要应用于需要管理和维护的应用程序,尤其是那些需要不断迭代更新的业务。具体来说,Deployment适用于以下场景:
- Web应用程序:Web应用程序通常需要频繁地升级和扩展,以应对不断变化的用户需求和流量峰值。使用Deployment可以方便地管理Web应用程序的部署、升级和水平扩展,确保应用程序始终处于可用状态。
- 云原生应用程序:云原生应用程序通常由多个微服务组成,需要进行复杂的编排和管理。使用Deployment可以方便地管理微服务的部署和升级,确保微服务之间的兼容性和协调性。
- 大数据应用程序:大数据应用程序通常需要管理大量的容器和集群资源,以处理海量数据和实时查询。使用Deployment可以方便地管理大数据应用程序的部署和扩展,确保应用程序的高可用性和性能。
- 分布式系统:分布式系统通常需要管理多个节点和组件,以实现复杂的协同和通信。使用Deployment可以方便地管理分布式系统的部署和升级,确保各个节点和组件之间的一致性和稳定性。
总之,Deployment适用于各种需要管理和维护的应用程序,特别是那些需要频繁迭代更新和水平扩展的业务。通过使用Deployment,我们可以方便地管理应用程序的生命周期,并确保应用程序始终处于可用状态。
StatefulSet
Kubernetes中的StatefulSet是一种控制器,用于管理有状态的应用程序,例如数据库或消息队列。
与Deployment不同,StatefulSet的Pods具有固定的顺序和唯一的标识符。每个Pod都有一个稳定的网络标识符(即DNS名称),可以通过该标识符进行查找和访问。这使得对于有状态应用程序,如数据库,每个实例的数据持久性更加容易实现,确保了应用程序的稳定性和可靠性。
支持有状态应用:每个pod有了编号,不是完全一样,记录状态,然后在Pod被重新创建时,能够为新Pod恢复这些状态。
- 拓扑状态:pod按照一定顺序创建,且删掉后新创建的pod要与原来的pod有相同的网络标识
- 存储状态:不同实例可以使用不同的存储数据,PVC,PV
常见例子:
- 通过若干个有顺序的MySQL的pod来管理数据,实例的名称将分别为mysql-0、mysql-1、mysql-2、…
- 在Zookeeper集群中,每个节点都有唯一的ID和状态,节点之间需要进行数据同步和协调,因此需要保证每个节点的启动顺序和稳定性。
DaemonSet
Kubernetes的DaemonSet对象是一种用于管理集群节点上的守护进程的控制器对象。守护进程是一种在节点上运行的后台进程,可以执行一些系统级别的任务,例如监控、日志收集、安全检查等。
DaemonSet会在每个节点上自动创建一个Pod,确保该节点上运行指定的守护进程。当一个新节点加入集群时,它也会自动创建一个Pod。如果某个节点被删除或不可用,它上面的Pod也会被自动删除。
DaemonSet与其他控制器对象的不同之处在于,它的Pod是针对每个节点而不是每个副本集(ReplicaSet)来管理的。这使得它非常适合用于运行具有单节点依赖性的任务,如日志收集和监控。
在创建DaemonSet对象时,需要指定一个Pod模板,以及要运行的守护进程的镜像和其他配置参数。如果需要对所有节点运行的守护进程进行更改,则可以更新DaemonSet的Pod模板。这将导致所有Pod被重启并更新为新的配置。
总之,Kubernetes的DaemonSet对象提供了一种简单而可靠的方法来管理集群节点上的守护进程,从而实现更高效的集群管理。
特点:
- 这个Pod运行在Kubernetes集群里的每一个节点(Node)上;
- 每个节点上只有一个这样的Pod实例;
- 当有新的节点加入Kubernetes集群后,该Pod会自动地在新节点上被创建出来;而当旧节点被删除后,它上面的Pod也相应地会被回收掉。
- 常见应用:网络插件、存储插件、监控组件、日志组件
Job
Job对象是用于在集群中运行一次性任务的控制器,如批处理作业或数据处理任务。当一个Job对象创建时,它会创建一个或多个Pod来执行任务,并在任务完成后自动删除Pod。如果任务失败,Job将重新启动一个新的Pod以重新执行任务,直到任务成功或达到指定的重试次数。
- 常见字段:
- spec.parallelism:它定义的是一个Job在任意时间最多可以启动多少个Pod同时运行
- spec.completions:它定义的是Job至少要完成的Pod数目,即Job的最小完成数。
- spec.activeDeadlineSeconds:最长运行时间
- spec.backoffLimit:重试次数
CronJob
CronJob对象则是用于定期执行任务的控制器。与Job不同,CronJob会在指定的时间间隔内按照预定的计划运行任务,如每天、每周或每月。CronJob会创建一个Job对象来运行任务,并根据指定的计划进行管理和更新。
- 常用字段:
- spec.concurrencyPolicy:某个Job还没有执行完,是否创建新Job
Operator
Operator是Kubernetes对象的一种扩展,它利用Kubernetes API和自定义资源扩展了Kubernetes对象,以便自动化管理Kubernetes对象。
在Kubernetes中,对象是基本的API概念,它们用于表示Kubernetes集群中的状态和配置。例如,Pod、Service、Deployment等都是Kubernetes对象。Kubernetes对象具有一组预定义的字段,用于描述对象的状态和配置,以及一组API操作,用于管理对象的生命周期。通过使用Kubernetes API,可以创建、更新、扩展和删除Kubernetes对象。
Operator利用Kubernetes API和自定义资源,以自己的方式扩展了Kubernetes对象。自定义资源是一种自定义的Kubernetes对象,可以用来表示自定义的应用程序或服务。自定义资源由Operator定义和管理,并且可以包含自定义字段和自定义行为,以便满足应用程序的特定需求。控制器负责监视自定义资源的状态,并根据需要自动管理应用程序的生命周期。
因此,Operator和Kubernetes对象是密切相关的。Operator使用Kubernetes API和自定义资源扩展了Kubernetes对象,以便自动化管理应用程序的生命周期。Operator本身也是Kubernetes对象,可以由Kubernetes API创建、更新、扩展和删除,以及通过标准的Kubernetes对象授权和访问控制机制进行管理。通过利用Operator,可以更好地管理Kubernetes对象,提高应用程序的可靠性和可维护性。
作业调度
资源管理
- requests设置pod的资源最小量,在调度的时候发挥作用
- limits设置pod的资源最大值,设置Cgroups,在运行的时候限制上限
- 可压缩资源(CPU)不足limits时:根据requests按比例分配分配
- 不可压缩资源(内存)不足limits时:根据优先级驱逐
- 优先驱逐Request==Limit==0的Pod
- 其次驱逐0< Request < Limit < Infinity
- 0 < Request == Limit会保留
默认调度器
- 调度过程:
- 从所有的节点中,根据调度算法挑选出所有可以运行该Pod的节点;
- 多种算法并行过滤,不同node并行
- 再根据调度算法挑选一个最符合条件的节点作为最终结果。
- 从所有的节点中,根据调度算法挑选出所有可以运行该Pod的节点;
优先级与抢占
- pod可以设置优先级
- 高优先级的pod在调度队列中优先被调度
- 高优先级的pod调度失败后可以抢占低优先级的pod
网络
service
Kubernetes (k8s) 中的 Service 是一种抽象,用于定义一组 Pod 如何访问应用程序。Service 提供了一个虚拟的 IP 地址和一个 DNS 名称,用于与 Pod 进行通信,它可以帮助应用程序隐藏底层的 Pod 实现细节。Service 可以通过多种方式将请求路由到目标 Pod,例如:负载均衡、DNS 轮询和客户端 IP 等方式。
在 Kubernetes 集群中,Pod 的 IP 地址是动态分配的,这使得直接访问 Pod 有一定的不可靠性。Service 提供了一个固定的 IP 地址和一个 DNS 名称,它们将永久地与该 Service 关联。这使得应用程序可以通过 Service 访问一组 Pod,而不必关心 Pod 的实际 IP 地址。
- 主要解决pod动态变化,提供统一的访问入口,实现:
- 服务发现
- 负载均衡
- 通过标签labels来关联pod
- ClusterIP:分配一个稳定的集群内部IP,可以通过这个IP+设置的端口访问pod
- NodePort:在每个node上监听一个端口来访问服务。需要自己规划端口。
- LoadBalancer:在NodePort的基础上增加一个公网的负载均衡器,从统一的IP进行访问,由LoadBalancer转发到node
Ingress
- 基于service,对外提供域名访问和负载均衡
部署
服务器基本环境
# 关闭防火墙
system stop firewalld
system disable firewalld
# 关闭selinux(Linux的一个安全机制)
# 永久
sed -i 's/enforcing/disable/' /etc/selinux/config
# 临时
setenforce 0
# 关闭swap
# 永久
vim /etc/fatab # 注释交换分区的那一行
# 临时
swapoff -a
# 设置主机名
hostnamectl set-hostname <hostname>
# 在master添加host
cat >> /etc/hosts << EOF
ip1 name1
ip2 name2
ip3 name3
EOF
kubeadm
- 通过kubeadm init和kubeadm join快速部署k8s集群
- kubeadm init创建master节点
- kubeadm join <master节点的IP和端口> 将一个节点加入到当前集群
二进制
- 通过二进制包,手动部署每个组件,组成k8s集群