1.容器几个知识点

1.1 容器作用
  • 可以把应用程序代码及运行依赖环境打包成镜像,作为交付介质,在各环境部署。
  • 可以将镜像(image)启动成为容器(container),并且提供多容器的生命周期进行管理(启、停、删)。
  • container容器之间相互隔离,且每个容器可以设置资源限额。
  • 提供轻量级虚拟化功能,容器就是在宿主机中的一个个的虚拟的空间,彼此相互隔离,完全独立。
  • 三大核心要素:镜像(Image)、容器(Container)、仓库(Registry)。
  • 容器1号进程决定容器存活。
1.2 Docker指令
  • COPY|ADD 添加本地文件到镜像中,不同的是,如果是压缩包,ADD会解压,是链接,ADD会下载。
  • cp 可以从宿主机拷贝文件到容器,也可以从容器拷贝镜像到宿主机。
  • CMD 构建容器后调用,也就是在容器启动时才进行调用,CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。启动容器后执行的命令会覆盖CMD命令。
  • ENTRYPOINT 设置容器初始化命令,使其可执行化 ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。
  • ENV 设置环境变量。
1.3 UnionFS 联合文件系统
  • Linux namespace和cgroup分别解决了容器的资源隔离与资源限制。
  • 在最新的 Docker 中,overlay2 取代了 aufs 成为了推荐的存储驱动。
  • 镜像就是由这些层一层一层堆叠起来的,镜像中的这些层都是只读的,当我们运行容器的时候,就可以在这些基础层至上添加新的可写层,也就是我们通常说的容器层,对于运行中的容器所做的所有更改(比如写入新文件、修改现有文件、删除文件)都将写入这个容器层。
  • 对容器层的操作,主要利用了写时复制(COW)技术。CoW就是copy-on-write,表示只在需要写时才去复制,这个是针对已有文件的修改场景。COW技术可以让所有的容器共享image的文件系统,所有数据都从image中读取,只有当要对文件进行写操作时,才从image里把要写的文件复制到自己的文件系统进行修改。所以无论有多少个容器共享同一个image,所做的写操作都是对从image中复制到自己的文件系统中的复本上进行,并不会修改image的源文件,且多个容器操作同一个文件,会在每个容器的文件系统里生成一个复本,每个容器修改的都是自己的复本,相互隔离,相互不影响。使用CoW可以有效的提高磁盘的利用率。
1.4 Docker网络
  • Host模式,容器内部不会创建网络空间,共享宿主机的网络空间。容器启动后,会默认监听3306端口,由于网络模式是host,因为可以直接通过宿主机的3306端口进行访问服务,效果等同于在宿主机中直接启动mysqld的进程。
  • Conatiner模式,这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
  • none模式,使用–net=none指定 网络模式为空,即仅保留网络命名空间,但是不做任何网络相关的配置(网卡、IP、路由等)
  • bridge模式,使用–net=bridge指定,默认设置 bridge本意是桥的意思,其实就是网桥模式。我们可以把网桥看成一个二层的交换机设备,Docker 创建一个容器的时候,创建一对虚拟接口/网卡,也就是veth pair;本地主机一端桥接 到默认的 docker0 或指定网桥上,并具有一个唯一的名字,如 veth9953b75;容器一端放到新启动的容器内部,并修改名字作为 eth0,这个网卡/接口只在容器的命名空间可见;从网桥可用地址段中(也就是与该bridge对应的network)获取一个空闲地址分配给容器的 eth0

2.k8s核心组件

  • ETCD:分布式高性能键值数据库,存储整个集群的所有元数据
  • ApiServer: API服务器,集群资源访问控制入口,提供restAPI及安全访问控制
  • Scheduler:调度器,负责把业务容器调度到最合适的Node节点
  • Controller Manager:控制器管理,确保集群资源按照期望的方式运行
  • kubelet:运行在每个节点上的主要的“节点代理”,脏活累活
  • pod生命周期管理,创建销毁容器
  • 容器监控,监控所在节点的资源使用情况,并定时向 master报告,资源使用数据都是通过 cAdvisor 获取的
  • kube-proxy:维护节点中的iptables或者ipvs规则

3.K8S工作流程

  • 1.用户准备一个资源文件(记录了业务应用的名称、镜像地址等信息),通过调用APIServer执行创建Pod
  • 2.APIServer收到用户的Pod创建请求,将Pod信息写入到etcd中
  • 3.调度器通过list-watch的方式,发现有新的pod数据,但是这个pod还没有绑定到某一个节点中
  • 4.调度器通过调度算法,计算出最适合该pod运行的节点,并调用APIServer,把信息更新到etcd中
  • 5.kubelet同样通过list-watch方式,发现有新的pod调度到本机的节点了,因此调用容器运行时,去根据pod的描述信息,拉取镜像,启动容器,同时生成事件信息
  • 6.同时,把容器的信息、事件及状态也通过APIServer写入到etcd中

4.架构设计的几点思考

  • 1.系统各个组件分工明确(APIServer是所有请求入口,CM是控制中枢,Scheduler主管调度,而Kubelet负责运行),配合流畅,整个运行机制一气呵成。
  • 2.除了配置管理和持久化组件ETCD,其他组件并不保存数据。意味除ETCD外其他组件都是无状态的。因此从架构设计上对kubernetes系统高可用部署提供了支撑。
  • 3.同时因为组件无状态,组件的升级,重启,故障等并不影响集群最终状态,只要组件恢复后就可以从中断处继续运行。
  • 4.各个组件和kube-apiserver之间的数据推送都是通过list-watch机制来实现。

5.POD

5.1 pod是什么
  • pod是集群可以调度的最小单元
  • 一个pod可以包含一个或多个容器
5.2 健康检查
  • 存活性探测
  • 就绪性探测
5.3 三种类型
  • exec:通过执行命令来检查服务是否正常,返回值为0则表示容器健康
  • httpGet方式:通过发送http请求检查服务是否正常,返回200-399状态码则表明容器健康
  • tcpSocket:通过容器的IP和Port执行TCP检查,如果能够建立TCP连接,则表明容器健康
5.4 资源限制
  • requests: 容器使用的最小资源需求,作用于schedule阶段,作为容器调度时资源分配的判断依赖,只有当前节点上可分配的资源量 >= request 时才允许将容器调度到该节点,request参数不限制容器的最大可使用资源。
  • limits:容器能使用资源的最大值,设置为0表示对使用的资源不做限制, 可无限的使用,当pod 内存超过limit时,会被oom,当cpu超过limit时,不会被kill,但是会限制不超过limit值。
5.5 调度策略
  • cordon 标记节点为不调度
  • nodeName 调度到某一台定义的节点名字服务器
  • nodeSelector 调度到打了标签的节点服务器
  • Taints and Tolerations 污点与容忍,只有能够容忍污点的容器才能被调用
  • drain 维护模式,不允许调度并排关所有容器关闭kubelet
5.6 安全上下文

如:设置容器内进程root用户启动

5.7 pod数据持久化
  • hostpath
  • nfs
  • ceph
  • emptyDir
5.8 pod驱逐策略

Kube-controller-manager:周期性检查所有节点状态,当节点处于 NotReady 状态超过一段时间后,驱逐该节点上所有 pod。停掉kubelet
pod-eviction-timeout:NotReady 状态节点超过该时间后,执行驱逐,默认 5 min
Kubelet:周期性检查本节点资源,当资源不足时,按照优先级驱逐部分 pod

  • 节点可用内存
  • 根盘可用存储空间
  • 可用数量
  • 镜像存储盘的可用空间
  • 镜像存储盘的inodes可用数量
5.9 Pod控制器

Workload (工作负载),控制器又称工作负载是用于实现管理pod的中间层,确保pod资源符合预期的状态,pod的资源出现故障时,会尝试进行重启,当根据重启策略无效,则会重新新建pod的资源。

  • ReplicaSet: 代用户创建指定数量的pod副本数量,确保pod副本数量符合预期状态,并且支持滚动式自动扩容和缩容功能
  • Deployment:工作在ReplicaSet之上,用于管理无状态应用,目前来说最好的控制器。支持滚动更新和回滚功能,提供声明式配置
  • DaemonSet:用于确保集群中的每一个节点只运行特定的pod副本,通常用于实现系统级后台任务。比如EFK服务
  • Job:只要完成就立即退出,不需要重启或重建
  • Cronjob:周期性任务控制,不需要持续后台运行
  • StatefulSet:管理有状态应用

6.service

6.1 Kubernetes服务访问之Service

service是一组pod的服务抽象,相当于一组pod的LB,负责将请求分发给对应的pod。service会为这个LB提供一个IP,一般称为cluster IP 。使用Service对象,通过selector进行标签选择,找到对应的Pod。

6.2 Service负载均衡之NodePort

cluster-ip为虚拟地址,只能在k8s集群内部进行访问,集群外部如果访问内部服务,实现方式之一为使用NodePort方式。NodePort会默认在 30000-32767,不指定的会随机使用其中一个。

6.3 服务发现

在k8s集群中,组件之间可以通过定义的Service名称实现通信。

6.4 Service与Pod如何关联

service对象创建的同时,会创建同名的endpoints对象,若服务设置了readinessProbe, 当readinessProbe检测失败时,endpoints列表中会剔除掉对应的pod_ip,这样流量就不会分发到健康检测失败的Pod中。

7.kube-proxy几种模式

运行在每个节点上,监听 API Server 中服务对象的变化,再通过创建流量路由规则来实现网络的转发

7.1 User space

让 Kube-Proxy 在用户空间监听一个端口,所有的 Service 都转发到这个端口,然后 Kube-Proxy 在内部应用层对其进行转发,所有报文都走一遍用户态,性能不高,k8s v1.2版本后废弃。

7.2 Iptables

当前默认模式,完全由 IPtables 来实现, 通过各个node节点上的iptables规则来实现service的负载均衡,但是随着service数量的增大,iptables模式由于线性查找匹配、全量更新等特点,其性能会显著下降。

7.3 IPVS

与iptables同样基于Netfilter,但是采用的hash表,因此当service数量达到一定规模时,hash查表的速度优势就会显现出来,从而提高service的服务性能。k8s 1.8版本开始引入,1.11版本开始稳定,需要开启宿主机的ipvs模块。

8.Kubernetes服务访问之Ingress

对于Kubernetes的Service,无论是Cluster-Ip和NodePort均是四层的负载,集群内的服务如何实现七层的负载均衡,这就需要借助于Ingress,Ingress控制器的实现方式有很多,比如nginx, Contour, Haproxy, trafik, Istio。Ingress-nginx是7层的负载均衡器 ,负责统一管理外部对k8s cluster中Service的请求。
主要包含:

  • ingress-nginx-controller:根据用户编写的ingress规则(创建的ingress的yaml文件),动态的去更改nginx服务的配置文件,并且reload重载使其生效(是自动化的,通过lua脚本来实现);
  • Ingress资源对象:将Nginx的配置抽象成一个Ingress对象。
8.1 实现逻辑
  • 1.ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化
  • 2.然后读取ingress规则(规则就是写明了哪个域名对应哪个service),按照自定义的规则,生成一段nginx配置
  • 3.再写到nginx-ingress-controller的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器把生成的nginx配置写入/etc/nginx/nginx.conf文件中- - 4.然后reload一下使配置生效。以此达到域名分别配置和动态更新的问题。

9.configMap

通常用来管理应用的配置文件或者环境变量
Kubernetes认证与授权
APIServer安全控制
Authentication:身份认证
这个环节它面对的输入是整个http request,负责对来自client的请求进行身份校验,支持的方法包括:

  • basic auth
  • client证书验证(https双向验证)
  • jwt token(用于serviceaccount)

10.secret

  • rbac:基于角色认证,创建一个sa账户或user,配置基于角色的权限[get,list,watch,…],把账户与角色权限绑定,即可操作k8s的资源
  • 通过证书与apiserver进行通信
  • secret:管理敏感类的信息,默认会base64编码存储,有三种类型:
    1.generic:通用型secret,指定一个文件,文件内容指定用户名,密码
    2.docker registry:用来存储私有docker registry的认证信息。
    3.tls:把证书加载进secret
    4.Service Account:用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中;创建ServiceAccount后,Pod中指定serviceAccount后,自动创建该ServiceAccount对应的secret;
    5.Opaque:base64编码格式的Secret,用来存储密码、密钥等;

11.Kubernetes调度

Kubernetes Scheduler 的作用是将待调度的 Pod 按照一定的调度算法和策略绑定到集群中一个合适的 Worker Node 上,并将绑定信息写入到 etcd 中,之后目标 Node 中 kubelet 服务通过 API Server 监听到 Scheduler 产生的 Pod 绑定事件获取 Pod 信息,然后下载镜像启动容器。

11.1 调度的过程

Scheduler 提供的调度流程分为预选 (Predicates) 和优选 (Priorities) 两个步骤:

  • 预选,K8S会遍历当前集群中的所有 Node,筛选出其中符合要求的 Node 作为候选
  • 优选,K8S将对候选的 Node 进行打分
    经过预选筛选和优选打分之后,K8S选择分数最高的 Node 来运行 Pod,如果最终有多个 Node 的分数最高,那么 Scheduler 将从当中随机选择一个 Node 来运行 Pod。
11.2 Kubernetes集群的网络实现
  • CNI介绍及集群网络选型
    容器网络接口(Container Network Interface),实现kubernetes集群的Pod网络通信及管理。包括:
    1.CNI Plugin负责给容器配置网络,它包括两个基本的接口:配置网络: AddNetwork(net NetworkConfig, rt RuntimeConf) (types.Result, error)清理网络: DelNetwork(net NetworkConfig, rt RuntimeConf) error
    2.IPAM Plugin负责给容器分配IP地址,主要实现包括host-local和dhcp。
    以上两种插件的支持,使得k8s的网络可以支持各式各样的管理模式,当前在业界也出现了大量的支持方案,其中比较流行的比如flannel、calico等。

kubernetes配置了cni网络插件后,其容器网络创建流程为:

  • kubelet先创建pause容器生成对应的network namespace
  • 调用网络driver,因为配置的是CNI,所以会调用CNI相关代码,识别CNI的配置目录为/etc/cni/net.d
  • CNI driver根据配置调用具体的CNI插件,二进制调用,可执行文件目录为/opt/cni/bin,项目
  • CNI插件给pause容器配置正确的网络,pod中其他的容器都是用pause的网络
    可以在此查看社区中的CNI实现,https://github.com/containernetworking/cni
    通用类型:flannel、calico等,部署使用简单。
11.3Flannel三种模型
  • 1.host-gw模型
    host-gw模型即网关模式,在服务器直接添加一条静态路由即可,效率高,各节点必须在同一网段10.4.7.21通过172.7.22.0这条静态路由连接10.4.7.22这台主机再连接172.7.21网段,反之亦是。

  • 2.VxLAN模型
    在不同网段,可以用VxLAN模式,主机A会生成一个flannel.1网卡,通过封装头从flannel.1网卡出去通过flanne隧道传出,从flannel.1网卡传入拆包,到达目标主机网卡到指向的静态路由,效率低。

  • 3.Directrouting模型

  • 直接路由模式,结合了VxLAN和host-gw模型

  • 自动识别服务器,如果同网段,则使用host-gw模型,如果不同网段则使用VxLAN模型

  • 通过HPA实现业务应用的动态扩缩容

  • 基于CPU的动态伸缩

  • 基于内存的动态伸缩

  • 基于自定义指标的动态伸缩

####### 11.4 kubernetes对接分部式存储

  • PersistentVolume(持久化卷),是对底层的存储的一种抽象,它和具体的底层的共享存储技术的实现方式有关,比如 Ceph、GlusterFS、NFS等。
    因为PV是直接对接底层存储的,就像集群中的Node可以为Pod提供计算资源(CPU和内存)一样,PV可以为Pod提供存储资源。因此PV不是namespaced的资源,属于集群层面可用的资源。Pod如果想使用该PV,需要通过创建PVC挂载到Pod中。
  • PVC全写是PersistentVolumeClaim(持久化卷声明),PVC 是用户存储的一种声明,创建完成后,可以和PV实现一对一绑定。对于真正使用存储的用户不需要关心底层的存储实现细节,只需要直接使用 PVC 即可。
  • storageClass实现动态挂载
    创建pv及pvc过程是手动,且pv与pvc一一对应,手动创建很繁琐。因此,通过storageClass + provisioner的方式来实现通过PVC自动创建并绑定PV。
    动态pvc验证及实现分析
    使用流程: 创建pvc,指定storageclass和存储大小,即可实现动态存储。

12.EFK

12.1 Elasticsearch

Elasticsearch一个开源的分布式、Restful 风格的搜索和数据分析引擎,它的底层是开源库Apache Lucene。它可以被下面这样准确地形容:

  • 一个分布式的实时文档存储,每个字段可以被索引与搜索;
  • 一个分布式实时分析搜索引擎;
  • 能胜任上百个服务节点的扩展,并支持 PB 级别的结构化或者非结构化数据。
12.2 Kibana

Kibana是一个开源的分析和可视化平台,设计用于和Elasticsearch一起工作。可以通过Kibana来搜索,查看,并和存储在Elasticsearch索引中的数据进行交互。也可以轻松地执行高级数据分析,并且以各种图标、表格和地图的形式可视化数据。

12.3 Fluentd

Fluentd一个针对日志的收集、处理、转发系统。通过丰富的插件系统,可以收集来自于各种系统或应用的日志,转化为用户指定的格式后,转发到用户所指定的日志存储系统之中。
Fluentd 通过一组给定的数据源抓取日志数据,处理后(转换成结构化的数据格式)将它们转发给其他服务,比如 Elasticsearch、对象存储、kafka等等。Fluentd 支持超过300个日志存储和分析服务,所以在这方面是非常灵活的。
主要运行步骤如下:
首先 Fluentd 从多个日志源获取数据,结构化并且标记这些数据,然后根据匹配的标签将数据发送到多个目标服务。

为什么推荐使用fluentd作为k8s体系的日志收集工具?

  • 将日志文件JSON化
  • 可插拔架构设计极小的资源占用
  • 极强的可靠性
  • 基于内存和本地文件的缓存
  • 强大的故障转移
12.4 Prometheus监控

监控接口:xx.xx.xx.xx:xx/metrics
监控类型:静态监控、动态监控(自动发现)
自动发现资源类型:node、ingress、service、pod、endpoint
监控对象:

  • 基础监控:node_exporter CPU、内存、磁盘、IO
  • 集群状态:kube-state-metrics k8s集群中各种控制器资源状态
  • 容器存活:blackbox-exporter 检查容器存活(http、tcp)是否可用
  • 容器资源利用:cadvisor 容器消耗了服务器多少资源
  • 核心组件:etcd、kube-apiserver、kubelet、coredns

13.DevOps

devops = 提倡开发、测试、运维协同工作来实现持续开发、持续交付的一种软件交付模式 + 基于工具和技术支撑的自动化流程的落地实践。
因此devops不是某一个具体的技术,而是一种思想 + 自动化能力,来使得构建、测试、发布软件能够更加地便捷、频繁和可靠的落地实践。

posted on 2021-07-27 11:00  jiayou111  阅读(326)  评论(0编辑  收藏  举报