文章

Kubernetes 学习实践

参考书籍

Kubernetes修炼手册 - Nigel Poulton 人民邮电出版社

Kubernetes官方文档

基础概念

k8s集群

编排器

  Kubernetes 是一个应用编排器(orchestrator),Kubernetes 包括但不仅限于以下功能。

  • 部署应用程序。
  • 根据需要动态扩缩容。
  • 当出现故障时自愈。
  • 进行不停机的滚动升级和回滚。

  Kubernetes 最突出的优点是无须人工干预决策的情况下自动完成以上所有任务。

k8s基础编排概念

容器化应用

  容器相比传统方式更加轻量、快速、便宜
  2000年以前:应用运行在物理机上;2000-2010年:应用运行在虚拟机上;2010年以后:应用运行在容器中。
  Kubernetes 普遍用于容器的编排。目前k8s主流容器是 Containerd 。

云操作系统

  物理机上的操作系统(Linux、Windows)会将硬件资源(比如网卡、硬盘)统一抽象,并对进程进行调度。
  云上安装k8s时,它会将云上的资源统一抽象,并对云上的应用统一调度。 (可以横跨不同的云包括自建机房,不被某一云厂商绑定,自由负载切换)

主节点 / 控制平面 Master Node / Control Plane

控制平面

工作节点 Work Node

  工作节点主要由3个组件构成: Kubelet 节点代理、CRI容器运行时接口(Container Runtime Interface)、Kube-proxy 网络代理。

工作节点

  • Kubelet
    • 在工作节点加入集群时,Kubelet 负责将当前节点注册到集群中,并将当前节点的Cpu、内存以及存储信息加入到集群资源池
    • Kubelet 的一个重要职责是监听 Api Server 分配的新任务,维护与控制平面的通信频道,并将执行结果返回。
  • CRI
    • 容器运行时接口(Container Runtime Interface) CRI是一个插件接口,它使 Kubelet 能够使用各种容器运行时,无需重新编译集群组件,例如摘取镜像、启动停止或重启容器。CRI 屏蔽了k8s内部运行机制,并向第三方容器提供了接口来支持接入。
    • containerd 「发音如“container-dee”」已替代 Docker 成为k8s最流行的容器。
  • Kube-proxy
    • 是集群中每个节点上所运行的网络代理,维护节点上的一些网络规则,这些网络规则会允许从集群内部或外部的网络会话与 Pod 进行网络通信。例如 保证每个工作节点都可以获取到唯一的 IP 地址,并实现了本地 IPTABLE 以及 IPVS 来保障 Pod 间的网络路由与负载均衡。

  工作节点是k8s集群中的工作者,主要负责以下事情:

  • 监听 Api Server 分派的新任务
  • 执行新分派的任务
  • 向控制平面回复任务执行的结果(通过 Api Server )

Controller管理器

  Controller管理器 对集群监控并响应事件,它负责创建 Controller 并监控他们的执行。每个 Controller 都在后台启动了独立的循环监听功能,负责监听 API Server 的变更,这样做的目标是保证集群的当前状态可以与期望状态匹配。

  • 每个控制循环实现上述功能的基础逻辑如下:
    • 获取期望状态
    • 观察当前状态
    • 判断两者差异
    • 变更当前状态来消除差异点
  • 常用的 Controller 包括DeploymentDaemonSetStatefulSet

Kubernetes DNS

  尽管其他插件都并非严格意义上的必需组件,但几乎所有 Kubernetes 集群都应该有集群 DNS, 因为很多示例都需要 DNS 服务。
集群 DNS 是一个 DNS 服务器,和环境中的其他 DNS 服务器一起工作,它为 Kubernetes 服务提供 DNS 记录。
Kubernetes 启动的容器自动将此 DNS 服务器包含在其 DNS 搜索列表中

Pod

  • 在k8s中,调度的原子单位是 Pod , Pod 本身并不会运行任何东西,只是作为一个承载容器的沙箱而存在。
  • 在英语中,会将a group of whales(一群鲸鱼)称作 a Pod of whale,因为 Docker 的Logo是鲸鱼,所以在k8s中会将包含了一组容器的事物称作Pod。
  • 如果在 Pod 中运行多个容器,那么多个容器间是共享相同的Pod环境的。共享环境中包括了IPC命名空间、内存、磁盘、网络以及其他资源等。举一个具体的例子,运行在相同 Pod 中的所有容器,都有相同的IP地址( Pod 的IP地址)。
  • 一般来说,用户通过更上层的控制器来完成Pod部署。上层的控制器包括 DeploymentDaemonSetStatefulSetDeployment提供了如扩缩容管理、不停机更新以及版本控制等其他特性。

  Pod 的生命周期:
Pod的生命周期

服务注册与发现

Service

  由于 Pod 是不可靠的,上层控制器如 Deployment 会自动替换掉有故障的 Pod ,每个 Pod 的IP都是不同的,Service组件实现了一组Pod的动态负载均衡,提供了请求路由到Pod的能力。
Service、网络、服务发现

Kubernetes 存储

卷 Volume

  容器中的文件在磁盘上是临时存放的,当容器崩溃或停止时,容器生命周期内创建或修改的所有文件都将丢失;当多个容器在一个 Pod 中运行并且需要共享文件时,会出现另一个问题。 跨所有容器设置和访问共享文件系统具有一定的挑战性。卷(Volume) 这一抽象概念为解决这两个问题而出现。
  Kubernetes 支持来自多种途径(如云上、自建机房,本地磁盘等)多种类型的存储。无论来自何处、无论什么软硬件的存储,在其对接到k8s时,都被统称为。卷的核心是一个目录,其中可能存有数据, Pod 中的容器可以访问该目录中的数据。卷所采用的特定的卷类型将决定该目录如何形成的、使用何种介质保存数据以及目录中存放的内容。
  Kubernetes 支持很多类型的卷。 Pod 可以同时使用任意数目的卷类型。 临时卷类型的生命周期与 Pod 相同, 但持久卷可以比 Pod 的存活期长。 当 Pod 不再存在时,Kubernetes 也会销毁临时卷;不过 Kubernetes 不会销毁持久卷。 对于给定 Pod 中任何类型的卷,在容器重启期间数据都不会丢失。

  • 持久卷 (Persistent Volume,PV)   持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样, 也是使用卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。
  • 临时卷 (Ephemeral Volume)   有些应用程序需要额外的存储,但并不关心数据在重启后是否仍然可用。 例如,缓存服务经常受限于内存大小,而且可以将不常用的数据转移到比内存慢的存储中,对总体性能的影响并不大。

容器存储接口 CSI

  就像CRI是容器运行时抽象化的接口一样,容器存储接口(Container Storage Interface) CSI将存储驱动的实现与k8s的集成简洁抽象化,不过日常管理一般不会与CSI接触。

k8s持久化系统

  概括地说,PV 代表的是 Kubernetes 中的存储; PVC 就像许可证,赋 予 Pod 访问 PV 的权限; CS 则使分配过程是动态的。

  • 持久卷(Persistent Volume,PV)
  • 持久卷申请 (Persistent Volume Claim,PVC)
  • 持久类(Storage Class,SC)

持久化存储

集群配置 ConfigMap

ConfigMap

  ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中,将你的配置数据和应用程序代码分开。ConfigMap 在设计上不是用来保存大量数据的。在 ConfigMap 中保存的数据不可超过 1 MiB。如果你需要保存超出此尺寸限制的数据,你可能希望考虑挂载存储卷 或者使用独立的数据库或者文件服务。   ConfigMap 同样支持声明式与命令式配置,配置参数参考 官方文档-ConfigMap

ConfigMap 的使用

通过环境变量使用 ConfigMap

  将 ConfigMap 作为环境变量来使用是有缺点的,所有 ConfigMap 的变化事件对运行中的容器是感知不了的。
通过环境变量使用 ConfigMap

将 ConfigMap 作为数据卷挂载

  将ConfigMap作为数据卷挂载是最灵活的方式,当卷中使用的 ConfigMap 被更新时,所投射的键最终也会被更新。 ConfigMap 作为数据卷挂载

其他使用方式

  • 在容器命令和参数内使用 ConfigMap
  • 编写代码在 Pod 中运行,使用 Kubernetes API 来读取 ConfigMap

StatefulSet 与 Deployment

StatefulSet 与 Deployment 的相同点

  • 都是 Kubernetes API 中的一等对象,并且遵循典型的 Kubernetes 控制器架构。这些控制器都通过启动对 API Server 的监听循环来观察集群状态,以便能够及时将当前状态调整至与期望状态保持一致。
  • Deployment和StatefulSet都支持自愈、自动扩缩容、滚动更新等特性。

StatefulSet 与 Deployment 的差异点

  • 名字
      StatefulSet 中的 Pod遵循 StatefulSetName-Integer 的规则,后面的数字是自增的;而 Deployment 则是随机名字的Pod。事实上,StatefulSet Pod 的 名字与扩缩容操作和关联存储卷操作是息息相关的。
  • 部署、扩展、更新、删除顺序
      StatefulSet 部署、扩展、更新、删除都要有逐一顺序操作,而 Deployment 中的 Pod 都是无序且并行的。
  • 存储
      StatefulSet 给定 Pod 的存储必须基于所请求的 storage class 来制备,删除或者扩缩 StatefulSet 并不会删除它关联的存储卷。
  • 网络
      StatefulSet 只能使用 无头服务 headlessService 它没有ClusterIP,无法负载均衡,返回的都是 pod 的 Dns 子域名(默认 <object-name>.<Service-name>.<namespace>.svc.cluster.local

k8s 安全模型

STRIDE 模型分析

  • 伪装(Spoofing)
    • 防止 k8s 组件的伪装
      • k8s 组件与 Api Server的通信均通过 mutual TLS mTLS (https 双向认证)
      • k8s 默认会生成一个证书颁发接口(Certificate Authority, CA) ,CA 一般情况下只在集群内部使用以确保其安全。
    • 防止 Pod 的伪装
      • 每一个Pod都有一个关联的ServiceAccount,它用于在集群内部为该Pod提供身份证明。Kubernetes会自动将一个服务账号令牌(Service account token)作为Secret挂载到每一个Pod中。
  • 篡改(Tampering)
    • 防止 k8s 组件的篡改
      • 严格限制对运行有Kubernetes的服务器的访问,尤其是部署了 Kubernetes控制层组件的节点。
      • 严格限制对保存有Kubernetes配置文件的库的访问。
      • 仅在最初部署Kubernetes时进行远程SSH访问(记得安全保管SSH密钥)。
      • 对于下载的二进制文件一定进行SHA-2校验和的查验。
      • 严格限制对镜像仓库及相关库的访问。
    • 防止 Pod 中应用的篡改
      • 通过配置 Pod 描述文件中 spec.securityContext ,能限制容器中的文件系统为只读属性
  • 抵赖(Repudiation)
    • 可以借住 DaemonSet 在所有节点部署代理程序,收集日志并发送到一个安全的中心日志库并加以审计。
  • 信息泄露(Information Disclosure)
    • k8s 通过提供 Secret 以加密敏感数据。
  • 拒绝服务(Denial of Service)
    • 借助防火墙,在内网控制对集群的访问
    • 保证集群资源 Contorll Panel、 Work Node、etcd 多活高可用
    • 对访问进行监控与预警
  • 提升权限(Elevation of Privilege)
    • 保护 Api Server
      • 基于角色的访问控制(Role-based Access Control, RBAC) 限制仅对指定的用户开放某API操作的权限,此处的 “用户”既可以是普通的用户账号,也包括系统服务。
    • 保护 Pod
      • 通过配置 Pod 描述文件中 spec.securityContext 避免进程以root身份运行、启用用户命名空间(user namespace)、维护一个map来记录UID的使用情况、禁止容器中的权限扩大。
      • 通过配置 Pod 描述文件中 spec.securityContext.capabilities 或者 赋予应用系统权限。
      • 使用 seccomp 限制容器的系统调用
本文由作者按照 CC BY 4.0 进行授权