[虚拟化] K8S概述

1 K8S概述

1.1 K8S的简述

  • Kubernetes(简称“K8s”或者“Kube”)是Google开源的、用于管理云平台多个主机上的容器化应用的——容器集群管理系统
  • 其设计目标是在主机集群之间提供一个能够自动化部署可拓展应用容器可运营的平台。
    • Kubernetes通常结合docker容器工具工作,并且整合多个运行着docker容器的主机集群
    • Kubernetes不仅仅支持Docker,还支持Rocket,这是另一种容器技术。
  • Kubernetes与Google。
    • K8s最初由 Google 的工程师开发和设计
    • Google 是最早研发 Linux 容器技术的企业之一,曾公开分享介绍 Google 云服务背后的技术- 如何将一切都运行于容器之中
    • Google 每周会启用超过 20 亿个容器全都由内部平台 Borg 支撑。
  • Borg 是 Kubernetes 的前身,多年来开发 Borg 的经验教训成了影响 Kubernetes 中许多技术的主要因素。

1.2 K8S的诞生背景:为什么需要Kubernetes?

  • K8s的目标是让部署容器化的应用能够简单、且高效;它提供了应用部署规划更新维护的一种机制。

  • K8s是一种可自动实施Linux 容器操作的开源平台。

    • 它可以帮助用户省去应用容器化过程的许多手动部署扩展操作
    • 也就是说,您可以将运行 Linux 容器的多组主机聚集在一起,借助 Kubernetes 编排功能,您可以构建跨多个容器的应用服务跨集群调度、扩展这些容器,并长期持续管理这些容器的健康状况
  • 有了 Kubernetes,您便可切实采取一些措施来提高 IT 安全性

  • 而且这些集群可跨公共云私有云混合云部署主机。

  • Kubernetes 还需要与联网、存储、安全性、遥测其他服务整合,以提供全面的容器基础架构

  • 综上,对于要求快速扩展的云原生应用而言,Kubernetes 是理想的托管平台

    • K8s于 2015 年发布,并迅速成为事实上的容器编排标准

1.2 K8S的特点

  • 自动推出和回滚

K8s 会逐步推出应用程序或其配置的更改,同时监控应用程序运行状况以确保它不会同时终止所有实例。
如果出现问题,K8s 会为您回滚(rollback)更改。
利用不断增长的部署解决方案生态系统。

  • 服务发现和负载均衡

使用不熟悉的服务发现机制无需修改应用程序。
K8s 为 Pod 提供了自己的 IP 地址和一组 Pod 的单个 DNS 名称,并且可以在它们之间进行负载平衡。

  • 存储编排

自动挂载选择的存储系统,无论是本地存储、公共云提供商,还是网络存储系统。

  • 机密和配置管理

部署和更新机密和应用程序配置,而无需重建映像,也无需在堆栈配置中公开机密。

  • 自动打包

根据资源需求和其他限制自动放置容器,而且不牺牲可用性。混合使用关键工作负载和尽力而为的工作负载,以提高利用率并节省更多资源。

  • 批量执行

除了服务之外,K8s 还可以管理批处理和 CI(Continuously Integration) 工作负载,并根据需要替换出现故障的容器。

  • IPv4/IPv6 双网络协议栈

将 IPv4 和 IPv6 地址分配给 Pod 和服务。

  • 水平压缩扩展

使用简单的命令、UI 或根据 CPU 使用情况自动压缩扩展应用程序。

  • 自我恢复

重新启动失败的容器,在节点故障时替换和重新安排容器,终止不响应用户定义健康检查的容器,并且在它们准备好提供服务之前不向客户端通告它们。

  • 专为可扩展性而设计

在不更改上游源代码的情况下为 K8s 集群添加功能。

https://kubernetes.io/

2 K8s的工作原理

2.1 运行架构

k8s 集群的架构,从左到右,分为两部分:

  • 第1部分: Master 节点(对应图中的 Control Plane) / 整个集群的大脑
    • Master 节点,一般包括四个组件:apiserver、scheduler、controller-manager、etcd
    • Apiserver
      • 上知天文下知地理,上连其余组件,下接ETCD,提供各类 api 处理、鉴权,和 Node 上的 kubelet 通信等
      • 只有 apiserver 会连接 ETCD。
    • Controller-manager:控制各类 controller,通过控制器模式,致力于将当前状态转变为期望状态
    • Scheduler:调度,打分,分配资源。
    • Etcd:整个集群的数据库,也可不部署在 Master 节点,单独搭建。
  • 第2部分是 Node 节点 / 运行 Master 节点调度的应用
    • Node 节点,一般也包括3个组件,docker,kube-proxy,kubelet
    • Kube-proxy:主要负责网络的打通,早期利用 iptables,现在使用 ipvs技术。
    • Docker:具体跑应用的载体。
    • Kubelet:agent,负责管理容器的生命周期。

2.2 k8s 组件调用流程

我们看下kubectl create deployment redis-deployment --image=redis下发之后,k8s 集群做了什么。

  • 首先 controller-manager, scheduler, kubelet 都会和 apiserver 开始进行 List-Watch 模型

    • List 是拿到当前的状态,Watch 是拿到期望状态
    • k8s 集群会致力于将当前状态达到达期望状态
  • kubectl 下发命令到 apiserver,鉴权处理之后将创建信息存入 etcd,Deployment 的实现是使用 ReplicaSet 控制器,当 controller-manager 提前拿到当前的状态(pod=0),接着接收到期望状态,需要创建 ReplicaSet(pod=1),就会开始创建 Pod。

  • 然后 scheduler 会进行调度,确认 Pod 被创建在哪一台 Node 上。

  • 之后 Node 上的 kubelet 真正拉起一个 docker。

这些步骤中,apiserver 的作用是不言而喻的,所以说上接其余组件,下连 ETCD;但是 apiserver 是可以横向扩容的,然后通过负载均衡,倒是 ETCD 在 k8s 架构中成了瓶颈。
最开始看这架构的时候,会想着为啥 apiserver, scheduler, controller-manager 不合成一个组件?
其实在 Google Borg 中,borgmaster 就是这样的,功能也是这些功能;
但是合在了一起,最后他们也发现集群大了之后 borgmaster 会有些性能上的问题,包括 kubelet 的心跳就是很大一块;
所以, k8s 从一开始开源,设计中有三个组件也是更好维护代码吧。

2.3 核心概念

Container

  • 一般地,1个container只应包含1个应用进程

因为:这样能更好的监控container的状态
可理解为k8s监控的最小粒度是container

Pod

  • 在Kubernetes中,基本调度单元称为“pod”

    • 通过该种抽象类别可以把更高级别的抽象内容增加到容器化组件
  • pod = 0..N 个 container

    • 一个Pod可承载一个或者多个相关的容器
      • 假定 Container 为 Docker Container,则:
        • 1个 Pod 中可以包含多个 Docker,这些 Docker 都会被调度到同一台 Node 上
        • 这些 Docker 共享 NetWork Namespace,且可声明共享同一个 Volume 来共享磁盘空间
        • 这样的好处是什么呢?
          • 其实在真实的世界中,很多应用是有部署在同一台机器的需求的
          • 比如, Redis 日志采集插件要采集日志,肯定需要和 Redis 部署在同一台机器(Pod)上才能读到 Redis 的日志
    • 但一般地,1个pod中只会有1个container
    • 1个pod下的container只会部署在1个物理节点

意味着:1个pod下不同container的交互可通过localhost进行

  • 同一pod存在多个container的情况一般是:
    • 1个为主container
    • 其他container负责做一些辅助任务
      • 如:log agent负责上报主container生产的日志

ReplicationController & ReplicaSet

  • 背景
    • 如果我们都人工的去解决遇到的pod重启问题,似乎又回到了以前刀耕火种的时代了是吧?
    • 如果有一种工具能够来帮助我们管理Pod就好了,Pod不够了自动帮我新增一个,Pod挂了自动帮我在合适的节点上重新启动一个Pod。
      • 这样是不是遇到重启问题我们都不需要手动去解决了。
    • 幸运的是,Kubernetes就为我们提供了这样的资源对象:
      • Replication Controller:用来部署、升级Pod
      • Replica Set:下一代的Replication Controller
      • Deployment:可以更加方便的管理Pod和ReplicaSet

ReplicationController

  • Replication Controller简称RC,RC是Kubernetes系统中的核心概念之一
    • 简单来说,RC可以保证在任意时间运行Pod的副本数量,能够保证Pod总是可用的。
  • 如果实际Pod数量比指定的多,那就结束掉多余的;如果实际数量比指定的少就新启动一些Pod,当Pod失败、被删除或者挂掉后,RC都会去自动创建新的Pod来保证副本数量。
    • 所以,即使只有一个Pod,我们也应该使用RC来管理我们的Pod。
    • 可以说,通过ReplicationController,Kubernetes实现了集群的高可用性

ReplicaSet

  • Replication Set简称RS.

    • 随着Kubernetes的高速发展,官方已经推荐我们使用RS和Deployment来代替RC了
    • 实际上RS和RC的功能基本一致,目前唯一的一个区别:
      • RC只支持基于等式的selector(env=dev或environment!=qa)
      • 但RS还支持基于集合的selector(version in (v1.0, v2.0))
      • 这对复杂的运维管理就非常方便了。
  • kubectl命令行工具中关于RC的大部分命令同样适用于我们的RS资源对象。

    • 不过我们也很少会去单独使用RS
    • 它主要被Deployment这个更加高层的资源对象使用,除非用户需要自定义升级功能或根本不需要升级Pod
  • 在一般情况下,我们推荐使用 Deployment 而不直接使用 Replica Set

小结

这里总结下关于RC/RS的一些特性和作用:

  • 大部分情况下,我们可以通过定义一个RC实现的Pod的创建和副本数量的控制
  • RC中包含一个完整的Pod定义模块(不包含apiversion和kind)
  • RC是通过label selector机制来实现对Pod副本的控制的
  • 通过改变RC里面的Pod副本数量,可以实现Pod的扩缩容功能
  • 通过改变RC里面的Pod模板中镜像版本,可以实现Pod的滚动升级功能(但是不支持一键回滚,需要用相同的方法去修改镜像地址)

Deployment

定义与作用

  • Deployment是k8s中用来管理发布的控制器,在开发的过程中使用非常频繁
    • 声明式API
    • 最终一致性
    • 水平触发
    • 资源对象
  • Deployment 可定义多副本个 Pod,从而为应用提供迁移能力
  • 若单纯使用 Pod,实际上当应用被调度到某台机器之后,机器宕机应用也无法自动迁移,但是使用 Deployment,则:
    • 会调用 ReplicaSet(一种控制器) 来保证当前集群中的应用副本数和指定的一致。

  • Deployment 定义一组pod的期望数量,controller会维持Pod的数量和期望的一致
    • 其实deployment是通过管理 ReplicaSet 的状态来间接管理pod
  • 配置Pod的发布方式,controller会按照给定的策略去更新pod资源,以此来保证更新过程中可用的pod数量和不可用的pod数量都在限定范围内。(MaxUnavailable以及MaxSurge字段)
  • 支持回滚操作,可记录多个前置版本(数量可通过配置设置revisionHistoryLimit)

主要字段说明

Deployment 状态迁移

Deployment 控制流程

  • 同样也是通过inform对事件进行list&watch,并调用相关的handle进行处理
    • 其中关于Check Paused是对有关于一些Debugger模式下可以只同步replicas而不发布版本。
  • 而对应RS控制器则更加简单了,只对pod数量进行控制管理就行。
    • 相对而言,deployment更加复杂一些,同时能做的事情也更多。

Labels

  • 所有k8s的资源都可以被打上标

比如pod、node

  • label为kv形式,且一个资源上能打上多种标签。

  • 打完标签后,可通过label selectors来筛选出打上特定label的资源。

  • 【案例】

可将不同版本的pod通过label打上不同的标签: version=v1/v2/…;
然后,利用label selectors就可将version=v1的pod全部取出。

  • 【案例】label还可标示node资源

举个例子:
如果某些node底层是gpu,
可将这些nodes搭上label:gpu=true,
然后,在部署需要在gpu上运行的服务时,便可通过label selectors来指定特定的pods需要部署在gpu=true的nodes上。

namespace

1个pod可能会有多个label,但只会有1个namespace。
namespace的概念可类比于【租户】,通过namespace可指定到不同的租户的命名空间。
但需注意的是,namespace仅仅是个逻辑上的分类,在你指定了某个namespace后,你只能看到对应namespace的pod,但并不作其他方面的区分。
比如,不同namespace的pod仍可以互相调用。

service

service可理解为就是psm,提供了一类服务的入口。
本质上,replicaSets等负责管理pod,而service负责pod与内外部服务的交互。
在service定义时需要定义port和targetport,port代表service正在监听的端口,收到请求后,service会将请求转发到对应pod的targetport上。

3 实践应用

3.1 ReplicationController & ReplicaSet & Deployment

3.1.1 ReplicationController

  • 【案例】

Step0 开始演示

# 启动k8s
minikube start
# 删除上次的pod
kubectl delete -f pod_nginx.yml

Step1 查看rc_nginx.yml
apiVersion: v1
kind: ReplicationController 
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    app: nginx
  template:
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

上面的YAML文件:

  • kind:ReplicationController
  • spec.replicas: 指定Pod副本数量,默认为1
  • spec.selector: RC通过该属性来筛选要控制的Pod
  • spec.template: 这里就是我们之前的Pod的定义的模块,但是不需要apiVersion和kind了
  • spec.template.metadata.labels: 注意这里的Pod的labels要和spec.selector相同,这样RC就可以来控制当前这个Pod了。
# 创建1个ReplicationController的横向扩展
kubectl create -f rc_nginx.yml
kubectl get pods
kubectl get rc

Step2 删除一个看看效果如何
通过delete pods 的方式删除一个容器,立刻就有一个新的容器起来

kubectl get  rc
kubectl get pod
kubectl delete pods nginx-h2qbt
kubectl get pods
kubectl get  rc

Step3 scale 水平扩展的数量

kubectl scale rc nginx --replicas=2
kubectl get  rc
kubectl scale rc nginx --replicas=5
kubectl get  pods -o wide

3.1.2 ReplicaSet

  • 查看rc_nginx.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: nginx
  labels:
    tier: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      tier: frontend
  template:
    metadata:
      name: nginx
      labels:
        tier: frontend
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
#删除ReplicationController创建的pod
kubectl delete -f rc_nginx.yml
#创建一个ReplicationController的横向扩展
kubectl create -f rs_nginx.yml
kubectl get pods -o wide
kubectl get pods
kubectl get rc

  • 删除一个看看效果如何

通过delete pods 的方式删除一个容器,立刻就有一个新的容器起来

kubectl get  rs
kubectl get pod
kubectl delete pods nginx-h2qbt
kubectl get pods
kubectl get  rs

  • scale 水平扩展的数量
kubectl scale rs nginx --replicas=2
kubectl get  rs
kubectl scale rs nginx --replicas=5
kubectl get  pods -o wide

通过这次了解了pod的扩展,ReplicaSet和ReplicationController的方式,基本上可以抛弃上次的直接pod的方式创建app了。下次说说Deployment。

Y 推荐资源

X 参考文献

posted @ 2023-09-07 07:57  千千寰宇  阅读(985)  评论(0编辑  收藏  举报