K8s-内部培训

K8s 内部培训

介绍

K8s 为 Kubernetes 的简称, 是一个开源的容器编排平台, 最初是由 Google 工程师开发和设计的, 后于 2015 年捐赠给了云原生计算机基金会-CNCF

应用服务管理发展史

早期服务应用大多以单包的形式运行在服务器上, 当我们增加一些服务时, 比如添加 JOB 应用时, 我们会另开一个新的应用, 但基本用一台服务器上就能完成

所以我们早期应用的发展就如下面图表所示, 由于用户数量较少, 所以更新应用时短暂的暂停服务也是可以接受的

┌──────────────**石器时代**───────────────┐ ┌──────────────**石器时代**───────────────┐ ┌──────────────**石器时代**───────────────┐ │ ┌─────────────`Server1`───────────────┐ │ │ ┌─────────────`Server1`───────────────┐ │ │ ┌─────────────`Server1`───────────────┐ │ │ │ ┌──☕──┐ │ │ │ │ ┌──☕──┐ ┌──☕──┐ │ │ │ │ ┌──☕──┐ ┌──☕──┐ ┌──☕──┐ │ │ │ │ │ APP1 │ │ │ │ │ │ APP1 │ │ APP2 │ │ │ │ │ │ APP1 │ │ APP2 │ │ APP3 │ │ │ │ │ └──────┘ │ │ ==> │ │ └──────┘ └──────┘ │ │ ==> │ │ └──────┘ └──────┘ └──────┘ │ │ │ ├─────────────────────────────────────┤ │ │ ├─────────────────────────────────────┤ │ │ ├─────────────────────────────────────┤ │ │ │ 安装: JDK8, Tomcat, 需要手动启动服务│ │ │ │ 安装: JDK8, Tomcat, 需要手动启动服务│ │ │ │ 安装: JDK8, Tomcat, 需要手动启动服务│ │ │ └─────────────────────────────────────┘ │ │ └─────────────────────────────────────┘ │ │ └─────────────────────────────────────┘ │ └─────────────────────────────────────────┘ └─────────────────────────────────────────┘ └─────────────────────────────────────────┘

随着用户数量的上升, 应用的并发也随之提高, 单台服务器的压力也随之增大, 有了如下情况:

  1. 高峰期经常出现卡顿
  2. 更新应用时的暂停服务已经不可接受
  3. 在服务器出现故障时的高可用有了更高的要求

为了解决上面的问题, 我们就进入了下个时代(下图一), 采购多台服务器, 对应用进行支持集群的改造, 这时我们的应用分别在三台服务器上, 并发能力提高了3倍, 并且冗灾能力大幅提升

尽管我们解决了上面的问题, 但是带来了新的问题, 因为服务器数量过多, 在安装应用需要的工具如 JDK、Tomcat、Node、Nginx、Redis 等等, 可能会因为安装版本和服务器系统版本不一致导致应用运行失败

所以会在环境安装中浪费太多时间, 所以很多企业开始引入如 Docker 的虚拟化技术(下图二), 用来解决环境不一致的问题, 并且一并解决了守护进程, 开机启动等问题

这时我们通过 docker-compose 技术, 升级应用、调整配置相比以前大大简化, 但是随着应用规模的扩大, 对应用高可用有了更高的要求, 纷纷开始进行微服务拆分, 应用数量和服务器数量越来越多, 服务的运维管理越来越复杂、

大家开始开发各种集群管理, 让大家可以在一个地方并且可视化的管理集群中的所有 Docker, 以 Google 开源的 Kubernetes 做的最功能完善且灵活可配置, 从而开始爆火.

于是众多企业开始上K8s(下图三), 不仅解决运维复杂的问题, 而且带来了更多更好的特性:

  1. 服务发现和负载均衡
  2. 存储编排
  3. 自动部署和回滚
  4. 自我修复
  5. 密钥和配置管理
┌──────────────**农耕文明**───────────────┐ ┌─────────────────**工业文明**───────────────┐ ┌─────────────────**信息文明**───────────────┐ │ ┌─────────────`Server1`───────────────┐ │ │ ┌────────────────`Server1`───────────────┐ │ │ ┌────────────────`K8s 集群`──────────────┐ │ │ │ ┌──☕──┐ ┌──☕──┐ ┌──☕──┐ │ │ │ │ ┌─────🐳────┐┌─────🐳────┐┌─────🐳────┐│ │ │ │ ┌─────🐳────┐┌─────🐳────┐┌─────🐳────┐│ │ │ │ │ APP1 │ │ APP2 │ │ APP3 │ │ │ │ │ │ APP1 ││ APP2 ││ APP3 ││ │ │ │ │ POD1 ││ POD2 ││ POD3 ││ │ │ │ └──────┘ └──────┘ └──────┘ │ │ │ │ ├───────────┤├───────────┤├───────────┤│ │ │ │ ├───────────┤├───────────┤├───────────┤│ │ │ ├─────────────────────────────────────┤ │ │ │ │JDK8/Tomcat││JDK8/Tomcat││JDK8/Tomcat││ │ │ │ │JDK8/Tomcat││JDK8/Tomcat││JDK8/Tomcat││ │ │ │ 安装: JDK8, Tomcat, 需要手动启动服务│ │ │ │ └───────────┘└───────────┘└───────────┘│ │ │ │ └───────────┘└───────────┘└───────────┘│ │ │ └─────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ ┌─────🐳────┐┌─────🐳────┐┌─────🐳────┐│ │ │ ┌─────────────`Server2`───────────────┐ │ │ ┌────────────────`Server1`───────────────┐ │ │ │ │ POD4 ││ POD5 ││ POD6 ││ │ │ │ ┌──☕──┐ ┌──☕──┐ ┌──☕──┐ │ │ │ │ ┌─────🐳────┐┌─────🐳────┐┌─────🐳────┐│ │ │ │ ├───────────┤├───────────┤├───────────┤│ │ │ │ │ APP1 │ │ APP2 │ │ APP3 │ │ │ │ │ │ APP1 ││ APP2 ││ APP3 ││ │ │ │ │JDK8/Tomcat││JDK8/Tomcat││JDK8/Tomcat││ │ │ │ └──────┘ └──────┘ └──────┘ │ │ ==> │ │ ├───────────┤├───────────┤├───────────┤│ │ ==> │ │ └───────────┘└───────────┘└───────────┘│ │ │ ├─────────────────────────────────────┤ │ │ │ │JDK8/Tomcat││JDK8/Tomcat││JDK8/Tomcat││ │ │ │ ┌─────🐳────┐┌─────🐳────┐┌─────🐳────┐│ │ │ │ 安装: JDK8, Tomcat, 需要手动启动服务│ │ │ │ └───────────┘└───────────┘└───────────┘│ │ │ │ │ POD7 ││ POD8 ││ POD9 ││ │ │ └─────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ ├───────────┤├───────────┤├───────────┤│ │ │ ┌─────────────`Server3`───────────────┐ │ │ ┌────────────────`Server1`───────────────┐ │ │ │ │JDK8/Tomcat││JDK8/Tomcat││JDK8/Tomcat││ │ │ │ ┌──☕──┐ ┌──☕──┐ ┌──☕──┐ │ │ │ │ ┌─────🐳────┐┌─────🐳────┐┌─────🐳────┐│ │ │ │ └───────────┘└───────────┘└───────────┘│ │ │ │ │ APP1 │ │ APP2 │ │ APP3 │ │ │ │ │ │ APP1 ││ APP2 ││ APP3 ││ │ │ ├────────────────────────────────────────┤ │ │ │ └──────┘ └──────┘ └──────┘ │ │ │ │ ├───────────┤├───────────┤├───────────┤│ │ │ │ ┌───────┐ ┌───────┐ ┌───────┐ │ │ │ ├─────────────────────────────────────┤ │ │ │ │JDK8/Tomcat││JDK8/Tomcat││JDK8/Tomcat││ │ │ │ │Server1│ │Server2│ │Server3│ ••• │ │ │ │ 安装: JDK8, Tomcat, 需要手动启动服务│ │ │ │ └───────────┘└───────────┘└───────────┘│ │ │ │ └───────┘ └───────┘ └───────┘ │ │ │ └─────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ ├─────────────────────────────────────────┤ ├────────────────────────────────────────────┤ ├────────────────────────────────────────────┤ │ 优点: 节省资源, 需要掌握的知识较少 │ │ 优点: 环境搭建容易, 安装Docker和配置文件 │ │ 优点: 自动故障恢复, 监控完善, 操作方便 │ │ 缺点: 运维操作繁杂, JDK版本难以统一 │ │ 缺点: 随着规模扩大, 日常运维也变得繁杂 │ │ 缺点: k8s 功能较多, 需要掌握的知识也多 │ └─────────────────────────────────────────┘ └────────────────────────────────────────────┘ └────────────────────────────────────────────┘ 图一 图二 图三

Kubernetes 组件

Kubernetes 各组件

  • Control Plane Components: 控制平面组件
    • kube-apiserver: 负责公开 Kubernetes API, 处理请求, 类似 cloud 中的网关
    • etcd: key-value 存储, 用于保存集群数据
    • kube-scheduler: 任务调度, 监听有新创建但未运行的pods, 选择节点来让 pod 在上面运行
    • kube-controller-manager: 负责运行控制器进程, 有如下不同类型的控制器
      • Node Controller: 节点控制器, 负责节点出现故障时进行通知和响应
      • Job Controller: 任务控制器, 检测代表一次性任务的 Job 对象, 然后创建 Pod 来运行这些任务直至完成
      • EndpointSlice Controller: 端点分片控制器, 提供 Service 和 Pod 之间的链接
      • ServiceAccount Controller: 为新的命名空间创建默认的服务账号
    • cloud-controller-manager: 云控制管理器, 集成云提供商的API, 我们内网部署的用不到
  • Node Components: 节点组件, 运行在各个节点, 负责维护运行的 Pod, 提供 Kubernetes 的运行环境
    • kubelet: 在每个节点中运行, 保证容器都运行在 Pod 中, kubelet 接受一组 PodSpec, 确保 PodSpec 中描述的容器处于运行状态且健康
    • kube-proxy: 网络代理, 是实现 Service 的一部分
    • Container Runtime: 容器运行时, Kubernetes 支持需要容器运行环境, 例如: docker, containerd, CRI-O
  • Addons: 插件, 提供集群级别的功能, 插件提供的资源属于 kube-system 命名空间
    • DNS: 提供集群内的域名系统
    • Web UI/Dashboard: 通用的基于 Web 的用户界面, 它使用户可以集中管理集群中的应用已经集群本身
    • Container Resource Monitoring: 将容器的一些常见的时间序列度量值保存到一个集中的数据库中, 并提供浏览这些数据的界面
    • Cluster-level Logging: 集群级日志, 将容器日志保存到一个集中的日志存储中, 这种集中日志存储提供搜索和浏览接口
    • Network Plugins: 网络插件, 实现容器网络接口(CNI)规范的软件组件, 负责为 Pod 分配 IP 地址, 并使这些 Pod 能在集群内部互相通信

Kubernetes 架构

Node 节点

Kubernetes 通过将容器放入在节点(Node) 上运行的 Pod 来执行你的负载. 节点可以是一个虚拟机或物理机, 每个节点包含 Pod 所需的服务器, 这些节点由 Control Plane 负责管理

一个集群的节点数量可以是1个, 也可以是多个. 且节点名称是唯一的.

可以通过 kubectl 来创建和修改 Node 对象

# 查一下集群中的所有节点信息
kubectl get node
# 查看某个节点详细信息
kubectl descibe $NODENAME
# 标记一个 Node 为不可调度
kubectl cordon $NODENAME

Controllers 控制器

在机器人和自动化领域, 又一个类似的概念叫控制回路 (Control Loop), 用于调节系统状态, 如: 房间里的温度自动调节器

当你设置了温度, 温度自动调节器让其当前状态接近期望温度; 在 Kubernetes 中, 控制器通过监控集群的公共状态, 并致力于将当前的状态转为期望状态

控制器是通过通知 apiserver 来管理状态的, 就像温度自动调节器是通过控制空调来调节气温的

Container Runtime Interface/CRI 容器运行时接口

CRI 是一个插件接口, 它使 kubelet 能够使用各种容器运行时, 定义了主要 gRPC 协议, 用于节点组件 kubelet 和容器运行时之间的通信

Containers 容器

容器将应用从底层主机设备中解耦, 这使得在不同的云或 OS 环境中部署更加容易

Kubernetes 集群中的每个节点都会运行容器, 这些容器构成分配给该节点的 Pod, 单个 Pod 中的容器会在共同调度下, 运行在相同的节点

容器镜像是一个随时可以运行的软件包, 它包含了运行容器程序所需要的一切, 代码和它需要的运行时、应用程序和系统库, 以及一些基本设置

容器运行时这个基础组件使 Kubernetes 能够有效运行容器, 他负责管理 Kubernetes 环境中的容器的执行和生命周期

Pod

Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署计算单元

Pod 是有一个或多个容器组成, 这些容器共享存储、网络、已经怎么样运行这些容器的声明, 统一调度.

此外还可以包含 init container, 用于做一些启动主应用前的准备工作, 比如通过 init container 注入 tingyun 等 agent 包

如下示例, 它由一个运行镜像 nginx:1.14.2 的容器组成

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: my-nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

要创建上面显示的 Pod, 保存上面内容到 my-nginx.yaml, 可以通过如下命令

kubectl apply -f my-nginx.yaml

Workloads 工作负载

工作负载是在 Kubernetes 上运行的应用程序, 无论是又一个还是多个组件构成, 你都可以通过一组 Pod 来运行它, Pod 代表的是集群上处于运行状态的一组容器的集合, 但通常一个 Pod 内只运行一个容器

Kubernetes 提供若干种内置的工作负载资源:

  • DeploymentReplicaSet Deployment 适合无状态应用, Deployment 中的所有 Pod 都是互相等价的
  • StatefulSet 有状态应用, 比如可以独立持久化文件, 互不影响
  • DaemonSet 提供节点本地支撑设施的 Pod, 保证每个节点上一个
  • JobCronJob 定义只需要执行一次并且执行后视为完完成的任务

Network 网络

Service

Service 是将一个或者一组 Pod 公开代理给集群内部, 使之能够各个应用之间通信, 甚至用于公开到集群外(NodePort 或者 代理给 Ingress)

它提供了类似域名的访问方式, 使用者无需关心后面有多少个 Pod 在提供服务, 他们是否健康, 他们 IP 是否发生变化.

定义 Service

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: my-nginx
  ports:
  - name: name-of-service-port
    protocol: TCP
    port: 80
    targetPort: http-web-svc

服务类型(type):

  • ClusterIp: 默认值, 智能在集群内访问
  • NodePort: 直接向集群外暴露, 通过节点端口访问
  • LoadBalancer: 使用云平台的负载均衡, Kubernetes 不直接提供
  • Externalname: 将服务映射到 externalName 字段的内容, 例如api.foo.bar.example

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 [email protected]

×

喜欢就点赞,疼爱就打赏