【重识云原生】第六章容器6.3.1节——K8S核心组件总述

2022-09-29 17:07:53 浏览数 (1)

 1 K8S核心组件分类

        一个kubernetes集群主要是由控制节点(master)、工作节点(node)构成,每个节点上都会安装不同的组件,依然先放上经典的K8S架构图:

1.1 Master

Master是集群的控制平面,负责集群的决策 ( 管理 ),由以下组件构成:

  • Api Server:资源操作的唯一入口,接收用户输入的命令,提供认证、授权、API注册和发现等机制,它是一个RestFul接口,用于接收外部资源请求,是整个集群的统一入口,请求信息交由etcd进行存储
  • Scheduler:资源调度器,负责集群资源调度,按照预定的调度策略将Pod调度到相应的node节点上
  • ControllerManager:控制管理器,负责维护集群的状态,比如程序部署安排、故障检测、自动扩展、滚动更新等,每个Node节点都会对应一个控制器对其进行管理
  • etcd:负责存储集群中各种资源对象的信息,用于保存集群相关数据

1.2 Node

Node是集群的数据平面,负责为容器提供运行环境 ( 干活 ),由以下组件构成:

  • Kubelet:由Master指派到Node节点中用于管理本机容器的代表,类似于agent, 负责维护容器的生命周期,即通过控制docker,来创建、更新、销毁容器
  • Kube Proxy:对该Node节点提供网络代理,负载均衡等操作
  • Docker:负责节点上容器的各种操作

2 组件简介

2.1 API Server

        API Server是所有服务访问的统一入口(所有请求的统一的入口),并提供认证、授权、访问控制、API 注册和发现等能力。API Server(kube-apiserver) API Server 提供 HTTP/HTTPS RESTful API,即 Kubernetes API。API Server 是 Kubernetes Cluster 的前端接口,各种客户端工具(CLI 或 UI)以及 Kubernetes 其他组件可以通过它管理 Cluster 的各种资源。

2.1.1 API Server的作用

API Server 提供了以下的功能:

  1. 整个集群管理的 API 接口:所有对集群进行的查询和管理都要通过 API 来进行。集群内部的组件(如kubelet)也是通过Apiserver更新和同步数据到etcd中。
  2. 集群内部各个模块之间通信的枢纽:所有模块之前并不会之间互相调用,而是通过和 API Server 打交道来完成自己那部分的工作。
  3. 集群安全控制:API Server 提供的验证和授权保证了整个集群的安全。
  4. 数据中心枢纽: API Server 负责和 Etcd 交互存放集群用到的运行数据。

2.1.2 工作原理

2.1.2.1 如何访问apiserver

        k8s通过kube-apiserver这个进程提供服务,该进程运行在单个k8s-master节点上。默认有两个端口。

1)本地端口

  1. 该端口用于接收HTTP请求;
  2. 该端口默认值为8080,可以通过API Server的启动参数“–insecure-port”的值来修改默认值;
  3. 默认的IP地址为“localhost”,可以通过启动参数“–insecure-bind-address”的值来修改该IP地址;
  4. 非认证或授权的HTTP请求通过该端口访问API Server。

2)安全端口

  1. 该端口默认值为6443,可通过启动参数“–secure-port”的值来修改默认值;
  2. 默认IP地址为非本地(Non-Localhost)网络端口,通过启动参数“–bind-address”设置该值;
  3. 该端口用于接收HTTPS请求;
  4. 用于基于Tocken文件或客户端证书及HTTP Base的认证;
  5. 用于基于策略的授权;
  6. 默认不启动HTTPS安全访问控制。

2.1.2.2 访问apiserver的方式

1)curl

curl localhost:8080/api

curl localhost:8080/api/v1/pods

curl localhost:8080/api/v1/services

curl localhost:8080/api/v1/replicationcontrollers

2)kubectl proxy

        Kubectl Proxy代理程序既能作为API Server的反向代理,也能作为普通客户端访问API Server的代理。通过master节点的8080端口来启动该代理程序。

3)kubectl客户端

        命令行工具kubectl客户端,通过命令行参数转换为对API Server的REST API调用,并将调用结果输出。

4)编程方式调用

2.1.2.3 通过apiserver访问node/pod/service

        k8s API Server最主要的REST接口是资源对象的增删改查。

        另外还有一类特殊的REST接口—k8s Proxy API接口,这类接口的作用是代理REST请求,即kubernetes API Server把收到的REST请求转发到某个Node上的kubelet守护进程的REST端口上,由该kubelet进程负责响应。

2.1.2.4 集群功能模块之间的通信

        kubernetes API Server作为集群的核心,负责集群各功能模块之间的通信,集群内各个功能模块通过API Server将信息存入etcd,当需要获取和操作这些数据时,通过API Server提供的REST接口(GETLISTWATCH方法)来实现,从而实现各模块之间的信息交互。

1)kubelet与apiserver交互

        每个Node节点上的kubelet定期就会调用API Server的REST接口报告自身状态,API Server接收这些信息后,将节点状态信息更新到etcd中。kubelet也通过API Server的Watch接口监听Pod信息,从而对Node机器上的POD进行管理。

 2)kube-controller-manager与apiserver交互

        kube-controller-manager中的Node Controller模块通过API Server提供的Watch接口,实时监控Node的信息,并做相应处理。

3)kube-scheduler与apiserver交互

        Scheduler通过API Server的Watch接口监听到新建Pod副本的信息后,它会检索所有符合该Pod要求的Node列表,开始执行Pod调度逻辑。调度成功后将Pod绑定到目标节点上。

2.1.2.5 apiserver参数介绍

        API Server 主要是和 etcd 打交道,并且对外提供 HTTP 服务,以及进行安全控制,因此它的命令行提供的参数也主要和这几个方面有关。下面是一些比较重要的参数以及说明(不同版本参数可能会有不同):

2.2 scheduler

2.2.1 scheduler简介

        scheduler是任务调度器,在K8S中实现组件名为kube-scheduler,负责任务调度、选择合适的节点来执行任务。Scheduler 负责决定将 Pod 放在哪个 Node 上运行。Scheduler 在调度时会充分考虑 Cluster 的拓扑结构,当前各个节点的负载,以及应用对高可用、性能、数据亲和性的需求。它监听 kube-apiserver,查询还未分配 Node 的 Pod,然后根据调度策略为这些 Pod 分配节点(更新 Pod 的 NodeName 字段)。

2.2.2 工作特性

2.2.2.1 调度器需要充分考虑诸多的因素:

        调度器需要充分考虑诸多的因素:

  • 公平调度
  • 资源高效利用
  • QoS
  • affinity 和 anti-affinity
  • 数据本地化(data locality)
  • 内部负载干扰(inter-workload interference)
  • deadlines

2.2.2.2 指定node节点调度

        有三种方式可以指定 Pod 只运行在指定的 Node 节点上:

  1. nodeSelector:只调度到匹配指定 label 的 Node 上
  2. nodeAffinity:功能更丰富的 Node 选择器,比如支持集合操作
  3. podAffinity:调度到满足条件的 Pod 所在的 Node 上

2.2.2.3 taints和tolerations

        Taints 和 tolerations 用于保证 Pod 不被调度到不合适的 Node 上,其中 Taint 应用于 Node 上,而 toleration 则应用于 Pod 上。目前支持的 taint 类型:

  1. NoSchedule:新的 Pod 不调度到该 Node 上,不影响正在运行的 Pod
  2. PreferNoSchedule:soft 版的 NoSchedule,尽量不调度到该 Node 上
  3. NoExecute:新的 Pod 不调度到该 Node 上,并且删除(evict)已在运行的 Pod。Pod 可以增加一个时间(tolerationSeconds)

        然而,当 Pod 的 Tolerations 匹配 Node 的所有 Taints 的时候可以调度到该 Node 上;当 Pod 是已经运行的时候,也不会被删除(evicted)。另外对于 NoExecute,如果 Pod 增加了一个 tolerationSeconds,则会在该时间之后才删除 Pod。

2.2.2.4 优先级调度

        从 v1.8 开始,kube-scheduler 支持定义 Pod 的优先级,从而保证高优先级的 Pod 优先调度。并从 v1.11 开始默认开启。

        注:在 v1.8-v1.10 版本中的开启方法为apiserver 配置 --feature-gates=PodPriority=true 和 --runtime-config=scheduling.k8s.io/v1alpha1=truekube-scheduler 配置 --feature-gates=PodPriority=true

2.2.2.5 多调度器

        如果默认的调度器不满足要求,还可以部署自定义的调度器。并且,在整个集群中还可以同时运行多个调度器实例,通过 podSpec.schedulerName 来选择使用哪一个调度器(默认使用内置的调度器)。

2.2.2.6 调度器扩展

        kube-scheduler 还支持使用 --policy-config-file 指定一个调度策略文件来自定义调度策略。

2.2.2.7 其他影响调度的因素

  • 如果 Node Condition 处于 MemoryPressure,则所有 BestEffort 的新 Pod(未指定 resources limits 和 requests)不会调度到该 Node 上
  • 如果 Node Condition 处于 DiskPressure,则所有新 Pod 都不会调度到该 Node 上
  • 为了保证 Critical Pods 的正常运行,当它们处于异常状态时会自动重新调度。Critical Pods 是指
    • annotation 包括 scheduler.alpha.kubernetes.io/critical-pod=''
    • tolerations 包括 [{"key":"CriticalAddonsOnly", "operator":"Exists"}]
    • priorityClass 为 system-cluster-critical 或者 system-node-critical

2.2.3 scheduler工作原理

        kube-scheduler 调度分为两个阶段,predicate 和 priority:

  • predicate:过滤不符合条件的节点
  • priority:优先级排序,选择优先级最高的节点

        predicates 策略:

  • PodFitsPorts:同 PodFitsHostPorts
  • PodFitsHostPorts:检查是否有 Host Ports 冲突
  • PodFitsResources:检查 Node 的资源是否充足,包括允许的 Pod 数量、CPU、内存、GPU 个数以及其他的 OpaqueIntResources
  • HostName:检查 

pod.Spec.NodeName 是否与候选节点一致:

  • MatchNodeSelector:检查候选节点的 

pod.Spec.NodeSelector 是否匹配:

  • NoVolumeZoneConflict:检查 volume zone 是否冲突
  • MaxEBSVolumeCount:检查 AWS EBS Volume 数量是否过多(默认不超过 39)
  • MaxGCEPDVolumeCount:检查 GCE PD Volume 数量是否过多(默认不超过 16)
  • MaxAzureDiskVolumeCount:检查 Azure Disk Volume 数量是否过多(默认不超过 16)
  • MatchInterPodAffinity:检查是否匹配 Pod 的亲和性要求
  • NoDiskConflict:检查是否存在 Volume 冲突,仅限于 GCE PD、AWS EBS、Ceph RBD 以及 ISCSI
  • GeneralPredicates:分为 noncriticalPredicates 和 EssentialPredicates。noncriticalPredicates 中包含 PodFitsResources,EssentialPredicates 中包含 PodFitsHost,PodFitsHostPorts 和 PodSelectorMatches。
  • PodToleratesNodeTaints:检查 Pod 是否容忍 Node Taints
  • CheckNodeMemoryPressure:检查 Pod 是否可以调度到 MemoryPressure 的节点上
  • CheckNodeDiskPressure:检查 Pod 是否可以调度到 DiskPressure 的节点上
  • NoVolumeNodeConflict:检查节点是否满足 Pod 所引用的 Volume 的条件

priorities 策略:

  • SelectorSpreadPriority:优先减少节点上属于同一个 Service 或 Replication Controller 的 Pod 数量
  • InterPodAffinityPriority:优先将 Pod 调度到相同的拓扑上(如同一个节点、Rack、Zone 等)
  • LeastRequestedPriority:优先调度到请求资源少的节点上
  • BalancedResourceAllocation:优先平衡各节点的资源使用
  • NodePreferAvoidPodsPriority:alpha.kubernetes.io/preferAvoidPods 字段判断, 权重为 10000,避免其他优先级策略的影响
  • NodeAffinityPriority:优先调度到匹配 NodeAffinity 的节点上
  • TaintTolerationPriority:优先调度到匹配 TaintToleration 的节点上
  • ServiceSpreadingPriority:尽量将同一个 service 的 Pod 分布到不同节点上,已经被 SelectorSpreadPriority 替代 [默认未使用]
  • EqualPriority:将所有节点的优先级设置为 1[默认未使用]
  • ImageLocalityPriority:尽量将使用大镜像的容器调度到已经下拉了该镜像的节点上 [默认未使用]
  • MostRequestedPriority:尽量调度到已经使用过的 Node 上,特别适用于 cluster-autoscaler[默认未使用]

        代码入口路径在release-1.9及之前的代码入口在plugin/cmd/kube-scheduler,从release-1.10起,kube-scheduler的核心代码迁移到pkg/scheduler目录下面,入口也迁移到cmd/kube-scheduler

2.2.4 启动 kube-scheduler 示例

代码语言:javascript复制
kube-scheduler --address=127.0.0.1 --leader-elect=true --kubeconfig=/etc/kubernetes/scheduler.conf

2.3 controller-manager

2.3.1 简介

        Controller Manager 由 kube-controller-manager 和 cloud-controller-manager 组成,是 Kubernetes 的大脑,它通过 apiserver 监控整个集群的状态,并确保集群处于预期的工作状态。

kube-controller-manager 由一系列的控制器组成:

  • Replication Controller
  • Node Controller
  • CronJob Controller
  • Daemon Controller
  • Deployment Controller
  • Endpoint Controller
  • Garbage Collector
  • Namespace Controller
  • Job Controller
  • Pod AutoScaler
  • RelicaSet
  • Service Controller
  • ServiceAccount Controller
  • StatefulSet Controller
  • Volume Controller
  • Resource quota Controller

        cloud-controller-manager 在 Kubernetes 启用 Cloud Provider 的时候才需要,用来配合云服务提供商的控制,也包括一系列的控制器,如

  • Node Controller
  • Route Controller
  • Service Controller

        从 v1.6 开始,cloud provider 已经经历了几次重大重构,以便在不修改 Kubernetes 核心代码的同时构建自定义的云服务商支持。参考 这里 查看如何为云提供商构建新的 Cloud Provider。

2.3.2 Metrics

        Controller manager metrics 提供了控制器内部逻辑的性能度量,如 Go 语言运行时度量、etcd 请求延时、云服务商 API 请求延时、云存储请求延时等。

        Controller manager metrics 默认监听在 kube-controller-manager 的 10252 端口,提供 Prometheus 格式的性能度量数据,可以通过 http://localhost:10252/metrics 来访问。

代码语言:javascript复制
$ curl http://localhost:10252/metrics 
... 
# HELP etcd_request_cache_add_latencies_summary Latency in microseconds of adding an object to etcd cache 
# TYPE etcd_request_cache_add_latencies_summary summary 
etcd_request_cache_add_latencies_summary{quantile="0.5"} NaN 
etcd_request_cache_add_latencies_summary{quantile="0.9"} NaN 
etcd_request_cache_add_latencies_summary{quantile="0.99"} NaN 
etcd_request_cache_add_latencies_summary_sum 0 
etcd_request_cache_add_latencies_summary_count 0 # HELP 
etcd_request_cache_get_latencies_summary Latency in microseconds of getting an object from 
etcd cache 
# TYPE etcd_request_cache_get_latencies_summary summary 
etcd_request_cache_get_latencies_summary{quantile="0.5"} NaN 
etcd_request_cache_get_latencies_summary{quantile="0.9"} NaN 
etcd_request_cache_get_latencies_summary{quantile="0.99"} NaN 
etcd_request_cache_get_latencies_summary_sum 0 
etcd_request_cache_get_latencies_summary_count 0 
...

2.3.3 kube-controller-manager 启动示例

代码语言:javascript复制
kube-controller-manager 
 --enable-dynamic-provisioning=true 
 --feature-gates=AllAlpha=true 
 --horizontal-pod-autoscaler-sync-period=10s 
 --horizontal-pod-autoscaler-use-rest-clients=true 
 --node-monitor-grace-period=10s 
 --address=127.0.0.1 
 --leader-elect=true 
 --kubeconfig=/etc/kubernetes/controller-manager.conf 
 --cluster-signing-key-file=/etc/kubernetes/pki/ca.key 
 --use-service-account-credentials=true 
 --controllers=*,bootstrapsigner,tokencleaner 
 --root-ca-file=/etc/kubernetes/pki/ca.crt 
 --service-account-private-key-file=/etc/kubernetes/pki/sa.key 
 --cluster-signing-cert-file=/etc/kubernetes/pki/ca.crt 
 --allocate-node-cidrs=true 
 --cluster-cidr=10.244.0.0/16 
 --node-cidr-mask-size=24

2.3.4 kube-controller-manager控制器分类

        kube-controller-manager 由一系列的控制器组成,这些控制器可以划分为三组:

1)必须启动的控制器:18个

  • EndpointController
  • ReplicationController
  • PodGCController
  • ResourceQuotaController
  • NamespaceController
  • ServiceAccountController
  • GarbageCollectorController
  • DaemonSetController
  • JobController
  • DeploymentController
  • ReplicaSetController
  • HPAController
  • DisruptionController
  • StatefulSetController
  • CronJobController
  • CSRSigningController
  • CSRApprovingController
  • TTLController

2)默认启动可选的控制器,可以通过选项设置是否开启

  • TokenController
  • NodeController
  • ServiceController
  • RouteController
  • PVBinderController
  • AttachDetachController

3)默认禁止的可选控制器,可通过选项设置是否开启

  • BootstrapSignerController
  • TokenCleanerController
  • cloud-controller-manager 在 Kubernetes 启用 Cloud Provider 的时候才需要,用来配合云服务提供商的控制,也包括一系列的控制器,如
  • Node Controller
  • Route Controller
  • Service Controller

2.3.5 cloud-controller-manager控制器分类

        cloud-controller-manager 在 Kubernetes 启用 Cloud Provider 的时候才需要,用来配合云服务提供商的控制,也包括一系列的控制器:

  • CloudNodeController
  • RouteController
  • ServiceController

2.3.6 高可用

        在启动时设置 --leader-elect=true 后,controller manager 会使用多节点选主的方式选择主节点。只有主节点才会调用 StartControllers() 启动所有控制器,而其他从节点则仅执行选主算法。

        多节点选主的实现方法见 leaderelection.go。它实现了两种资源锁(Endpoint 或 ConfigMap,kube-controller-manager 和 cloud-controller-manager 都使用 Endpoint 锁),通过更新资源的 Annotation(control-plane.alpha.kubernetes.io/leader),来确定主从关系。

2.3.7 高性能

        从 Kubernetes 1.7 开始,所有需要监控资源变化情况的调用均推荐使用 Informer。Informer 提供了基于事件通知的只读缓存机制,可以注册资源变化的回调函数,并可以极大减少 API 的调用。

        Informer 的使用方法可以参考 这里。

2.3.8 node驱逐

        Node 控制器在节点异常后,会按照默认的速率(–node-eviction-rate=0.1,即每10秒一个节点的速率)进行 Node 的驱逐。Node 控制器按照 Zone 将节点划分为不同的组,再跟进 Zone 的状态进行速率调整:

  1. Normal:所有节点都 Ready,默认速率驱逐。
  2. PartialDisruption:即超过33% 的节点 NotReady 的状态。当异常节点比例大于 --unhealthy-zone-threshold=0.55 时开始减慢速率:
    1. 小集群(即节点数量小于 --large-cluster-size-threshold=50):停止驱逐
    2. 大集群,减慢速率为 --secondary-node-eviction-rate=0.01
  3. FullDisruption:所有节点都 NotReady,返回使用默认速率驱逐。但当所有 Zone 都处在 FullDisruption 时,停止驱逐。

2.4 etcd

        etcd 是 CoreOS 基于 Raft 开发的分布式 key-value 存储,可用于服务发现、共享配置以及一致性保障(如数据库选主、分布式锁等)。etcd官方将其定位为一个可信赖的分布式键值存储服务, 它能够为整个分布式集群存储一些关键数据, 协助分布式集群的正常运转。

2.4.1 etcd 主要功能

  • 基本的 key-value 存储
  • 监听机制
  • key 的过期及续约机制,用于监控和服务发现
  • 原子 CAS 和 CAD,用于分布式锁和 leader 选举

2.4.2 etcd版本说明

         etcd现在有两个版本, v2和v3版本, v2版本将数据保存到内存, v3版本将数据保存到数据库. 正常我们都选择使用v3版本, 但Kubernetes v1.11版本之前使用的是v2版本.

2.4.3 etcd内部架构图

  • http Server: 这里采用的是使用http进行构建的c/s服务, k8s也是采用的http协议进行c/s服务的开发. 为什么要这么做呢? 因为http天生支持一系列的操作. 例如: get ,post, put, delete, 授权认证等. 所以, 没有必要再去采用标准的tcp协议. 开发一系列的认证流程, 所以, 直接采用http协议即可.
  • Raft:共识算法,或者叫最终一致算法。比如:有3台etcd机器在运行的过程中,突然停了,那么3台etcd中的配置可能是不一样的,但是,一旦运行起来,经过一段时间,最终会达到一致。每一个Raft集群都包含多个服务器,在任意时刻,每一台服务器只可能处于Leader(主节点)、Follower(跟随者)、Candidater(竞选者)三种状态中的一种。在处于正常状态(可访问)时,集群中只会存在一个Leader,其余的服务器都是Follower。是读写的信息, 所有的读写信息都被存在Raft里面, 而且, 为了防止这些信息出现损坏, 他还有一个WAL预写日志
  • WAL: 预写日志, 吸入到数据库之前,先保存到日志里。如果要对数据进行更改, 那么先写入一条日志, 然后定时的对日志进行完整的备份. 也就是完整 临时. 比如: 我先备份一个大版本, 备份以后, 还会有1个子版本, 两个子版本....., 然后将这些版本再次进行一个完整备份,把它变成一个大版本. 这样做的好处, 我们不能始终进行完整备份, 因为消耗的数据量太大. 为什么还要在一定时间内进行完整的备份呢?防止增量备份太多, 还原的时候太费事. 并且, Raft还会实时的把这些数据和日志存入到本地磁盘进行持久化.
  • Store: 试试把WAL中的日志和数据, 写入磁盘进行持久化.

2.5 kubectl

        kubectl 是 Kubernetes 的命令行工具(CLI),是 Kubernetes 用户和管理员必备的管理工具。

        kubectl 提供了大量的子命令,方便管理 Kubernetes 集群中的各种功能。这里不再罗列各种子命令的格式,而是介绍下如何查询命令的帮助:

  • kubectl -h 查看子命令列表
  • kubectl options 查看全局选项
  • kubectl --help 查看子命令的帮助
  • kubectl [command] [PARAMS] -o= 设置输出格式(如 json、yaml、jsonpath 等)
  • kubectl explain [RESOURCE] 查看资源的定义

2.5.1 配置

        使用 kubectl 的第一步是配置 Kubernetes 集群以及认证方式,包括:

  • cluster 信息:Kubernetes server 地址
  • 用户信息:用户名、密码或密钥
  • Context:cluster、用户信息以及 Namespace 的组合

2.5.2 常用命令格式

  • 创建:

kubectl run --image= 或者 

kubectl create -f manifest.yaml

  • 查询:

kubectl get

  • 更新 

kubectl set 或者 

kubectl patch

  • 删除:

kubectl delete  或者 

kubectl delete -f manifest.yaml

  • 查询 Pod IP:

kubectl get pod -o jsonpath='{.status.podIP}'

  • 容器内执行命令:

kubectl exec -ti sh

  • 容器日志:

kubectl logs [-f]

  • 导出服务:

kubectl expose deploy --port=80

  • Base64 解码:

kubectl get secret SECRET -o go-template='{{ .data.KEY | base64decode }}'

        注意,kubectl run 仅支持 Pod、Replication Controller、Deployment、Job 和 CronJob 等几种资源。具体的资源类型是由参数决定的,默认为 Deployment:

创建的资源类型

参数

Pod

--restart=Never

Replication Controller

--generator=run/v1

Deployment

--restart=Always

Job

--restart=OnFailure

CronJob

--schedule=

2.5.3 kubectl 插件

        kubectl 插件提供了一种扩展 kubectl 的机制,比如添加新的子命令。插件可以以任何语言编写,只需要满足以下条件即可:

  • 插件放在 ~/.kube/plugins 或环境变量 KUBECTL_PLUGINS_PATH 指定的目录中
  • 插件的格式为 子目录 / 可执行文件或脚本 且子目录中要包括 plugin.yaml 配置文件

你也可以使用 krew 来管理 kubectl 插件。

2.5.4 原始 URI

        kubectl 也可以用来直接访问原始 URI,比如要访问 Metrics API 可以:

  • kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes
  • kubectl get --raw /apis/metrics.k8s.io/v1beta1/pods
  • kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes/
  • kubectl get --raw /apis/metrics.k8s.io/v1beta1/namespace//pods/

2.5.5 kubectl安装方法

        kubectl 的安装方法:

代码语言:javascript复制
# OS X 
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl 
# Linux 
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl 
# Windows 
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/windows/amd64/kubectl.exe

2.6 kubelet

        每个Node节点上都运行一个 Kubelet 服务进程,默认监听 10250 端口,接收并执行 Master 发来的指令,管理 Pod 及 Pod 中的容器。每个 Kubelet 进程会在 API Server 上注册所在Node节点的信息,定期向 Master 节点汇报该节点的资源使用情况,并通过 cAdvisor 监控节点和容器的资源。

2.6.1 节点管理

        节点管理主要是节点自注册和节点状态更新:

  • Kubelet 可以通过设置启动参数 --register-node 来确定是否向 API Server 注册自己;
  • 如果 Kubelet 没有选择自注册模式,则需要用户自己配置 Node 资源信息,同时需要告知 Kubelet 集群上的 API Server 的位置;
  • Kubelet 在启动时通过 API Server 注册节点信息,并定时向 API Server 发送节点新消息,API Server 在接收到新消息后,将信息写入 etcd

2.6.2 Pod 管理

2.6.2.1 获取 Pod 清单

        Kubelet 以 PodSpec 的方式工作。PodSpec 是描述一个 Pod 的 YAML 或 JSON 对象。 kubelet 采用一组通过各种机制提供的 PodSpecs(主要通过 apiserver),并确保这些 PodSpecs 中描述的 Pod 正常健康运行。

        向 Kubelet 提供节点上需要运行的 Pod 清单的方法:

  • 文件:启动参数 --config 指定的配置目录下的文件 (默认 / etc/kubernetes/manifests/)。该文件每 20 秒重新检查一次(可配置)。
  • HTTP endpoint (URL):启动参数 --manifest-url 设置。每 20 秒检查一次这个端点(可配置)。
  • API Server:通过 API Server 监听 etcd 目录,同步 Pod 清单。
  • HTTP server:kubelet 侦听 HTTP 请求,并响应简单的 API 以提交新的 Pod 清单。

2.6.2.2 通过 API Server 获取 Pod 清单及创建 Pod 的过程

        Kubelet 通过 API Server Client(Kubelet 启动时创建)使用 Watch 加 List 的方式监听 "/registry/nodes/$ 当前节点名" 和 “/registry/pods” 目录,将获取的信息同步到本地缓存中。

        Kubelet 监听 etcd,所有针对 Pod 的操作都将会被 Kubelet 监听到。如果发现有新的绑定到本节点的 Pod,则按照 Pod 清单的要求创建该 Pod。

        如果发现本地的 Pod 被修改,则 Kubelet 会做出相应的修改,比如删除 Pod 中某个容器时,则通过 Docker Client 删除该容器。 如果发现删除本节点的 Pod,则删除相应的 Pod,并通过 Docker Client 删除 Pod 中的容器。

        Kubelet 读取监听到的信息,如果是创建和修改 Pod 任务,则执行如下处理:

  • 为该 Pod 创建一个数据目录;
  • 从 API Server 读取该 Pod 清单;
  • 为该 Pod 挂载外部卷;
  • 下载 Pod 用到的 Secret;
  • 检查已经在节点上运行的 Pod,如果该 Pod 没有容器或 Pause 容器没有启动,则先停止 Pod 里所有容器的进程。如果在 Pod 中有需要删除的容器,则删除这些容器;
  • 用 “kubernetes/pause” 镜像为每个 Pod 创建一个容器。Pause 容器用于接管 Pod 中所有其他容器的网络。每创建一个新的 Pod,Kubelet 都会先创建一个 Pause 容器,然后创建其他容器。
  • 为 Pod 中的每个容器做如下处理:
    1. 为容器计算一个 hash 值,然后用容器的名字去 Docker 查询对应容器的 hash 值。若查找到容器,且两者 hash 值不同,则停止 Docker 中容器的进程,并停止与之关联的 Pause 容器的进程;若两者相同,则不做任何处理;
    2. 如果容器被终止了,且容器没有指定的 restartPolicy,则不做任何处理;
    3. 调用 Docker Client 下载容器镜像,调用 Docker Client 运行容器。

2.6.2.3 Static Pod

        所有以非 API Server 方式创建的 Pod 都叫 Static Pod。Kubelet 将 Static Pod 的状态汇报给 API Server,API Server 为该 Static Pod 创建一个 Mirror Pod 和其相匹配。Mirror Pod 的状态将真实反映 Static Pod 的状态。当 Static Pod 被删除时,与之相对应的 Mirror Pod 也会被删除。

2.6.3 容器健康检查

        Pod 通过两类探针检查容器的健康状态:

  • (1) LivenessProbe 探针:用于判断容器是否健康,告诉 Kubelet 一个容器什么时候处于不健康的状态。如果 LivenessProbe 探针探测到容器不健康,则 Kubelet 将删除该容器,并根据容器的重启策略做相应的处理。如果一个容器不包含 LivenessProbe 探针,那么 Kubelet 认为该容器的 LivenessProbe 探针返回的值永远是 “Success”;
  • (2)ReadinessProbe:用于判断容器是否启动完成且准备接收请求。如果 ReadinessProbe 探针探测到失败,则 Pod 的状态将被修改。Endpoint Controller 将从 Service 的 Endpoint 中删除包含该容器所在 Pod 的 IP 地址的 Endpoint 条目。

        Kubelet 定期调用容器中的 LivenessProbe 探针来诊断容器的健康状况。LivenessProbe 包含如下三种实现方式:

  • ExecAction:在容器内部执行一个命令,如果该命令的退出状态码为 0,则表明容器健康;
  • TCPSocketAction:通过容器的 IP 地址和端口号执行 TCP 检查,如果端口能被访问,则表明容器健康;
  • HTTPGetAction:通过容器的 IP 地址和端口号及路径调用 HTTP GET 方法,如果响应的状态码大于等于 200 且小于 400,则认为容器状态健康。

        LivenessProbe 和 ReadinessProbe 探针包含在 Pod 定义的 spec.containers.{某个容器} 中。

2.6.4 cAdvisor 资源监控

        Kubernetes 集群中,应用程序的执行情况可以在不同的级别上监测到,这些级别包括:容器、Pod、Service 和整个集群。Heapster 项目为 Kubernetes 提供了一个基本的监控平台,它是集群级别的监控和事件数据集成器 (Aggregator)。Heapster 以 Pod 的方式运行在集群中,Heapster 通过 Kubelet 发现所有运行在集群中的节点,并查看来自这些节点的资源使用情况。Kubelet 通过 cAdvisor 获取其所在节点及容器的数据。Heapster 通过带着关联标签的 Pod 分组这些信息,这些数据将被推到一个可配置的后端,用于存储和可视化展示。支持的后端包括 InfluxDB(使用 Grafana 实现可视化) 和 Google Cloud Monitoring。

        cAdvisor 是一个开源的分析容器资源使用率和性能特性的代理工具,集成到 Kubelet中,当Kubelet启动时会同时启动cAdvisor,且一个cAdvisor只监控一个Node节点的信息。cAdvisor 自动查找所有在其所在节点上的容器,自动采集 CPU、内存、文件系统和网络使用的统计信息。cAdvisor 通过它所在节点机的 Root 容器,采集并分析该节点机的全面使用情况。

        cAdvisor 通过其所在节点机的 4194 端口暴露一个简单的 UI。

2.6.5 Kubelet Eviction(驱逐)

        Kubelet 会监控资源的使用情况,并使用驱逐机制防止计算和存储资源耗尽。在驱逐时,Kubelet 将 Pod 的所有容器停止,并将 PodPhase 设置为 Failed。

        Kubelet 定期(housekeeping-interval)检查系统的资源是否达到了预先配置的驱逐阈值,包括

Eviction Signal

Condition

Description

memory.available

MemoryPressue

memory.available:=node.status.capacity[memory] -node.stats.memory.workingSet (计算方法参考这里)

nodefs.available

DiskPressure

nodefs.available:=node.stats.fs.available (Kubelet Volume以及日志等)

nodefs.inodesFree

DiskPressure

nodefs.inodesFree:=node.stats.fs.inodesFree

imagefs.available

DiskPressure

imagefs.available:=node.stats.runtime.imagefs.available (镜像以及容器可写层等)

imagefs.inodesFree

DiskPressure

imagefs.inodesFree:=node.stats.runtime.imagefs.inodesFree

        这些驱逐阈值可以使用百分比,也可以使用绝对值,如:

代码语言:javascript复制
--eviction-hard=memory.available<500Mi,nodefs.available<1Gi,imagefs.available<100Gi 
--eviction-minimum-reclaim="memory.available=0Mi,nodefs.available=500Mi,imagefs.available=2Gi"` 
--system-reserved=memory=1.5Gi

        这些驱逐信号可以分为软驱逐和硬驱逐:

  • 软驱逐(Soft Eviction):配合驱逐宽限期(eviction-soft-grace-period和eviction-max-pod-grace-period)一起使用。系统资源达到软驱逐阈值并在超过宽限期之后才会执行驱逐动作。
  • 硬驱逐(Hard Eviction ):系统资源达到硬驱逐阈值时立即执行驱逐动作。

        驱逐动作包括回收节点资源和驱逐用户 Pod 两种:

  • 回收节点资源
    • 配置了 imagefs 阈值时
      • 达到 nodefs 阈值:删除已停止的 Pod
      • 达到 imagefs 阈值:删除未使用的镜像
    • 未配置 imagefs 阈值时
      • 达到 nodefs阈值时,按照删除已停止的 Pod 和删除未使用镜像的顺序清理资源
  • 驱逐用户 Pod
    • 驱逐顺序为:BestEffort、Burstable、Guaranteed
    • 配置了 imagefs 阈值时
      • 达到 nodefs 阈值,基于 nodefs 用量驱逐(local volume logs)
      • 达到 imagefs 阈值,基于 imagefs 用量驱逐(容器可写层)
    • 未配置 imagefs 阈值时
      • 达到 nodefs阈值时,按照总磁盘使用驱逐(local volume logs 容器可写层)

        除了驱逐之外,Kubelet 还支持一系列的容器和镜像垃圾回收选项,它们未来将会被驱逐替代:

垃圾回收参数

驱逐参数

解释

--image-gc-high-threshold

--eviction-hard 或 --eviction-soft

现存的驱逐回收信号可以触发镜像垃圾回收

--image-gc-low-threshold

--eviction-minimum-reclaim

驱逐回收实现相同行为

--minimum-image-ttl-duration

由于驱逐不包括TTL配置,所以它还会继续支持

--maximum-dead-containers

一旦旧日志存储在容器上下文之外,就会被弃用

--maximum-dead-containers-per-container

一旦旧日志存储在容器上下文之外,就会被弃用

--minimum-container-ttl-duration

一旦旧日志存储在容器上下文之外,就会被弃用

--low-diskspace-threshold-mb

--eviction-hard or eviction-soft

驱逐回收将磁盘阈值泛化到其他资源

--outofdisk-transition-frequency

--eviction-pressure-transition-period

驱逐回收将磁盘压力转换到其他资源

2.6.6 容器运行时

        容器运行时(Container Runtime)是 Kubernetes 最重要的组件之一,负责真正管理镜像和容器的生命周期。Kubelet 通过 容器运行时接口(Container Runtime Interface,CRI) 与容器运行时交互,以管理镜像和容器。

        Container Runtime Interface(CRI)是 Kubernetes v1.5 引入的容器运行时接口,它将 Kubelet 与容器运行时解耦,将原来完全面向 Pod 级别的内部接口拆分成面向 Sandbox 和 Container 的 gRPC 接口,并将镜像管理和容器管理分离到不同的服务。

        CRI 最早从从 1.4 版就开始设计讨论和开发,在 v1.5 中发布第一个测试版。在 v1.6 时已经有了很多外部容器运行时,如 frakti 和 cri-o 等。v1.7 中又新增了 cri-containerd 支持用 Containerd 来管理容器。

        CRI 基于 gRPC 定义了 RuntimeService 和 ImageService 等两个 gRPC 服务,分别用于容器运行时和镜像的管理。其定义在

  • v1.14 以以上:https://github.com/kubernetes/cri-api/tree/master/pkg/apis/runtime
  • v1.10-v1.13: pkg/kubelet/apis/cri/runtime/v1alpha2
  • v1.7-v1.9: pkg/kubelet/apis/cri/v1alpha1/runtime
  • v1.6: pkg/kubelet/api/v1alpha1/runtime

        Kubelet 作为 CRI 的客户端,而容器运行时则需要实现 CRI 的服务端(即 gRPC server,通常称为 CRI shim)。容器运行时在启动 gRPC server 时需要监听在本地的 Unix Socket (Windows 使用 tcp 格式)。

        目前基于 CRI 容器引擎已经比较丰富了,包括:

  • Docker: 核心代码依然保留在 kubelet 内部(pkg/kubelet/dockershim),是最稳定和特性支持最好的运行时
  • OCI(Open Container Initiative,开放容器标准)容器运行时:
    • 社区有两个实现
      • Containerd,支持 kubernetes v1.7
      • CRI-O,支持 Kubernetes v1.6
    • 支持的 OCI 容器引擎包括
      • runc:OCI 标准容器引擎
      • gVisor:谷歌开源的基于用户空间内核的沙箱容器引擎
      • Clear Containers:Intel 开源的基于虚拟化的容器引擎
      • Kata Containers:基于虚拟化的容器引擎,由 Clear Containers 和 runV 合并而来
  • PouchContainer:阿里巴巴开源的胖容器引擎
  • Frakti:支持 Kubernetes v1.6 ,提供基于 hypervisor 和 docker 的混合运行时,适用于运行非可信应用,如多租户和 NFV 等场景
  • Rktlet:支持 rkt 容器引擎
  • Virtlet:Mirantis 开源的虚拟机容器引擎,直接管理 libvirt 虚拟机,镜像须是 qcow2 格式
  • Infranetes:直接管理 IaaS 平台虚拟机,如 GCE、AWS 等

2.6.7 启动 kubelet 示例

代码语言:javascript复制
/usr/bin/kubelet 
 --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf 
 --kubeconfig=/etc/kubernetes/kubelet.conf 
 --pod-manifest-path=/etc/kubernetes/manifests 
 --allow-privileged=true 
 --network-plugin=cni 
 --cni-conf-dir=/etc/cni/net.d 
 --cni-bin-dir=/opt/cni/bin 
 --cluster-dns=10.96.0.10 
 --cluster-domain=cluster.local 
 --authorization-mode=Webhook 
 --client-ca-file=/etc/kubernetes/pki/ca.crt 
 --cadvisor-port=0 
 --rotate-certificates=true 
 --cert-dir=/var/lib/kubelet/pki

2.6.8 kubelet 工作原理

2.6.8.1 kubelet 内部组件结构

        如下 kubelet 内部组件结构图所示,Kubelet 由许多内部组件构成:

  • Kubelet API,包括 10250 端口的认证 API、4194 端口的 cAdvisor API、10255 端口的只读 API 以及 10248 端口的健康检查 API
  • syncLoop:从 API 或者 manifest 目录接收 Pod 更新,发送到 podWorkers 处理,大量使用 channel 处理来处理异步请求
  • 辅助的 manager,如 cAdvisor、PLEG、Volume Manager 等,处理 syncLoop 以外的其他工作
  • CRI:容器执行引擎接口,负责与 container runtime shim 通信
  • 容器执行引擎,如 dockershim、rkt 等(注:rkt 暂未完成 CRI 的迁移)
  • 网络插件,目前支持 CNI 和 kubenet

2.6.9 查询 Node 汇总指标

        通过 Kubelet 的 10255 端口可以查询 Node 的汇总指标。有两种访问方式:

  • 在集群内部可以直接访问 kubelet 的 10255 端口,比如 http://:10255/stats/summary
  • 在集群外部可以借助 

        kubectl proxy 来访问,比如:

代码语言:javascript复制
kubectl proxy& 
curl http://localhost:8001/api/v1/proxy/nodes/<node-name>:10255/stats/summary

2.7 kube proxy

2.7.1 kube-proxy 服务功能简述

        每台机器上都运行一个 kube-proxy 服务,它监听 API server 中 service 和 endpoint 的变化情况,并通过 iptables 等来为服务配置负载均衡(仅支持 TCP 和 UDP)。kube-proxy 可以直接运行在物理机上,也可以以 static pod 或者 daemonset 的方式运行。

        kube-proxy 当前支持以下几种实现:

  • userspace:最早的负载均衡方案,它在用户空间监听一个端口,所有服务通过 iptables 转发到这个端口,然后在其内部负载均衡到实际的 Pod。该方式最主要的问题是效率低,有明显的性能瓶颈。
  • iptables:目前推荐的方案,完全以 iptables 规则的方式来实现 service 负载均衡。该方式最主要的问题是在服务多的时候产生太多的 iptables 规则,非增量式更新会引入一定的时延,大规模情况下有明显的性能问题
  • ipvs:为解决 iptables 模式的性能问题,v1.11 新增了 ipvs 模式(v1.8 开始支持测试版,并在 v1.11 GA),采用增量式更新,并可以保证 service 更新期间连接保持不断开
  • winuserspace:同 userspace,但仅工作在 windows 节点上

        注意:使用 ipvs 模式时,需要预先在每台 Node 上加载内核模块 nf_conntrack_ipv4, ip_vs, ip_vs_rr, ip_vs_wrr, ip_vs_sh 等。

代码语言:javascript复制
# load module <module_name> 
modprobe -- ip_vs 
modprobe -- ip_vs_rr 
modprobe -- ip_vs_wrr 
modprobe -- ip_vs_sh 
modprobe -- nf_conntrack_ipv4 

# to check loaded modules, use 
lsmod | grep -e ip_vs -e nf_conntrack_ipv4 
# or 
cut -f1 -d " " /proc/modules | grep -e ip_vs -e nf_conntrack_ipv4

2.7.2 启动 kube-proxy 示例

代码语言:javascript复制
kube-proxy --kubeconfig=/var/lib/kubelet/kubeconfig --cluster-cidr=10.240.0.0/12 --feature-gates=ExperimentalCriticalPodAnnotation=true --proxy-mode=iptables

2.7.3 kube-proxy 工作原理

        kube-proxy 监听 API server 中 service 和 endpoint 的变化情况,并通过 userspace、iptables、ipvs 或 winuserspace 等 proxier 来为服务配置负载均衡(仅支持 TCP 和 UDP)。

2.7.4 kube-proxy 不足

        kube-proxy 目前仅支持 TCP 和 UDP,不支持 HTTP 路由,并且也没有健康检查机制。这些可以通过自定义 Ingress Controller 的方法来解决。

2.8 kubeadm

        kubeadm 是 Kubernetes 主推的部署工具之一,正在快速迭代开发中。

2.8.1 初始化系统

        所有机器都需要初始化容器执行引擎(如 docker 或 frakti 等)和 kubelet。这是因为 kubeadm 依赖 kubelet 来启动 Master 组件,比如 kube-apiserver、kube-manager-controller、kube-scheduler、kube-proxy 等。

2.8.1.1 安装 master

        在初始化 master 时,只需要执行 kubeadm init 命令即可,比如:

代码语言:javascript复制
kubeadm init --pod-network-cidr 10.244.0.0/16 --kubernetes-version stable

这个命令会自动:

  • 系统状态检查
  • 生成 token
  • 生成自签名 CA 和 client 端证书
  • 生成 kubeconfig 用于 kubelet 连接 API server
  • 为 Master 组件生成 Static Pod manifests,并放到 /etc/kubernetes/manifests 目录中
  • 配置 RBAC 并设置 Master node 只运行控制平面组件
  • 创建附加服务,比如 kube-proxy 和 kube-dns

2.8.1.2 配置 Network plugin

        kubeadm 在初始化时并不关心网络插件,默认情况下,kubelet 配置使用 CNI 插件,这样就需要用户来额外初始化网络插件。

2.8.1.2.1 CNI bridge

代码语言:javascript复制
mkdir -p /etc/cni/net.d 
cat >/etc/cni/net.d/10-mynet.conf <<-EOF 
{
  "cniVersion": "0.3.0",
  "name": "mynet",
  "type": "bridge",
  "bridge": "cni0",
  "isGateway": true,
  "ipMasq": true,
  "ipam": {
     "type": "host-local",
     "subnet": "10.244.1.0/24", 
     "routes": [
         {"dst": "0.0.0.0/0"} 
      ] 
   } 
} 
EOF 
cat >/etc/cni/net.d/99-loopback.conf <<-EOF 
{
  "cniVersion": "0.3.0",
  "type": "loopback" 
} 
EOF
  • flannel
代码语言:javascript复制
kubectl create -f https://github.com/coreos/flannel/raw/master/Documentation/kube-flannel-rbac.yml 
kubectl create -f https://github.com/coreos/flannel/raw/master/Documentation/kube-flannel.yml
  • weave
代码语言:javascript复制
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d'n')"
  • calico
代码语言:javascript复制
kubectl apply -f https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml 
kubectl apply -f https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml

2.8.2 添加 Node

代码语言:javascript复制
token=$(kubeadm token list | grep authentication,signing | awk '{print $1}') 
kubeadm join --token $token ${master_ip}

        这包括以下几个步骤:

  • 从 API server 下载 CA
  • 创建本地证书,并请求 API Server 签名
  • 最后配置 kubelet 连接到 API Server

2.8.3 删除安装

代码语言:javascript复制
kubeadm reset

2.9 其他重要插件

2.9.1 Web UI

        Dashboard是 Kubernetes 集群的通用的、基于 Web 的用户界面。 它使用户可以管理集群中运行的应用程序以及集群本身并进行故障排除。

2.9.2 DNS

        DNS 是 Kubernetes 的核心功能之一,通过 kube-dns 或 CoreDNS 作为集群的必备扩展来提供命名服务。

2.9.2.1 kube-dns

2.9.2.1.1 启动 kube-dns 示例

        一般通过扩展的方式部署 DNS 服务,如把 kube-dns.yaml 放到 Master 节点的 /etc/kubernetes/addons 目录中。当然也可以手动部署:

代码语言:javascript复制
kubectl apply -f https://github.com/feiskyer/kubernetes-handbook/raw/master/manifests/kubedns/kube-dns.yaml

        这会在 Kubernetes 中启动一个包含三个容器的 Pod,运行着 DNS 相关的三个服务:

代码语言:javascript复制
# kube-dns container 
kube-dns --domain=cluster.local. --dns-port=10053 --config-dir=/kube-dns-config --v=2 

# dnsmasq container 
dnsmasq-nanny -v=2 -logtostderr -configDir=/etc/k8s/dns/dnsmasq-nanny -restartDnsmasq=true -- -k --cache-size=1000 --log-facility=- --server=127.0.0.1#10053 

# sidecar container 
sidecar --v=2 --logtostderr --probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.cluster.local.,5,A --probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.cluster.local.,5,A

        Kubernetes v1.10 也支持 Beta 版的 CoreDNS,其性能较 kube-dns 更好。可以以扩展方式部署,如把 coredns.yaml 放到 Master 节点的 /etc/kubernetes/addons 目录中。当然也可以手动部署:

代码语言:javascript复制
kubectl apply -f https://github.com/feiskyer/kubernetes-handbook/raw/master/manifests/kubedns/coredns.yaml

2.9.2.1.2 kube-dns 工作原理

        如下图所示,kube-dns 由三个容器构成:

  • kube-dns:DNS 服务的核心组件,主要由 KubeDNS 和 SkyDNS 组成
    • KubeDNS 负责监听 Service 和 Endpoint 的变化情况,并将相关的信息更新到 SkyDNS 中
    • SkyDNS 负责 DNS 解析,监听在 10053 端口 (tcp/udp),同时也监听在 10055 端口提供 metrics
    • kube-dns 还监听了 8081 端口,以供健康检查使用
  • dnsmasq-nanny:负责启动 dnsmasq,并在配置发生变化时重启 dnsmasq
    • dnsmasq 的 upstream 为 SkyDNS,即集群内部的 DNS 解析由 SkyDNS 负责
  • sidecar:负责健康检查和提供 DNS metrics(监听在 10054 端口)

 2.9.2.1.3 源码简介

        kube-dns 的代码已经从 kubernetes 里面分离出来,放到了 https://github.com/kubernetes/dns。

        kube-dns、dnsmasq-nanny 和 sidecar 的代码均是从 cmd//main.go 开始,并分别调用 pkg/dns、pkg/dnsmasq 和 pkg/sidecar 完成相应的功能。而最核心的 DNS 解析则是直接引用了 github.com/skynetservices/skydns/server 的代码,具体实现见 skynetservices/skydns。

2.9.3 CoreDNS

        从 v1.11 开始可以使用 CoreDNS 来提供命名服务,并从 v1.13 开始成为默认 DNS 服务。CoreDNS 的特点是效率更高,资源占用率更小,推荐使用 CoreDNS 替代 kube-dns 为集群提供 DNS 服务。

        从 kube-dns 升级为 CoreDNS 的步骤为:

代码语言:javascript复制
$ git clone https://github.com/coredns/deployment 
$ cd deployment/kubernetes 
$ ./deploy.sh | kubectl apply -f - 
$ kubectl delete --namespace=kube-system deployment kube-dns

        全新部署的话,可以点击这里 查看 CoreDNS 扩展的配置方法。

2.9.3.1 支持的 DNS 格式

  • Service
    • A record:生成 my-svc.my-namespace.svc.cluster.local,解析 IP 分为两种情况
      • 普通 Service 解析为 Cluster IP
      • Headless Service 解析为指定的 Pod IP 列表
    • SRV record:生成 _my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster.local
  • Pod
    • A record:pod-ip-address.my-namespace.pod.cluster.local
    • 指定 hostname 和 subdomain:hostname.custom-subdomain.default.svc.cluster.local,如下所示
代码语言:javascript复制
apiVersion: v1 
kind: Pod 
metadata: 
  name: busybox2 
  labels: 
    name: busybox 
spec: 
  hostname: busybox-2 
  subdomain: default-subdomain 
  containers: 
    - image: busybox 
      command: 
        - sleep 
        - "3600" 
      name: busybox

 2.9.3.2 支持配置私有 DNS 服务器和上游 DNS 服务器

        从 Kubernetes 1.6 开始,可以通过为 kube-dns 提供 ConfigMap 来实现对存根域以及上游名称服务器的自定义指定。例如,下面的配置插入了一个单独的私有根 DNS 服务器和两个上游 DNS 服务器。

代码语言:javascript复制
apiVersion: v1 
kind: ConfigMap 
metadata: 
  name: kube-dns 
  namespace: kube-system 
data: 
  stubDomains: | {“acme.local”: [“1.2.3.4”]} 
  upstreamNameservers: | [“8.8.8.8”, “8.8.4.4”]

        使用上述特定配置,查询请求首先会被发送到 kube-dns 的 DNS 缓存层 (Dnsmasq 服务器)。Dnsmasq 服务器会先检查请求的后缀,带有集群后缀(例如:”.cluster.local”)的请求会被发往 kube-dns,拥有存根域后缀的名称(例如:”.acme.local”)将会被发送到配置的私有 DNS 服务器 [“1.2.3.4”]。最后,不满足任何这些后缀的请求将会被发送到上游 DNS [“8.8.8.8”, “8.8.4.4”] 里。

 2.9.3 Ingress

        官方只为我们实现了四层代理,Ingress可以实现七层代理,也就是可以根据组件名和域名进行负载均衡。Ingress 就是为进入集群的请求提供路由规则的集合,如下图所示:

         Ingress 可以给 service 提供集群外部访问的 URL、负载均衡、SSL 终止、HTTP 路由等。为了配置这些 Ingress 规则,集群管理员需要部署一个 Ingress controller,它监听 Ingress 和 service 的变化,并根据规则配置负载均衡并提供访问入口。

        Ingress 正常工作需要集群中运行 Ingress Controller。Ingress Controller 与其他作为 kube-controller-manager 中的在集群创建时自动启动的 controller 成员不同,需要用户选择最适合自己集群的 Ingress Controller,或者自己实现一个。

        Ingress Controller 以 Kubernetes Pod 的方式部署,以 daemon 方式运行,保持 watch Apiserver 的 /ingress 接口以更新 Ingress 资源,以满足 Ingress 的请求。比如可以使用 Nginx Ingress Controller:

代码语言:javascript复制
helm install stable/nginx-ingress --name nginx-ingress --set rbac.create=true

        其他 Ingress Controller 还有:

  • traefik ingress 提供了一个 Traefik Ingress Controller 的实践案例
  • kubernetes/ingress-nginx 提供了一个详细的 Nginx Ingress Controller 示例
  • kubernetes/ingress-gce 提供了一个用于 GCE 的 Ingress Controller 示例

2.9.4 Federation

        在云计算环境中,服务的作用距离范围从近到远一般可以有:同主机(Host,Node)、跨主机同可用区(Available Zone)、跨可用区同地区(Region)、跨地区同服务商(Cloud Service Provider)、跨云平台。K8s 的设计定位是单一集群在同一个地域内,因为同一个地区的网络性能才能满足 K8s 的调度和计算存储连接要求。而集群联邦(Federation)就是为提供跨 Region 跨服务商 K8s 集群服务而设计的。

        每个 Federation 有自己的分布式存储、API Server 和 Controller Manager。用户可以通过 Federation 的 API Server 注册该 Federation 的成员 K8s Cluster。当用户通过 Federation 的 API Server 创建、更改 API 对象时,Federation API Server 会在自己所有注册的子 K8s Cluster 都创建一份对应的 API 对象。在提供业务请求服务时,K8s Federation 会先在自己的各个子 Cluster 之间做负载均衡,而对于发送到某个具体 K8s Cluster 的业务请求,会依照这个 K8s Cluster 独立提供服务时一样的调度模式去做 K8s Cluster 内部的负载均衡。而 Cluster 之间的负载均衡是通过域名服务的负载均衡来实现的。

         所有的设计都尽量不影响 K8s Cluster 现有的工作机制,这样对于每个子 K8s 集群来说,并不需要更外层的有一个 K8s Federation,也就是意味着所有现有的 K8s 代码和机制不需要因为 Federation 功能有任何变化。

 Federation 主要包括三个组件:

  • federation-apiserver:类似 kube-apiserver,但提供的是跨集群的 REST API
  • federation-controller-manager:类似 kube-controller-manager,但提供多集群状态的同步机制
  • kubefed:Federation 管理命令行工具

        Federation 的代码维护在 https://github.com/kubernetes/federation。

2.9.5 Prometheus(普罗米修斯)监控

        Prometheus是一个监控和时间序列数据库,并且还提供了告警的功能。它提供了强大的查询语言和 HTTP 接口,也支持将数据导出到 Grafana 中展示。

         使用 Prometheus 监控 Kubernetes 需要配置好数据源,一个简单的示例是 prometheus.yml。

        推荐使用 Prometheus Operator 或 Prometheus Chart 来部署和管理 Prometheus,比如

代码语言:javascript复制
helm install stable/prometheus-operator --name prometheus-operator --namespace monitoring

        使用端口转发的方式访问 Prometheus,如 kubectl --namespace monitoring port-forward service/kube-prometheus-prometheus :9090

 2.9.6 ELK日志收集

        ELK 可谓是容器日志收集、处理和搜索的黄金搭档:

  • Logstash(或者 Fluentd)负责收集日志
  • Elasticsearch 存储日志并提供搜索
  • Kibana 负责日志查询和展示

        注意:Kubernetes 默认使用 fluentd(以 DaemonSet 的方式启动)来收集日志,并将收集的日志发送给 elasticsearch。

小提示 在使用 cluster/kube-up.sh 部署集群的时候,可以设置 KUBE_LOGGING_DESTINATION 环境变量自动部署 Elasticsearch 和 Kibana,并使用 fluentd 收集日志 (配置参考 addons/fluentd-elasticsearch): KUBE_LOGGING_DESTINATION=elasticsearch KUBE_ENABLE_NODE_LOGGING=true cluster/kube-up.sh

        如果使用 GCE 或者 GKE 的话,还可以 将日志发送给 Google Cloud Logging,并可以集成 Google Cloud Storage 和 BigQuery。

        如果需要集成其他的日志方案,还可以自定义 docker 的 log driver,将日志发送到 splunk 或者 awslogs 等。

参考链接

k8s 架构图_信安成长日记的博客-CSDN博客_k8s架构原理图

K8s架构|全面整理K8s的架构介绍_BugGuys的博客-CSDN博客_k8s架构

k8s整体架构的知识整理

k8s架构与组件详解 - 知乎

一文讲明白K8S各核心架构组件

一文讲明白K8S各核心架构组件 - 赐我白日梦 - 博客园

k8s的架构 -阿里云开发者社区

通俗易懂 k8s——架构篇

Kubernetes的整体架构

K8s架构|全面整理K8s的架构介绍

一文秒懂 K8s 架构 | Kubernetes 架构简介 | 红帽

2.k8s的架构 - 腾讯云开发者社区-腾讯云

架构原理 · Kubernetes指南

Master-Node communication

Core Kubernetes: Jazz Improv over Orchestration

Installing kubeadm | Kubernetes

核心组件 · Kubernetes指南

k8s基础介绍(详细)_南柯一梦,笑谈浮生的博客-CSDN博客_k8s基础

0 人点赞