深入浅出 Kubernetes.pdf

集群控制器

核心组件

01-深入浅出 Kubernetes - 图1

K8S 大图

image.png

集群网络详解

核心方案

01-深入浅出 Kubernetes - 图3

集群网络鸟瞰图(flannel 为例)

image.png
包括集群CIDR,VPC路由表,节点网络,节点的podCIDR,节点上的虚拟网桥cni0,连接Pod和网桥的veth等部分。
01-深入浅出 Kubernetes - 图5

集群网络搭建

初始阶段 —》集群阶段 —》节点阶段 —》Pod阶段

通信

基于以上的网络环境,Pod 可以完成四种通信
01-深入浅出 Kubernetes - 图6

  • 本地通信,说的是 Pod 内部,不同容器之前通信。因为 Pod 内网容器之间共享一个网络协议栈,所以他们之间的通信,可以通过 loopback 设备完成。
  • 同节点 Pod 之间的通信,是 cni0 虚拟网桥内部的通信,这相当于一个二层局域网内部设备通信。
  • 跨节点 Pod 通信略微复杂一点,但也很直观,发送端数据包,通过 cni0 网桥的网关,流转到节点上,然后经过节点 eth0 发送给 VPC 路由。
  • Pod 与非 Pod 网络的实体通信,需要经过节点上 iptables 规则做 snat,而此规则就是 flanneld 依据命令行 —ip-masq 选项做的配置。

如下图
image.png

扩缩容

增加节点

kubeadm join …
image.png

  • 一边,新加节点从管控处获取的 bootstrap token(与 openapi token 不同,此token 是 value 的一部分内容),实际上是管控通过可信的途径从集群 Master 上获取的。新加节点使用这个 bootstrap token 连接 Master,Master 则可通过验证这个bootstrap token 来建立对新加节点的信任。
  • 另一边,新加节点以匿名身份从 Master kube-public 命名空间中获取集群cluster-info,cluster-info 包括集群 CA 证书,和使用集群 bootstrap token 对这个 CA 做的签名。新加节点使用从管控处获取的 bootstrap token,对 CA 生成 b 新的签名,然后将此签名与 cluster-info 内签名做对比,如果两个签名一致,则说明cluster-info 和 bootstrap token 来自同一集群。新加节点因为信任管控,所以建立对 Master 的信任。

    减少节点

    有时候我们想更新一些服务器,或者维护/更新一些镜像的时候,需要暂定一部分node节点可以通过cordon 实现临时暂停k8s节点。
    https://www.jianshu.com/p/30c17d9a43b5
    01-深入浅出 Kubernetes - 图9

    认证与调度

    入口:apiserver

    CA双向认证

    使用基于 CA 签名的双向数字证书认证来保证客户端与 api server 之间的安全通信。
    image.png
    客户端和 API Server 作为通信的普通参与者,各有一张证书。而这两张证书,都是由 CA 签发,我们简单称它们为集群 CA 和客户端 CA。客户端信任集群 CA,所以它信任拥有集群 CA 签发证书的 API Server;反过来 API Server 需要信任客户端 CA,它才愿意与客户端通信。
    image.png
    认证过程

  • 首先,客户端证书的签发者 CN 是集群 id c0256a3b8e4b948bb9c21e66b0e1d9a72 即集群CA证书

  • 其次,只有在 API Server 信任客户端 CA 证书的情况下,上边的客户端证书才能通过 API Server 的验证。
  • 再 次,API Server 使 用 的 证 书,这个证书的 CN 是 kube-apiserver, 签 发 者 是 c0256a3b8e4b948bb9c21e66b0e1d9a72,即集群 CA 证书。
  • 最后,客户端需要验证上边这张 API Server 的证书,对比集群 CA 证书和客户端 CA 证书, 发现两张证书完全一样,这符合我们的预期。

    调度

    01-深入浅出 Kubernetes - 图12
    架构图如下
    image.png
    既然是多节点的架构,那pod被运行在哪个节点该怎么确定了,这个时候就需要调度算法了,类比linux os中的CPU调度算法。调度算法需要解决的问题,是替 pod 选择一个舒适的“居所”,让 pod 所定义的任务可以在这个节点上顺利地完成。目标就是“择优而居”。算法简单理解两步走

    • 第一步,从所有节点中排除不满足条件的节点,即预选;通过在节点上判断包括资源(CPU、内存等)、端口等是否满足需求。
    • 第二步,给剩余的节点打分,最后得分高者胜出,即优选,对通过了第一步的剩余节点通过相关的规则(剩余CPU、内存,CPU使用/内存使用的比值,以及同一个服务的多个Pod分散在不同节点等)进行打分(会根据各项得分,然后乘以一个权重系数进行最后的综合计算),得分高者胜出,作为目标节点。

      集群服务的三个要点和一种实现

      K8S服务的本质是什么

      本质是:负载均衡

      三个要点

      01-深入浅出 Kubernetes - 图14

      一种实现

      我们思考了过滤器框架的设计,并在此基础上,理解使用 iptables 实现的服务负载均衡的原理。
      image.png
      节点上的反向代理,如下图所示的proxy
      image.png
      在这里把服务照进反向代理这个现实的,是 K8S 集群的一个控制器,即 kube-proxy。关于 K8S 集群控制器的原理,请参考我另外一篇关于控制器的文章。简单来 说,kube-proxy 作为部署在集群节点上的控制器,它们通过集群 API Server 监听着集群状态变化。当有新的服务被创建的时候,kube-proxy 则会把集群服务的状态、属性,翻译成反向代理的配置。

      Proxy的实现

      基于linux 内核中的 iptables 来实现的。
      image.png
      image.png
      现在我们看一下 K8S 集群节点的网络全貌。横向来看,节点上的网络环境,被分割成不同的网络命名空间,包括主机网络命名空间和 Pod 网络命名空间;纵向来看,每个网络命名空间包括完整的网络栈,从应用到协议栈,再到网络设备。
      为了实现管道和过滤功能两者的解耦,netfilter 用了表这个概念。表就是 netfilter 的过滤中心,其核心功能是过滤方式的分类(表),以及每种过滤方式中,过滤规则的组织(链)。
      image.png
      集群服务的反向代理,实际上就是利用自定义链,模块化地实现了数据包的DNAT 转换。KUBE-SERVICE 是整个反向代理的入口链,其对应所有服务的总入口;KUBE-SVC-XXXX 链是具体某一个服务的入口链,KUBE-SERVICE 链会根据服务 IP,跳转到具体服务的 KUBE-SVC-XXXX 链;而 KUBE-SEP-XXXX 链代表着某一个具体 Pod 的地址和端口,即 endpoint,具体服务链 KUBE-SVC-XXXX 会以一定算法(一般是随机),跳转到 endpoint 链。
      image.png

      镜像拉取这件小事

      OAuth2.0

      其主要流程如下
      01-深入浅出 Kubernetes - 图21
      image.png
      简单来说,这个协议其实就做了两件事情:
      ● 在用户授权的情况下,三方应用获取 token 所表示的临时访问权限;
      ● 然后三方应用使用这个 token 去获取资源。

      Docker 扮演的角色

      image.png
  • 理解 docker login

    • 第一件事情是跟用户要账户密码。
    • 第二件事情,docker 访问镜像仓库的 https 地址,并通过挑战 v2 接口来确认,接口是否会返回 Docker-Distribution-Api-Version 头字段。
    • 第三件事情,docker 使用用户提供的账户密码,访问 Www-Authenticate 头字段返回的鉴权服务器的地址 Bearer realm。如果这个访问成功,则鉴权服务器会返回 jwt 格式的 token 给 docker,然后 docker 会把账户密码编码并保存在用户目录的 .docker/docker.json 文件里。
      1. [root@localhost addons]# more ~/.docker/config.json
      2. {
      3. "auths": {
      4. "docker.sangfor.com": {
      5. "auth": "cHJvZHVjdF8yNTczXzY3NjgyNjoyYTE3MDcxZTljNjM3ZDUx"
      6. }
      7. },
      8. "HttpHeaders": {
      9. "User-Agent": "Docker-Client/19.03.2 (linux)"
      10. }
      11. }
  • 拉取镜像是怎么回事

镜像一般会包括两部分内容,一个是 manifests 文件,这个文件定义了镜像的元数据,另一个是镜像层,是实际的镜像分层文件。拉取 manifests 文件,基本上也会做三件事情:

  • 首先,docker 直接访问镜像 manifests 的地址,以便获取 Www-Authenticate 头字段。这个字段包括鉴权服务器的地址 Bearer realm,镜像服务地址 service,以及定义了镜像和操作的 scope。
  • 接着,docker 访问上边拿到的 Bearer realm 地址来鉴权,以及在鉴权之后获取一个临时的token。这对应协议大图使用账户密码获取临时 token 这一步,使用的账户密码直接读取自 docker.json 文件。
  • 最 后, 使 用 上 边 的 token, 以 Authorization 头 字 段 的 方 式, 来 下 载 manifests 文件。这对应的是协议大图下载镜像这一步。当然因为镜像还有分层文件,所以实际 docker 还会用这个临时 token 多次下载文件才能完成镜像下载。

    K8S实现私有镜像获取

    常规方式

    K8s 集群一般会管理多个节点,每个节点都有自己的 docker 环境。如果让用 户分别到集群节点上登录镜像仓库,这显然是很不方便的。为了解决这个问题,K8s 实现了自动拉取镜像的功能。这个功能的核心,是把 docker.json 内容编码,并以 Secret 的方式作为 Pod 定义的一部分传给 Kubelet。
    image.png
    具体来说,步骤如下:
    1. 创 建 secret。 这 个 secret 的 .dockerconfigjson 数 据 项 包 括 了 一 份 base64 编码的 docker.json 文件;
    2. 创建 pod,且 pod 编排中 imagePullSecrets 指向第一步创建的 secret;
    3. Kubelet 作为集群控制器,监控着集群的变化。当它发现新的 pod 被创建,就会通过 API Server 获取 pod 的定义,这包括 imagePullSecrets 引用的 secret;
    4. Kubelet 调用 docker 创建容器且把 .dockerconfigjson 传给 docker;
    5. 最后 docker 使用解码出来的账户密码拉取镜像,这和上一节的方法一致。

    进阶方式

    上边的功能,一定程度上解决了集群节点登录镜像仓库不方便的问题。但是我们在创建 Pod 的时候,仍然需要给 Pod 指定 imagePullSecrets。K8s 通过变更准入控制(Mutating Admission Control)进一步优化了上边的基本功能。
    image.png
    进一步优化的内容如下:
    1. 在 第 一 步 创 建 secret 之 后, 添 加 default service account 对 imagePullSecrets 的引用;
    2. Pod 默认使用 default service account,而 service account 变更准入控制器会在 default service account 引用 imagePullSecrets 的情况下,添加 imagePullSecrets 配置到 pod 的编排里。

实践篇

集群节点NotReady问题排查(1/2)

二分之一活的微服务(Istio、pilot问题排查)

CA证书过期(Istio中Cidatel不能重启)