# 一.基础介绍

# 1.应用部署方式演变

在部署应用程序的方式上,主要经历了三个时代:

  • 传统部署:互联网早期,会直接将应用程序部署在物理机上

    • 优点:简单,不需要其它技术的参与
    • 缺点:不能为应用程序定义资源使用边界,很难合理地分配计算资源,而且程序之间容易产生影响
  • 虚拟化部署:可以在一台物理机上运行多个虚拟机,每个虚拟机都是独立的一个环境

    • 优点:程序环境不会相互产生影响,提供了一定程度的安全性
    • 缺点:增加了操作系统,浪费了部分资源
  • 容器化部署:与虚拟化类似,但是共享了操作系统

    • 优点:可以保证每个容器拥有自己的文件系统、CPU、内存、进程空间等运行应用程序所需要的资源都被容器包装,并和底层基础架构解耦容器化的应用程序可以跨云服务商、跨 Linux 操作系统发行版进行部署

image-20230315161732274

# 2.容器编排工具

容器编排工具是用于自动化、管理和协调容器化应用程序的工具。它们帮助开发人员和运维人员管理容器、部署应用、自动伸缩、升级和监控应用等。以下是一些常见的容器编排工具:

  1. Kubernetes(K8s): Kubernetes 是最流行的容器编排工具之一,提供强大的功能来管理容器化应用程序,包括自动化部署、伸缩、负载均衡、服务发现、自动恢复等。

  2. Docker Swarm: Docker Swarm 是由 Docker 提供的容器编排工具,它允许用户通过简单的命令创建和管理 Swarm 集群,实现容器的部署和扩展。

  3. Apache Mesos: Mesos 是一个开源的集群管理器,可以有效地共享资源,支持容器化应用程序和传统应用程序的统一管理。

  4. Amazon ECS: Amazon Elastic Container Service(ECS)是 Amazon Web Services(AWS)提供的托管式容器编排服务,可在 AWS 云环境中部署和管理容器化应用。

  5. HashiCorp Nomad: Nomad 是 HashiCorp 提供的轻量级和灵活的集群编排工具,支持多种应用类型(包括容器、虚拟机和传统应用程序)的调度和管理。

  6. OpenShift: Red Hat 的 OpenShift 是一个基于 Kubernetes 的容器应用平台,提供开发、部署和管理容器化应用的工具和服务。

  7. Rancher: Rancher 是一个开源的容器管理平台,支持多个容器编排引擎(如 Kubernetes、Docker Swarm 和 Mesos),以及集成的管理和监控功能。

  8. Portainer: Portainer 是一个图形化的管理工具,用于管理 Docker 容器和集群,提供用户友好的界面和操作。

  9. Marathon: Marathon 是 Apache Mesos 生态系统中的一个编排工具,专门用于管理长时间运行的服务和任务。

# 3.公有云

公有云是最常见的云计算部界类型。公有云资源(例如服务器和存储空间)由第三方云服务提供商拥有和运营,这些资源通过 Internet 提供。在公有云中,所有硬件、软件和其他支持性基础结构均为云提供商所拥有和管理。Microsoft Azure 是公有云的一个示例。在公有云中,你与其他组织或云“租户”共享相同的硬件、存储和网络设备,并且你可以使用 Web 浏览器访问服务和管理帐户,公有云部署通常用于提供基于 Web 的电子邮件、网上办公应用、存储以及测试和开发环境。 公有云优势:

  • 成本更低: 无需购买硬件或软件,仅对使用的服务付费。
  • 无需维护: 维护由服务提供商提供。
  • 近乎无限制的缩放性: 提供按需资源,可满足业务需求。
  • 高可靠性: 具备众多服务器,确保免受故障影响。

# 4.私有云

自己搭建云平台,或者购买:私有云由专供一个企业或组织使用的云计算资源构成。私有云可在物理上位于组织的现场数据中心,也可由第三方服务提供商托管。但是,在私有云中,服务和基础结构始终在私有网络上进行维护,硬件和软件专供组织使用。 这样,私有云可使组织更加方便地自定义资源,从而满足特定的 IT 需求,私有云的使用对象近常为政府机构、金融机构以及其他具备业务关键性运营且希望对环境拥有更大控制权的中型到大型组织。 私有云优势:

  • 灵活性更强: 组织可自定义云环境以满足特定业务需求
  • 控制力更强: 资源不与其他组织共享,因此能获得更高的控制力以及更高的隐私级别。
  • 可伸缩性更强: 与本地基础结构相比,私有云通常具有更强的可伸缩性。

# 5.VPC

image-20230308150339278

# 6.容器编排区别

Features 特性 Kubernetes Docker Swarm
安装和集群配置 安装很复杂;但是一旦安装完毕,集群就非常强大 安装非常简单;但是集群不是很强大
图形用户界面
可伸缩性 高可伸缩性和快速扩展 高度可伸缩&比 Kubernetes 快 5 倍
自动伸缩 可以进行自动缩放 不能自动缩放
负载均衡 为了在不同的 Pods 中的不同容器之间平衡负载流量,需要手动干预 可以自动平衡集群中容器之间的流量
滚动更新回滚 可以部署滚动更新 可以部署滚动更新,但不能自动回滚
数据量 可以共享存储卷。只能与其他集装箱在同一 Pod 可以与任何其他容器共享存储卷。
日志记录和监控 内置的日志和监控工具 应该使用像 ELK 这样的第三方工具进行日志记录和监控

# 7.为什么使用 k8s

k8s 是一个开源的容器集群管理系统,可以实现容器集群的自动化部署、自动扩缩容、维护等功能。

  • 故障迁移:当某一个 node 节点关机或挂掉后,node 节点上的服务会自动转移到另一个 node 节点上,这个过程所有服务不中断。这是 docker 或普通云主机是不能做到的

  • 资源调度:当 node 节点上的 cpu、内存不够用的时候,可以扩充 node 节点,新建的 pod 就会被 kube-schedule 调度到新扩充的 node 节点上

  • 资源隔离:创建开发、运维、测试三个命名空间,切换上下文后,开发人员就只能看到开发命名空间的所有 pod,看不到运维命名空间的 pod,这样就不会造成影响,互不干扰,传统的主机或只有 docker 环境中,登录进去就会看到所有的服务或者容器,因为采用 docker 容器,进程之间互不影响,

  • 安全:不同角色有不同的权限,查看 pod、删除 pod 等操作;RBAC 认证增加了 k8s 的安全

  • 快速精准地部署应用程序,限制硬件用量仅为所需资源

Kubernetes 的优势

  • 可移动: 公有云、私有云、混合云、多态云
  • 可扩展: 模块化、插件化、可挂载、可组合
  • 自修复: 自动部署、自动重启、自动复制、自动伸缩

k8s 可以更快的更新新版本,打包应用,更新的时候可以做到不用中断服务,服务器故障不用停机,从开发环境到测试环境到生产环境的迁移极其方便,一个配置文件搞定,一次生成 image,到处运行。

# 二.Kubernetes 介绍

# 1.Kubernetes 是什么?

Kubernetes(K8S)是 Google 在 2014 年发布的一个开源项目,用于自动化容器化应用程序的部署、扩展和管理,Kubernetes 通常结合 docker 容器工作,并且整合多个运行着 docker 容器的主机集群。

Kubernetes 的目标是让部署容器化的应用简单并目高效,Kubernetes 一个核心特点就是能够自主的管理容器来保证云平台中的容器按照用户的期望运行。

官网地址 (opens new window)

中文社区 (opens new window)

# 2.Kubernetes 作用?

kubernetes 的本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理。目的是实现资源管理的自动化,主要提供了如下的主要功能:

  • 自我修复:一旦某一个容器崩溃,能够在 1 秒中左右迅速启动新的容器
  • 弹性伸缩:可以根据需要,自动对集群中正在运行的容器数量进行调整
  • 服务发现:服务可以通过自动发现的形式找到它所依赖的服务
  • 负载均衡:如果一个服务起动了多个容器,能够自动实现请求的负载均衡
  • 版本回退:如果发现新发布的程序版本有问题,可以立即回退到原来的版本
  • 存储编排:可以根据容器自身的需求自动创建存储卷

# 3.kubernetes 组件

kubernetes 概念

  • Master:集群控制节点,每个集群需要至少一个 master 节点负责集群的管控
  • Node:工作负载节点,由 master 分配容器到这些 node 工作节点上,然后 node 节点上的 docker 负责容器的运行
  • Pod:kubernetes 的最小控制单元,容器都是运行在 pod 中的,一个 pod 中可以有 1 个或者多个容器
  • Controller:控制器,通过它来实现对 pod 的管理,比如启动 pod、停止 pod、伸缩 pod 的数量等等
  • Service:pod 对外服务的统一入口,service 可以维护同一类的多个 pod
  • Label:标签,用于对 pod 进行分类,同一类 pod 会拥有相同的标签
  • NameSpace:命名空间,用来隔离 pod 的运行环境

# 4.集群类型

Kubernetes 集群大致分为两类:一主多从多主多从

  • 一主多从:一个 Master 节点和多台 Node 节点,搭建简单,但是有单机故障风险,适合用于测试环境。
  • 多主多从:多台 Master 和多台 Node 节点,搭建麻烦,安全性高,适合用于生产环境

image-20230315162532291

# 5.管理集群方式

kubernetes 中管理集群中资源的方式通常有四种:

  • 命令行
  • YAML
  • API
  • dashboard 图形界面

其中 dashboard 是 K8s 官方的图形界面工具。使用简单,操作方便,能监控 nodepod 等。

# 6.资源管理方式

  • 命令式对象管理:直接使用命令去操作 kubernetes 资源
  • 配置文件式对象配置:通过命令配置和配置文件去操作 kubernetes 资源
  • 声明式对象配置:通过 apply 命令和配置文件去操作 kubernetes 资源
#命令式对象配置
kubectl run nginx-pod --image=nginx:1.17.1 --port=80

#配置文件式对象配置
kubectl create/patch -f nginx-pod.yaml

#声明式对象配置
kubectl apply -f nginx-pod.yaml
1
2
3
4
5
6
7
8
类型 操作对象 适用环境 优点 缺点
命令式对象管理 对象 测试 简单 只能操作活动对象,无法审计、跟踪
命令式对象配置 文件 开发 可以审计、跟踪 项目大时,配置文件多,操作麻烦
声明式对象配置 目录 开发 支持目录操作 意外情况下难以调试

# 7.工作负载方式

  • Deployment:无状态应用部署,比如微服务,提供多副本等功能
  • StatefulSet:有状态应用部警,比如 redis,提供稳定的存储、网络等功能
  • DaemonSet:守护型应用部羿,比如日志收集组件,在每个机器都运行一份
  • Job/CronJob:定时任务部署,比如垃圾清理组件,可以在指定时间运行

# 8.k8s 资源管理?

Kubernetes 的本质就是一个集群系统,用户可以在集群中部署各种服务。所谓的部署服务,其实就是在 Kubernetes 集群中运行一个个的容器,并将指定的程序跑在容器中。 Kubernetes 的最小管理单元是 Pod 而不是容器,所以只能将容器放在 Pod 中,而 Kubernetes 一般也不会直接管理 Pod ,而是通过 Pod 控制器来管理 Pod 的。 Pod 提供服务之后,就需要考虑如何访问 Pod 中的服务,Kubernetes 提供了 Service 资源实现这个功能。 当然,如果 Pod 中程序的数据需要持久化,Kubernetes 还提供了各种存储系统。

image-20230820161447731

# 9.kubernetes 架构

一个 kubernetes 集群主要是由控制节点(master)、**工作节点(node)**构成,每个节点上都会安装不同的组件。

工作方式:

Kubernetes Cluster = N Master Node + N Worker Node:N 主节点+N 工作节点; N>=1

image-20230308151556317

image-20230308170440354

# 10.kubernetes 组件

  • master集群的控制平面,负责集群的决策 ( 管理 )
    • ApiServer : 资源操作的唯一入口,接收用户输入的命令,提供认证、授权、API 注册和发现等机制
    • Scheduler : 负责集群资源调度,按照预定的调度策略将 Pod 调度到相应的 node 节点上
    • ControllerManager : 负责维护集群的状态,比如程序部署安排、故障检测、自动扩展、滚动更新等
    • Etcd :负责存储集群中各种资源对象的信息
  • node集群的数据平面,负责为容器提供运行环境 ( 干活 )
    • Kubelet : 负责维护容器的生命周期,即通过控制 docker,来创建、更新、销毁容器
    • KubeProxy : 负责提供集群内部的服务发现和负载均衡
    • Docker : 负责节点上容器的各种操作

image-20230820162122080

# 11.Node 组件

节点组件在每个节点上运行,维护运行的 Pod 并提供 Kubernetes 运行环境。

kubelet:一个在集群中每个节点 node 上运行的代理。 它保证容器 containers 都 运行在 Pod 中。

kubelet 接收一组通过各类机制提供给它的 PodSpecs,确保这些 PodSpecs 中描述的容器处于运行状态且健康。 kubelet 不会管理不是由 Kubernetes 创建的容器。

kube-proxy:``kube-proxy 是集群中每个节点上运行的网络代理, 实现 Kubernetes 服务 Service 概念的一部分。

kube-proxy维护节点上的网络规则。这些网络规则允许从集群内部或外部的网络会话与 Pod 进行网络通信。

如果操作系统提供了数据包过滤层并可用的话,kube-proxy 会通过它来实现网络规则。否则, kube-proxy仅转发流量本身。

# 12.Namespace 资源操作

Namespacekubernetes 系统中的一种非常重要资源,它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离

默认情况下,kubernetes 集群中的所有的 Pod 都是可以相互访问的。但是在实际中,可能不想让两个 Pod 之间进行互相的访问,那此时就可以将两个 Pod 划分到不同的 namespace 下。kubernetes 通过将集群内部的资源分配到不同的 Namespace 中,可以形成逻辑上的"组",以方便不同的组的资源进行隔离使用和管理。

可以通过 kubernetes 的授权机制,将不同的 namespace 交给不同租户进行管理,这样就实现了多租户的资源隔离。此时还能结合 kubernetes 的资源配额机制,限定不同租户能占用的资源,例如 CPU 使用量、内存使用量等等,来实现租户可用资源的管理。

kubernetes 在集群启动之后,会默认创建几个 namespace

[root@master ~]# kubectl  get namespace
NAME              STATUS   AGE
default           Active   45h     #  所有未指定Namespace的对象都会被分配在default命名空间
kube-node-lease   Active   45h     #  集群节点之间的心跳维护,v1.13开始引入
kube-public       Active   45h     #  此命名空间下的资源可以被所有人访问(包括未认证用户)
kube-system       Active   45h     #  所有由Kubernetes系统创建的资源都处于这个命名空间
1
2
3
4
5
6

namespace相关命令

#查看所有的ns
kubectl get ns

#查看指定的ns
kubectl get ns ns名称

#指定输出格式  命令:kubectl get ns ns名称  -o 格式参数
#kubernetes支持的格式有很多,比较常见的是wide、json、yaml
kubectl get ns default -o yaml

#查看ns详情  命令:
kubectl describe ns ns名称
1
2
3
4
5
6
7
8
9
10
11
12

# 三.pod 详解

# 1.Pod 介绍

  • Pod 是 kubernetes 集群进行管理的最小单元,程序要运行必须部署在容器中,而容器必须存在于 Pod 中。
  • Pod 可以认为是容器的封装,一个 Pod 中可以存在一个或者多个容器。

容器的本质是系统中的一个进程:在 k8s 中不再按照传统思维的将容器作为调度单位,kubernetes 中的项目调度器是统一按照 pod 的资源需求做调度计算,也就是开始总结的那句话: pod 是 kubernetes 项目的原子调度单位

pod结构:

image-20230820163618094

如图所示,一个 pod 包含了两类容器:

  • 用户容器
  • Pause 容器,也常常被称为“根容器”(老版本叫做 infra 容器)

pause 容器主要为每个用户容器提供以下功能:

  1. PID 命名空间:Pod 中的不同应用程序可以看到其他应用程序的进程 ID。

  2. 网络命名空间:Pod 中的多个容器能够访问同一个 IP 和端口范围。

  3. IPC 命名空间:Pod 中的多个容器能够使用 SystemV IPC 或 POSIX 消息队列进行通信。

  4. UTS 命名空间:Pod 中的多个容器共享一个主机名。

  5. Volumes(共享存储卷):Pod 中的各个容器可以访问在 Pod 级别定义的 Volumes。

kubernetes 在集群启动之后,集群中的各个组件也都是以 Pod 方式运行的。可以通过下面命令查看:

#指定命名空间
kubectl get pod -n kube-system

#使用watch命令监视pod状态
watch -n 1 kubectl get pod

#查看Pod详细信息
kubectl get pod -owide
1
2
3
4
5
6
7
8

# 2.pod 实现原理

在一个 pod 中所有容器是共享一个 Network Namespace的,根据声明的不同来实现不同的资源共享,但是容器间的复杂关系在容器上难以解决,所以 kubernetes 项目里,pod 的实现借用了一个中间容器,也就是常常说的根容器。在 pod 中,根容器永远是第一个创建的容器,用户后面定义的容器会加入进 pod 的 Network Namespace,从而在视图上容器都在 pod 里。pause 镜像大小只有 683k,它是由汇编语言写的镜像。

pod原理总结:

  • pod 内的容器可以使用 localhost 进行通信
  • 根容器能看到的网络资源,其他容器都能看到,也就是 pod 的网络资源和 pod 内的容器共享
  • 一个 pod 有一个 ip 地址,和 pod 对应的 Network namespace 的 ip 一致
  • pod 的生命周期只与根容器有关,与 pod 内的容器无关
  • 从 pod 里的容器的视角来说,它们的流量进出可以看做是通过根容器完成的

# 3.复制控制器

复制控制器(Replication Controller,RC)

通常我们在 k8s 集群里面会有成千上百个 pod,那么对于 pod 的管理也是需要有一定的机制,k8s 内部有个叫做RC(Replication Controller) 的复制控制器。

RC 主要的是监控 pod 节点的数目,当我们在启动 pod 的时候希望有多个 pod 副本,可以使用 RC 来控制启动的数目,如果期间有部分 pod 挂掉了,RC 会自动进行重启 pod。

image-20230313233039676

# 4.pod 定义

apiVersion: v1     #必选,版本号,例如v1
kind: Pod         #必选,资源类型,例如 Pod
metadata:         #必选,元数据
  name: string     #必选,Pod名称
  namespace: string  #Pod所属的命名空间,默认为"default"
  labels:           #自定义标签列表
    - name: string       
spec:  #必选,Pod中容器的详细定义
  containers:  #必选,Pod中容器列表
  - name: string   #必选,容器名称
    image: string  #必选,容器的镜像名称
    imagePullPolicy: [ Always|Never|IfNotPresent ]  #获取镜像的策略
    command: [string]   #容器的启动命令列表,如不指定,使用打包时使用的启动命令
    args: [string]      #容器的启动命令参数列表
    workingDir: string  #容器的工作目录
    volumeMounts:       #挂载到容器内部的存储卷配置
    - name: string      #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
      mountPath: string #存储卷在容器内mount的绝对路径,应少于512字符
      readOnly: boolean #是否为只读模式
    ports: #需要暴露的端口库号列表
    - name: string        #端口的名称
      containerPort: int  #容器需要监听的端口号
      hostPort: int       #容器所在主机需要监听的端口号,默认与Container相同
      protocol: string    #端口协议,支持TCP和UDP,默认TCP
    env:   #容器运行前需设置的环境变量列表
    - name: string  #环境变量名称
      value: string #环境变量的值
    resources: #资源限制和请求的设置
      limits:  #资源限制的设置
        cpu: string     #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
        memory: string  #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
      requests: #资源请求的设置
        cpu: string    #Cpu请求,容器启动的初始可用数量
        memory: string #内存请求,容器启动的初始可用数量
    lifecycle: #生命周期钩子
        postStart: #容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
        preStop: #容器终止前执行此钩子,无论结果如何,容器都会终止
    livenessProbe:  #对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器
      exec:         #对Pod容器内检查方式设置为exec方式
        command: [string]  #exec方式需要制定的命令或脚本
      httpGet:       #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
        path: string
        port: number
        host: string
        scheme: string
        HttpHeaders:
        - name: string
          value: string
      tcpSocket:     #对Pod内个容器健康检查方式设置为tcpSocket方式
         port: number
       initialDelaySeconds: 0       #容器启动完成后首次探测的时间,单位为秒
       timeoutSeconds: 0          #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
       periodSeconds: 0           #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
       successThreshold: 0
       failureThreshold: 0
       securityContext:
         privileged: false
  restartPolicy: [Always | Never | OnFailure]  #Pod的重启策略
  nodeName: <string> #设置NodeName表示将该Pod调度到指定到名称的node节点上
  nodeSelector: obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上
  imagePullSecrets: #Pull镜像时使用的secret名称,以key:secretkey格式指定
  - name: string
  hostNetwork: false   #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
  volumes:   #在该pod上定义共享存储卷列表
  - name: string    #共享存储卷名称 (volumes类型有很多种)
    emptyDir: {}       #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
    hostPath: string   #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
      path: string                #Pod所在宿主机的目录,将被用于同期中mount的目录
    secret:          #类型为secret的存储卷,挂载集群与定义的secret对象到容器内部
      scretname: string
      items:
      - key: string
        path: string
    configMap:         #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
      name: string
      items:
      - key: string
        path: string
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

在这里,可通过一个命令来查看每种资源的可配置项

#查看某种资源可以配置的一级属性
kubectl explain 资源类型

#查看属性的子属性
kubectl explain 资源类型.属性
1
2
3
4
5

在 kubernetes 中基本所有资源的一级属性都是一样的,主要包含 5 部分:

  • apiVersion 版本,由 kubernetes 内部定义,版本号必须可以用 kubectl api-versions 查询到
  • kind 类型,由 kubernetes 内部定义,版本号必须可以用 kubectl api-resources 查询到
  • metadata 元数据,主要是资源标识和说明,常用的有 name、namespace、labels 等
  • spec 描述,这是配置中最重要的一部分,里面是对各种资源配置的详细描述
  • status状态信息,里面的内容不需要定义,由 kubernetes 自动生成

# 5.containers 属性

pod.spec.containers属性,这也是 pod 配置中最为关键的一项配置。

[root@k8s-master ~]# kubectl explain pod.spec.containers
KIND:     Pod
VERSION:  v1
RESOURCE: containers <[]Object>   #数组,代表可以有多个容器
FIELDS:
   name  <string>     	# 容器名称
   image <string>     	# 容器需要的镜像地址
   imagePullPolicy  <string> # 镜像拉取策略
   command  <[]string> # 容器的启动命令列表,如不指定,使用打包时使用的启动命令
   args     <[]string> # 容器的启动命令需要的参数列表
   env      <[]Object> # 容器环境变量的配置
   ports    <[]Object>     # 容器需要暴露的端口号列表
   resources <Object>      # 资源限制和资源请求的设置
1
2
3
4
5
6
7
8
9
10
11
12
13

创建pod-base.yaml文件,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-base
  namespace: dev
  labels:
    user: xxx
spec:
  containers:
    - name: nginx
      image: nginx:1.17.1
    - name: busybox
      image: busybox:1.30
1
2
3
4
5
6
7
8
9
10
11
12
13
# 创建Pod
[root@k8s-master ~]# kubectl apply -f pod-base.yml
pod/pod-base created

# 查看Pod状况
# READY 1/2 : 表示当前Pod中有2个容器,其中1个准备就绪,1个未就绪
# RESTARTS  : 重启次数,因为有1个容器故障了,Pod一直在重启试图恢复它
[root@k8s-master ~]# kubectl get pod -n dev
NAME                     READY   STATUS             RESTARTS   AGE
nginx                    1/1     Running            0          2d17h
nginx-78f678f57f-q5l5r   1/1     Running            0          2d13h
nginx-78f678f57f-tk85k   1/1     Running            0          2d13h
nginx-78f678f57f-wcxgv   1/1     Running            0          2d13h
pod-base                 1/2     CrashLoopBackOff   3          90s

# 可以通过describe查看内部的详情
# 此时已经运行起来了一个基本的Pod,虽然它暂时有问题
[root@k8s-master ~]# kubectl describe pod pod-base -n dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 6.镜像拉取

创建pod-imagepullpolicy.yaml文件,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-imagepullpolicy
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    imagePullPolicy: Never # 用于设置镜像拉取策略
  - name: busybox
    image: busybox:1.30
1
2
3
4
5
6
7
8
9
10
11
12

imagePullPolicy,用于设置镜像拉取策略,kubernetes 支持配置三种拉取策略:

  • Always:总是从远程仓库拉取镜像

  • IfNotPresent:本地有则使用本地镜像,本地没有则从远程仓库拉取镜像

  • Never:只使用本地镜像,从不去远程仓库拉取,本地没有就报错

  • 默认值说明:

    • 如果镜像 tag 为具体版本号, 默认策略是:IfNotPresent

    • 如果镜像 tag 为:latest(最终版本) ,默认策略是 always

# 创建Pod
[root@k8s-master ~]# kubectl apply -f pod-imagepullpolicy.yaml
pod/pod-imagepullpolicy created
[root@k8s-master ~]# kubectl get pod -n dev
NAME                     READY   STATUS              RESTARTS   AGE
nginx                    1/1     Running             0          2d17h
nginx-78f678f57f-q5l5r   1/1     Running             0          2d13h
nginx-78f678f57f-tk85k   1/1     Running             0          2d13h
nginx-78f678f57f-wcxgv   1/1     Running             0          2d13h
pod-base                 1/2     CrashLoopBackOff    7          12m
pod-imagepullpolicy      0/2     ContainerCreating   0          16s

# 查看Pod详情
# 此时明显可以看到nginx镜像有一步Pulling image "busybox:1.30"的过程
[root@k8s-master ~]# kubectl describe pod pod-imagepullpolicy -n dev
....
Events:
  Type     Reason     Age                From                Message
  ----     ------     ----               ----                -------
  Normal   Scheduled  80s                default-scheduler   Successfully assigned dev/pod-imagepullpolicy to k8s-node1
  Normal   Pulled     79s                kubelet, k8s-node1  Container image "nginx:1.17.1" already present on machine
  Normal   Created    79s                kubelet, k8s-node1  Created container nginx
  Normal   Started    79s                kubelet, k8s-node1  Started container nginx
  Normal   Pulling    79s                kubelet, k8s-node1  Pulling image "busybox:1.30"
  Normal   Pulled     63s                kubelet, k8s-node1  Successfully pulled image "busybox:1.30"
  Normal   Created    21s (x4 over 63s)  kubelet, k8s-node1  Created container busybox
  Normal   Started    21s (x4 over 63s)  kubelet, k8s-node1  Started container busybox
  Normal   Pulled     21s (x3 over 62s)  kubelet, k8s-node1  Container image "busybox:1.30" already present on machine
  Warning  BackOff    7s (x6 over 61s)   kubelet, k8s-node1  Back-off restarting failed container
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 7.启动命令

容器初始化完毕之后运行一个命令,这就用到了 command 配置。

创建pod-command.yaml文件,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-command
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done;"]
1
2
3
4
5
6
7
8
9
10
11
12

command,用于在 pod 中的容器初始化完毕之后运行一个命令。

# 创建Pod
[root@k8s-master ~]# kubectl apply -f pod-imagepullpolicy.yaml
pod/pod-imagepullpolicy created
[root@k8s-master ~]# ls
calico.yaml  deploy-nginx.yaml  kube-flannel.yml  kube-flannel.yml.bak  mak.sh  nginxpod.yaml  pod-base.yml  pod-command.yaml  pod-imagepullpolicy.yaml  pod-nginx.yaml  pu1.sh  svc-nginx.yaml

# 查看Pod状态
# 此时发现两个pod都正常运行了
[root@k8s-master ~]# kubectl get pod -n dev
NAME                     READY   STATUS             RESTARTS   AGE
pod-command              2/2     Running            0          40s


# 进入pod中的busybox容器,查看文件内容
# 补充一个命令: kubectl exec  pod名称 -n 命名空间 -it -c 容器名称 /bin/sh  在容器内部执行命令
# 使用这个命令就可以进入容器的内部,然后进行相关操作了
# 比如,可以查看txt文件的内容
[root@k8s-master ~]# kubectl exec pod-command -n dev -it -c busybox /bin/sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 8.环境变量

创建pod-env.yaml文件,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-env
  namespace: dev
spec:
  containers:
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","while true;do /bin/echo $(date +%T);sleep 60; done;"]
    env: # 设置环境变量列表
    - name: "username"
      value: "admin"
    - name: "password"
      value: "123456"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

env,环境变量,用于在 pod 中的容器设置环境变量。

这种方式不是很推荐,推荐将这些配置单独存储在配置文件中,也就是 configMap 中.

# 9.设置端口

容器的端口设置,也就是containers的 ports 选项。首先看下 ports 支持的子选项:

[root@k8s-master ~]# kubectl explain pod.spec.containers.ports
KIND:     Pod
VERSION:  v1
RESOURCE: ports <[]Object>
FIELDS:
   name         <string>  # 端口名称,如果指定,必须保证name在pod中是唯一的
   containerPort<integer> # 容器要监听的端口(0<x<65536)
   hostPort     <integer> # 容器要在主机上公开的端口,如果设置,主机上只能运行容器的一个副本(一般省略)
   hostIP       <string>  # 要将外部端口绑定到的主机IP(一般省略)
   protocol     <string>  # 端口协议。必须是UDP、TCP或SCTP。默认为“TCP”。
1
2
3
4
5
6
7
8
9
10

接下来,编写一个测试案例,创建pod-ports.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-ports
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports: # 设置容器暴露的端口列表
    - name: nginx-port
      containerPort: 80
      protocol: TCP
1
2
3
4
5
6
7
8
9
10
11
12
13
[root@k8s-master ~]# kubectl create -f pod-ports.yaml
pod/pod-ports created

[root@k8s-master ~]# kubectl get pod pod-ports -n dev -o yaml
....
spec:
  containers:
  - image: nginx:1.17.1
    imagePullPolicy: IfNotPresent
    name: nginx
    ports:
    - containerPort: 80
      name: nginx-port
      protocol: TCP
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-wmpvr
      readOnly: true
....
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

访问容器中的程序需要使用的是Podip:containerPort

# 10.资源配额

容器中的程序要运行,肯定是要占用一定资源的,比如 cpu 和内存等,如果不对某个容器的资源做限制,那么它就可能吃掉大量资源,导致其它容器无法运行。针对这种情况,kubernetes 提供了对内存和 cpu 的资源进行配额的机制,这种机制主要通过 resources 选项实现,他有两个子选项:

  • limits:用于限制运行时容器的最大占用资源,当容器占用资源超过 limits 时会被终止,并进行重启
  • requests :用于设置容器需要的最小资源,如果环境资源不够,容器将无法启动

可以通过上面两个选项设置资源的上下限。

接下来,编写一个测试案例,创建pod-resources.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-resources
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    resources: # 资源配额
      limits:  # 限制资源(上限)
        cpu: "2" # CPU限制,单位是core数
        memory: "10Gi" # 内存限制
      requests: # 请求资源(下限)
        cpu: "1"  # CPU限制,单位是core数
        memory: "10Mi"  # 内存限制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

在这对 cpu 和 memory 的单位做一个说明:

  • cpu:core 数,可以为整数或小数
  • memory: 内存大小,可以使用 Gi、Mi、G、M 等形式
# 运行Pod
[root@k8s-master ~]# kubectl create  -f pod-resources.yaml
pod/pod-resources created

# 查看发现pod运行正常
[root@k8s-master ~]# kubectl get pod pod-resources -n dev
NAME            READY   STATUS    RESTARTS   AGE
pod-resources   1/1     Running   0          39s

# 接下来,停止Pod
[root@k8s-master ~]# kubectl delete  -f pod-resources.yaml
pod "pod-resources" deleted

# 编辑pod,修改resources.requests.memory的值为10Gi
[root@k8s-master ~]# vim pod-resources.yaml

# 再次启动pod
[root@k8s-master ~]# kubectl create  -f pod-resources.yaml
pod/pod-resources created

# 查看Pod状态,发现Pod启动失败
[root@k8s-master ~]# kubectl get pod pod-resources -n dev -o wide
NAME            READY   STATUS    RESTARTS   AGE
pod-resources   0/1     Pending   0          20s

# 查看pod详情会发现,如下提示
[root@k8s-master ~]# kubectl describe pod pod-resources -n dev
......
Warning  FailedScheduling  48s (x2 over 48s)  default-scheduler  0/3 nodes are available: 3
Insufficient memory.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 11.Pod 生命周期

我们一般将 pod 对象从创建至终的这段时间范围称为 pod 的生命周期,它主要包含下面的过程:

  • pod 创建过程

  • 运行初始化容器(init container)过程

  • 运行主容器(main container)

    • 容器启动后钩子(post start)、容器终止前钩子(pre stop)

    • 容器的存活性探测(liveness probe)、就绪性探测(readiness probe)

  • pod 终止过程

image-20230315185339156

在整个生命周期中,Pod 会出现 5 种状态相位),分别如下:

  • 挂起(Pending):apiserver 已经创建了 pod 资源对象,但它尚未被调度完成或者仍处于下载镜像的过程中
  • 运行中(Running):pod 已经被调度至某节点,并且所有容器都已经被 kubelet 创建完成
  • 成功(Succeeded):pod 中的所有容器都已经成功终止并且不会被重启
  • 失败(Failed):所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非 0 值的退出状态
  • 未知(Unknown):apiserver 无法正常获取到 pod 对象的状态信息,通常由网络通信失败所导致

创建和终止

pod 的创建过程

  1. 用户通过 kubectl 或其他 api 客户端提交需要创建的 pod 信息给 apiServer
  2. apiServer 开始生成 pod 对象的信息,并将信息存入 etcd,然后返回确认信息至客户端
  3. apiServer 开始反映 etcd 中的 pod 对象的变化,其它组件使用 watch 机制来跟踪检查 apiServer 上的变动
  4. scheduler 发现有新的 pod 对象要创建,开始为 Pod 分配主机并将结果信息更新至 apiServer
  5. node 节点上的 kubelet 发现有 pod 调度过来,尝试调用 docker 启动容器,并将结果回送至 apiServer
  6. apiServer 将接收到的 pod 状态信息存入 etcd 中

pod 的终止过程

  1. 用户向 apiServer 发送删除 pod 对象的命令
  2. apiServcer 中的 pod 对象信息会随着时间的推移而更新,在宽限期内(默认 30s),pod 被视为 dead
  3. 将 pod 标记为 terminating 状态
  4. kubelet 在监控到 pod 对象转为 terminating 状态的同时启动 pod 关闭过程
  5. 端点控制器监控到 pod 对象的关闭行为时将其从所有匹配到此端点的 service 资源的端点列表中移除
  6. 如果当前 pod 对象定义了 preStop 钩子处理器,则在其标记为 terminating 后即会以同步的方式启动执行
  7. pod 对象中的容器进程收到停止信号
  8. 宽限期结束后,若 pod 中还存在仍在运行的进程,那么 pod 对象会收到立即终止的信号
  9. kubelet 请求 apiServer 将此 pod 资源的宽限期设置为 0 从而完成删除操作,此时 pod 对于用户已不可见

# 12.重启策略

一旦容器探测出现了问题,kubernetes 就会对容器所在的 Pod 进行重启,其实这是由 pod 的重启策略决定的,pod 的重启策略有 3 种,分别如下:

  • Always :容器失效时,自动重启该容器,这也是默认值。
  • OnFailure : 容器终止运行且退出码不为 0 时重启
  • Never : 不论状态为何,都不重启该容器

重启策略适用于 pod 对象中的所有容器,首次需要重启的容器,将在其需要时立即进行重启,随后再次需要重启的操作将由 kubelet 延迟一段时间后进行,且反复的重启操作的延迟时长以此为 10s、20s、40s、80s、160s 和 300s,300s 是最大延迟时长。

apiVersion: v1
kind: Pod
metadata:
  name: pod-restartpolicy
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      httpGet:
        scheme: HTTP
        port: 80
        path: /hello
  restartPolicy: Never # 设置重启策略为Never
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 13.创建并运行 pod

配置文件方式:

  • 创建:kubectl create -f pod-nginx.yaml
  • 删除:kubectl delete -f pod-nginx.yaml

命令方式:

kubectl run (pod控制器名称) [参数] --image 指定 Pod 的镜像 --port 指定端口 --namespace 指定 namespace


[root@master ~]# kubectl run nginx --image=nginx:latest --port=80 --namespace dev
deployment.apps/nginx created
1
2
3
#查看 pod 信息
[root@k8s-master ~]# kubectl get pods -n dev
NAME       READY   STATUS    RESTARTS   AGE
nginx      1/1     Running   0          8m58s
nginxpod   1/1     Running   0          5h47m

#查看Pod的详细信息
kubectl describe pod nginx -n namespace
1
2
3
4
5
6
7
8

# 14.进入容器

#获取podIP
kubectl get pod -owide -n 命名空间

#访问POD
kubectl exec -it 容器名称 -n 命名空间 bash
1
2
3
4
5

# 15.删除 pod

#删除指定Pod
kubectl delete pod 容器名称 -n 命名空间
1
2
# 删除指定Pod
[root@k8s-master ~]# kubectl delete pod nginx -n dev
pod "nginx" deleted

# 此时,显示删除Pod成功,但是再查询,发现又新产生了一个
[root@k8s-master ~]# kubectl get pods -n dev
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          21s

# 这是因为当前Pod是由Pod控制器创建的,控制器会监控Pod状况,一旦发现Pod死亡,会立即重建
# 此时要想删除Pod,必须删除Pod控制器

# 先来查询一下当前namespace下的Pod控制器
[root@k8s-master ~]# kubectl get deploy -n  dev
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           9m7s

# 接下来,删除此PodPod控制器
[root@k8s-master ~]# kubectl delete deploy nginx -n dev
deployment.apps "nginx" deleted

# 稍等片刻,再查询Pod,发现Pod被删除了
[root@k8s-master ~]# kubectl get pods -n dev
No resources found in dev namespace.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 16.Pod status 状态解释

错误英文 中文
CrashLoopBackOff 容器退出,kubelet 正在将它重启
InvalidImageName 无法解析镜像名称
ImageInspectError 无法校验镜像
ErrImageNeverPull 策略禁止拉取镜像
ImagePullBackOff 镜像正在重试拉取
RegistryUnavailable 连接不到镜像中心
ErrImagePull 通用的拉取镜像出错
CreateContainerConfigError 不能创建 kubelet 使用的容器配置
CreateContainerError 创建容器失败
m.internalLifecycle.PreStartContainer 执行 hook 报错
RunContainerError 启动容器失败
PostStartHookError 执行 hook 报错
ContainersNotInitialized 容器没有初始化完毕
ContainersNotReady 容器没有准备完毕
ContainerCreating 容器创建中
PodInitializing pod 初始化中
DockerDaemonNotReady docker 还没有完全启动
NetworkPluginNotReady 网络插件还没有完全启动

# 四.Label 和 Pod 控制器

# 1.labels

Label 是 kubernetes 系统中的一个重要概念。它的作用就是在资源上添加标识,用来对它们进行区分和选择。

Label 的特点:

  • 一个 Label 会以 key/value 键值对的形式附加到各种对象上,如 Node、Pod、Service 等等
  • 一个资源对象可以定义任意数量的 Label ,同一个 Label 也可以被添加到任意数量的资源对象上去
  • Label 通常在资源对象定义时确定,当然也可以在对象创建后动态添加或者删除

labels 标签,在 kubernetes 我们会经常见到,它的功能非常关键,就相关于服务 pod 的身份证信息,如果我们创建一个 deployment 资源,它之所有能守护下面启动的 N 个 pod 以达到期望的数据,service 之所以能把流量准确无误的转发到指定的 pod 上去,归根结底都是 labels 在这里起作用.

labels 受 namespace 管控,在同一个 namespace 下面的服务 labels,如果只有一个,就需要注意其唯一性,不要有重复的存在,不然服务就会跑串,出现一些奇怪的现象,我们在资源中可以配置多个 lables 来一起组合使用,这样就会大大降低重复的情况了。

# 2.lable 作用

  • 标签是一种简单却功能强大的 Kubernetes 特性,不仅可以组织 pod,也可以组织所有其他的 Kubernetes 资源
  • 详细来讲,标签是可以附加到资源的任意键值对,用以选择具有该确切标签的资源(这是通过标签选 择器完成的)
  • 只要标签的key 在资源内是唯一的,一个资源便可以拥有多个标签
  • 通常在我们创建资源时就会将标签附加到资源上,但之后我们也可以再添加其他标签,或者修改现有标签的值,而无须重新创建资源

通过给这些 pod 添加标签,可以得到一个更组织化的系统,以便我们理解。

此时每个 pod 都标有两个标签:

  • **app,**它指定 pod 属于哪个应用、组件或微服务
  • **rel,**它显示在 pod 中运行的应用程序版本是 stable、beta 还是 canary

# 3.Label 命令

#查看所有pod的标签:
kubectl get pod --show-labels

#查看单个pod的标签:
kubectl get pod redis --show-labels

#查看namespaces下所有pod的标签:
kubectl get pod --all-namespaces --show-labels

#列出标签key是db的Pod
kubectl get pod -l db

#使用标签检索Pod
kubectl get pod -l app=my-dep

#列出带key是db、值redis的标签
kubectl get pod -l db=redis

# 筛选标签
[root@k8s-master ~]# kubectl get pod -n dev -l version=2.0 --show-labels
NAME    READY   STATUS    RESTARTS   AGE   LABELS
nginx   1/1     Running   0          14m   version=2.0
[root@k8s-master ~]# kubectl get pod -n dev -l version!=2.0 --show-labels
No resources found in dev namespace.

# 为pod资源打标签
[root@k8s-master ~]# kubectl label pod nginx version=1.0 -n dev
pod/nginx labeled

# 为pod资源更新标签
[root@k8s-master ~]# kubectl label pod nginx version=2.0 -n dev --overwrite
pod/nginx labeled

#删除标签
[root@k8s-master ~]# kubectl label pod nginx version- -n dev
pod/nginx labeled
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 4.Pod 控制器

在 kubernetes 中,Pod 是最小的控制单元,但是 kubernetes 很少直接控制 Pod,一般都是通过 Pod 控制器来完成的。Pod 控制器用于 pod 的管理,确保 pod 资源符合预期的状态,当 pod 的资源出现故障时,会尝试进行重启或重建 pod。在 kubernetes 中 Pod 控制器的种类有很多。

在 kubernetes 中,按照 pod 的创建方式可以将其分为两类:

  • 自主式 pod:kubernetes 直接创建出来的 Pod,这种 pod 删除后就没有了,也不会重建
  • 控制器创建的 pod:kubernetes 通过控制器创建的 pod,这种 pod 删除了之后还会自动重建

什么是 Pod 控制器

Pod 控制器是管理 pod 的中间层,使用 Pod 控制器之后,只需要告诉 Pod 控制器,想要多少个什么样的 Pod 就可以了,它会创建出满足条件的 Pod 并确保每一个 Pod 资源处于用户期望的目标状态。

如果 Pod 资源在运行中出现故障,它会基于指定策略重新编排 Pod。

image-20230820165212521

# 5.pod 控制器种类

pod 控制器也叫做工作负载,有状态应用使用 StatefulSet 部署,无状态应用使用 Deployment 部署。

在 kubernetes 中,有很多类型的 pod 控制器,每种都有自己的适合的场景,常见的有下面这些:

  • ReplicationController:比较原始的 pod 控制器,已经被废弃,由 ReplicaSet 替代
  • ReplicaSet:保证副本数量一直维持在期望值,并支持 pod 数量扩缩容,镜像版本升级
  • Deployment:通过控制 ReplicaSet 来控制 Pod,并支持滚动升级、回退版本
  • Horizontal Pod Autoscaler:可以根据集群负载自动水平调整 Pod 的数量,实现削峰填谷
  • DaemonSet:在集群中的指定 Node 上运行且仅运行一个副本,一般用于守护进程类的任务
  • Job:它创建出来的 pod 只要完成任务就立即退出,不需要重启或重建,用于执行一次性任务
  • Cronjob:它创建的 Pod 负责周期性任务控制,不需要持续后台运行
  • StatefulSet:管理有状态应用

image-20230820165330631

# 6.ReplicaSet(RS)

ReplicaSet 的主要作用是保证一定数量的 pod 正常运行,它会持续监听这些 Pod 的运行状态,

一旦 Pod 发生故障,就会重启或重建。同时它还支持对 pod 数量的扩缩容和镜像版本的升降级。

ReplicaSet 的资源清单文件:

apiVersion: apps/v1 # 版本号
kind: ReplicaSet # 类型
metadata: # 元数据
  name: # rs名称
  namespace: # 所属命名空间
  labels: #标签
    controller: rs
spec: # 详情描述
  replicas: 3 # 副本数量
  selector: # 选择器,通过它指定该控制器管理哪些pod
    matchLabels:      # Labels匹配规则
      app: nginx-pod
    matchExpressions: # Expressions匹配规则
      - {key: app, operator: In, values: [nginx-pod]}
  template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

在这里面,需要新了解的配置项就是 spec 下面几个选项:

  • replicas:指定副本数量,其实就是当前 rs 创建出来的 pod 的数量,默认为 1
  • selector:选择器,它的作用是建立 pod 控制器和 pod 之间的关联关系,采用的 Label Selector 机制在 pod 模板上定义 label,在控制器上定义选择器,就可以表明当前控制器能管理哪些 pod 了
  • template:模板,就是当前控制器创建 pod 所使用的模板板,里面其实就是前一章学过的 pod 的定义

创建ReplicaSet:

创建pc-replicaset.yaml文件,内容如下:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: pc-replicaset
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 创建rs
[root@k8s-master ~]# kubectl create -f pc-replicaset.yaml
replicaset.apps/pc-replicaset created

# 查看rs
# DESIRED:期望副本数量
# CURRENT:当前副本数量
# READY:已经准备好提供服务的副本数量
[root@k8s-master ~]# kubectl get rs pc-replicaset -n dev -o wide
NAME          DESIRED   CURRENT READY AGE   CONTAINERS   IMAGES             SELECTOR
pc-replicaset 3         3       3     22s   nginx        nginx:1.17.1       app=nginx-pod

# 查看当前控制器创建出来的pod
# 这里发现控制器创建出来的pod的名称是在控制器名称后面拼接了-xxxxx随机码
[root@k8s-master ~]# kubectl get pod -n dev
NAME                          READY   STATUS    RESTARTS   AGE
pc-replicaset-6vmvt   1/1     Running   0          54s
pc-replicaset-fmb8f   1/1     Running   0          54s
pc-replicaset-snrk2   1/1     Running   0          54s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

扩缩容:

# 编辑rs的副本数量,修改spec:replicas: 6即可
[root@k8s-master ~]# kubectl edit rs pc-replicaset -n dev
replicaset.apps/pc-replicaset edited

# 查看pod
[root@k8s-master ~]# kubectl get pods -n dev
NAME                          READY   STATUS    RESTARTS   AGE
pc-replicaset-6vmvt   1/1     Running   0          114m
pc-replicaset-cftnp   1/1     Running   0          10s
pc-replicaset-fjlm6   1/1     Running   0          10s
pc-replicaset-fmb8f   1/1     Running   0          114m
pc-replicaset-s2whj   1/1     Running   0          10s
pc-replicaset-snrk2   1/1     Running   0          114m

# 当然也可以直接使用命令实现
# 使用scale命令实现扩缩容, 后面--replicas=n直接指定目标数量即可
[root@k8s-master ~]# kubectl scale rs pc-replicaset --replicas=2 -n dev
replicaset.apps/pc-replicaset scaled

# 命令运行完毕,立即查看,发现已经有4个开始准备退出了
[root@k8s-master ~]# kubectl get pods -n dev
NAME                       READY   STATUS        RESTARTS   AGE
pc-replicaset-6vmvt   0/1     Terminating   0          118m
pc-replicaset-cftnp   0/1     Terminating   0          4m17s
pc-replicaset-fjlm6   0/1     Terminating   0          4m17s
pc-replicaset-fmb8f   1/1     Running       0          118m
pc-replicaset-s2whj   0/1     Terminating   0          4m17s
pc-replicaset-snrk2   1/1     Running       0          118m

#稍等片刻,就只剩下2个了
[root@k8s-master ~]# kubectl get pods -n dev
NAME                       READY   STATUS    RESTARTS   AGE
pc-replicaset-fmb8f   1/1     Running   0          119m
pc-replicaset-snrk2   1/1     Running   0          119m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

镜像升级:

# 编辑rs的容器镜像 - image: nginx:1.17.2
[root@k8s-master ~]# kubectl edit rs pc-replicaset -n dev
replicaset.apps/pc-replicaset edited

# 再次查看,发现镜像版本已经变更了
[root@k8s-master ~]# kubectl get rs -n dev -o wide
NAME                DESIRED  CURRENT   READY   AGE    CONTAINERS   IMAGES        ...
pc-replicaset       2        2         2       140m   nginx         nginx:1.17.2  ...

# 同样的道理,也可以使用命令完成这个工作
# kubectl set image rs rs名称 容器=镜像版本 -n namespace
[root@k8s-master ~]# kubectl set image rs pc-replicaset nginx=nginx:1.17.1  -n dev
replicaset.apps/pc-replicaset image updated

# 再次查看,发现镜像版本已经变更了
[root@k8s-master ~]# kubectl get rs -n dev -o wide
NAME                 DESIRED  CURRENT   READY   AGE    CONTAINERS   IMAGES            ...
pc-replicaset        2        2         2       145m   nginx        nginx:1.17.1 ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

删除ReplicaSet:

# 使用kubectl delete命令会删除此RS以及它管理的Pod
# 在kubernetes删除RS前,会将RS的replicasclear调整为0,等待所有的Pod被删除后,在执行RS对象的删除
[root@k8s-master ~]# kubectl delete rs pc-replicaset -n dev
replicaset.apps "pc-replicaset" deleted
[root@k8s-master ~]# kubectl get pod -n dev -o wide
No resources found in dev namespace.

# 如果希望仅仅删除RS对象(保留Pod),可以使用kubectl delete命令时添加--cascade=false选项(不推荐)
[root@k8s-master ~]# kubectl delete rs pc-replicaset -n dev --cascade=false
replicaset.apps "pc-replicaset" deleted
[root@k8s-master ~]# kubectl get pods -n dev
NAME                  READY   STATUS    RESTARTS   AGE
pc-replicaset-cl82j   1/1     Running   0          75s
pc-replicaset-dslhb   1/1     Running   0          75s

# 也可以使用yaml直接删除(推荐)
[root@k8s-master ~]# kubectl delete -f pc-replicaset.yaml
replicaset.apps "pc-replicaset" deleted
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 7.Deployment(Deploy)

为了更好的解决服务编排的问题,kubernetes 在 V1.2 版本开始,引入了 Deployment 控制器。

值得一提的是,这种控制器并不直接管理 pod,而是通过管理 ReplicaSet 来间接管理 Pod,即:Deployment管理 ReplicaSet,ReplicaSet 管理 Pod。所以 DeploymentReplicaSet 功能更加强大。

image-20230820165430373

Deployment主要功能有下面几个:

  • 支持 ReplicaSet 的所有功能
  • 支持发布的停止、继续
  • 支持滚动升级和回滚版本

Deployment 的资源清单文件:

apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据
  name: # rs名称
  namespace: # 所属命名空间
  labels: #标签
    controller: deploy
spec: # 详情描述
  replicas: 3 # 副本数量
  revisionHistoryLimit: 3 # 保留历史版本
  paused: false # 暂停部署,默认是false
  progressDeadlineSeconds: 600 # 部署超时时间(s),默认是600
  strategy: # 策略
    type: RollingUpdate # 滚动更新策略
    rollingUpdate: # 滚动更新
      maxSurge: 30% # 最大额外可以存在的副本数,可以为百分比,也可以为整数
      maxUnavailable: 30% # 最大不可用状态的 Pod 的最大值,可以为百分比,也可以为整数
  selector: # 选择器,通过它指定该控制器管理哪些pod
    matchLabels:      # Labels匹配规则
      app: nginx-pod
    matchExpressions: # Expressions匹配规则
      - {key: app, operator: In, values: [nginx-pod]}
  template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

创建deployment:

创建pc-deployment.yaml,内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pc-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 以yml方式查看deploy
kubectl get deploy my-dep -o yaml

# 创建deployment
[root@k8s-master01 ~]# kubectl create -f pc-deployment.yaml --record=true
deployment.apps/pc-deployment created

# 查看deployment
# UP-TO-DATE 最新版本的pod的数量
# AVAILABLE  当前可用的pod的数量
[root@k8s-master01 ~]# kubectl get deploy pc-deployment -n dev
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
pc-deployment   3/3     3            3           15s

# 查看rs
# 发现rs的名称是在原来deployment的名字后面添加了一个10位数的随机串
[root@k8s-master01 ~]# kubectl get rs -n dev
NAME                       DESIRED   CURRENT   READY   AGE
pc-deployment-6696798b78   3         3         3       23s

# 查看pod
[root@k8s-master01 ~]# kubectl get pods -n dev
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-6696798b78-d2c8n   1/1     Running   0          107s
pc-deployment-6696798b78-smpvp   1/1     Running   0          107s
pc-deployment-6696798b78-wvjd8   1/1     Running   0          107s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

扩缩容:

# 变更副本数量为5个
[root@k8s-master ~]# kubectl scale deploy pc-deployment --replicas=5  -n dev
deployment.apps/pc-deployment scaled

#修改 replicas
kubectl edit deployment my-dep

# 查看deployment
[root@k8s-master ~]# kubectl get deploy pc-deployment -n dev
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
pc-deployment   5/5     5            5           2m

# 查看pod
[root@k8s-master ~]#  kubectl get pods -n dev
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-6696798b78-d2c8n   1/1     Running   0          4m19s
pc-deployment-6696798b78-jxmdq   1/1     Running   0          94s
pc-deployment-6696798b78-mktqv   1/1     Running   0          93s
pc-deployment-6696798b78-smpvp   1/1     Running   0          4m19s
pc-deployment-6696798b78-wvjd8   1/1     Running   0          4m19s

# 编辑deployment的副本数量,修改spec:replicas: 4即可
[root@k8s-master ~]# kubectl edit deploy pc-deployment -n dev
deployment.apps/pc-deployment edited

# 查看pod
[root@k8s-master ~]# kubectl get pods -n dev
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-6696798b78-d2c8n   1/1     Running   0          5m23s
pc-deployment-6696798b78-jxmdq   1/1     Running   0          2m38s
pc-deployment-6696798b78-smpvp   1/1     Running   0          5m23s
pc-deployment-6696798b78-wvjd8   1/1     Running   0          5m23s


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

镜像更新:

deployment 支持两种更新策略:重建更新和滚动更新,可以通过 strategy 指定策略类型,支持两个属性:

  • 重建更新: 杀死全部已存在 pod,然后一次性更新到最新的版本
  • 滚动更新: 就是杀死一部分,就启动一部分,在更新过程中,存在两个版本 pod

strategy:指定新的 Pod 替换旧的 Pod 的策略, 支持两个属性: type:指定策略类型,支持两种策略 Recreate:在创建出新的 Pod 之前会先杀掉所有已存在的 Pod RollingUpdate:滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本 Pod rollingUpdate:当 type 为 RollingUpdate 时生效,用于为 RollingUpdate 设置参数,支持两个属性: maxUnavailable:用来指定在升级过程中不可用 Pod 的最大数量,默认为 25%。 maxSurge: 用来指定在升级过程中可以超过期望的 Pod 的最大数量,默认为 25%。

重建更新

1.编辑pc-deployment.yaml, 在 spec 节点下添加更新策略

spec:
  strategy: # 策略
    type: Recreate # 重建更新
1
2
3

2.创建 deploy 进行验证

# 变更镜像
[root@k8s-master ~]# kubectl set image deployment pc-deployment nginx=nginx:1.17.2 -n dev
deployment.apps/pc-deployment image updated

# 观察升级过程
[root@k8s-master ~]#  kubectl get pods -n dev -w
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-5d89bdfbf9-65qcw   1/1     Running   0          31s
pc-deployment-5d89bdfbf9-w5nzv   1/1     Running   0          31s
pc-deployment-5d89bdfbf9-xpt7w   1/1     Running   0          31s

pc-deployment-5d89bdfbf9-xpt7w   1/1     Terminating   0          41s
pc-deployment-5d89bdfbf9-65qcw   1/1     Terminating   0          41s
pc-deployment-5d89bdfbf9-w5nzv   1/1     Terminating   0          41s

pc-deployment-675d469f8b-grn8z   0/1     Pending       0          0s
pc-deployment-675d469f8b-hbl4v   0/1     Pending       0          0s
pc-deployment-675d469f8b-67nz2   0/1     Pending       0          0s

pc-deployment-675d469f8b-grn8z   0/1     ContainerCreating   0          0s
pc-deployment-675d469f8b-hbl4v   0/1     ContainerCreating   0          0s
pc-deployment-675d469f8b-67nz2   0/1     ContainerCreating   0          0s

pc-deployment-675d469f8b-grn8z   1/1     Running             0          1s
pc-deployment-675d469f8b-67nz2   1/1     Running             0          1s
pc-deployment-675d469f8b-hbl4v   1/1     Running             0          2s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

滚动更新

1.编辑pc-deployment.yaml,在 spec 节点下添加更新策略

spec:
  strategy: # 策略
    type: RollingUpdate # 滚动更新策略
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
1
2
3
4
5
6

2.创建 deploy 进行验证

# 变更镜像
[root@k8s-master ~]# kubectl set image deployment pc-deployment nginx=nginx:1.17.3 -n dev
deployment.apps/pc-deployment image updated


# 变更镜--修改
kubectl edit deployment/my-dep


# 查看my-dep的状态 显示deployment "my-dep" successfully rolled out表示部署“my-dep”成功展开
kubectl rollout status deployment/pc-deployment

#每秒1次的频率查看
[root@k8s-master ~]# watch -n 1 kubectl get pods -n dev -w

# 观察升级过程
[root@k8s-master ~]# kubectl get pods -n dev -w
NAME                           READY   STATUS    RESTARTS   AGE
pc-deployment-c848d767-8rbzt   1/1     Running   0          31m
pc-deployment-c848d767-h4p68   1/1     Running   0          31m
pc-deployment-c848d767-hlmz4   1/1     Running   0          31m
pc-deployment-c848d767-rrqcn   1/1     Running   0          31m

pc-deployment-966bf7f44-226rx   0/1     Pending             0          0s
pc-deployment-966bf7f44-226rx   0/1     ContainerCreating   0          0s
pc-deployment-966bf7f44-226rx   1/1     Running             0          1s
pc-deployment-c848d767-h4p68    0/1     Terminating         0          34m

pc-deployment-966bf7f44-cnd44   0/1     Pending             0          0s
pc-deployment-966bf7f44-cnd44   0/1     ContainerCreating   0          0s
pc-deployment-966bf7f44-cnd44   1/1     Running             0          2s
pc-deployment-c848d767-hlmz4    0/1     Terminating         0          34m

pc-deployment-966bf7f44-px48p   0/1     Pending             0          0s
pc-deployment-966bf7f44-px48p   0/1     ContainerCreating   0          0s
pc-deployment-966bf7f44-px48p   1/1     Running             0          0s
pc-deployment-c848d767-8rbzt    0/1     Terminating         0          34m

pc-deployment-966bf7f44-dkmqp   0/1     Pending             0          0s
pc-deployment-966bf7f44-dkmqp   0/1     ContainerCreating   0          0s
pc-deployment-966bf7f44-dkmqp   1/1     Running             0          2s
pc-deployment-c848d767-rrqcn    0/1     Terminating         0          34m

# 至此,新版本的pod创建完毕,就版本的pod销毁完毕
# 中间过程是滚动进行的,也就是边销毁边创建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

滚动更新的过程:

image-20230315191158909

镜像更新中 rs 的变化:

# 查看rs,发现原来的rs的依旧存在,只是pod数量变为了0,而后又新产生了一个rs,pod数量为4
# 其实这就是deployment能够进行版本回退的奥妙所在
[root@k8s-master ~]# kubectl get rs -n dev
NAME                       DESIRED   CURRENT   READY   AGE
pc-deployment-6696798b78   0         0         0       7m37s
pc-deployment-6696798b11   0         0         0       5m37s
pc-deployment-c848d76789   4         4         4       72s
1
2
3
4
5
6
7

版本回退:

deployment 支持版本升级过程中的暂停、继续功能以及版本回退等诸多功能,下面具体来看.

kubectl rollout: 版本升级相关功能,支持下面的选项:

  • status 显示当前升级状态
  • history 显示 升级历史记录
  • pause 暂停版本升级过程
  • resume 继续已经暂停的版本升级过程
  • restart 重启版本升级过程
  • undo 回滚到上一级版本(可以使用--to-revision 回滚到指定版本)
#历史记录
kubectl rollout history deployment/my-dep

#查看某个历史详情
kubectl rollout history deployment/my-dep --revision=2

# 查看当前升级版本的状态
[root@k8s-master ~]# kubectl rollout status deploy pc-deployment -n dev
deployment "pc-deployment" successfully rolled out

# 查看升级历史记录,可以发现有三次版本记录,说明完成过两次升级
[root@k8s-master ~]# kubectl rollout history deploy pc-deployment -n dev
deployment.apps/pc-deployment
REVISION  CHANGE-CAUSE
1         kubectl create --filename=pc-deployment.yaml --record=true
2         kubectl create --filename=pc-deployment.yaml --record=true
3         kubectl create --filename=pc-deployment.yaml --record=true

# 版本回滚
#回滚(回到上次)
kubectl rollout undo deployment/my-dep

# 回滚到指定版本
[root@k8s-master ~]# kubectl rollout undo deployment pc-deployment --to-revision=1 -n dev
deployment.apps/pc-deployment rolled back

# 查看发现,通过nginx镜像版本可以发现到了第一版
[root@k8s-master ~]# kubectl get deploy -n dev -o wide
NAME            READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES
pc-deployment   4/4     4            4           74m   nginx        nginx:1.17.1

# 查看rs,发现第一个rs中有4个pod运行,后面两个版本的rs中pod为运行
# 其实deployment之所以可是实现版本的回滚,就是通过记录下历史rs来实现的,
# 一旦想回滚到哪个版本,只需要将当前版本pod数量降为0,然后将回滚版本的pod提升为目标数量就可以了
[root@k8s-master ~]# kubectl get rs -n dev
NAME                       DESIRED   CURRENT   READY   AGE
pc-deployment-6696798b78   4         4         4       78m
pc-deployment-966bf7f44    0         0         0       37m
pc-deployment-c848d767     0         0         0       71m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

金丝雀发布:

Deployment 控制器支持控制更新过程中的控制,如“暂停(pause)”或“继续(resume)”更新操作。

比如有一批新的 Pod 资源创建完成后立即暂停更新过程,此时,仅存在一部分新版本的应用,主体部分还是旧的版本。然后,再筛选一小部分的用户请求路由到新版本的 Pod 应用,继续观察能否稳定地按期望的方式运行。确定没问题之后再继续完成余下的 Pod 资源滚动更新,否则立即回滚更新操作。这就是所谓的金丝雀发布。

# 更新deployment的版本,并配置暂停deployment
[root@k8s-master ~]#  kubectl set image deploy pc-deployment nginx=nginx:1.17.4 -n dev && kubectl rollout pause deployment pc-deployment  -n dev
deployment.apps/pc-deployment image updated
deployment.apps/pc-deployment paused

#观察更新状态
[root@k8s-master ~]# kubectl rollout status deploy pc-deployment -n dev 
Waiting for deployment "pc-deployment" rollout to finish: 2 out of 4 new replicas have been updated...

# 监控更新的过程,可以看到已经新增了一个资源,
#但是并未按照预期的状态去删除一个旧的资源,就是因为使用了pause暂停命令
[root@k8s-master ~]# kubectl get rs -n dev -o wide
NAME                       DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES
pc-deployment-5d89bdfbf9   3         3         3       19m     nginx        nginx:1.17.1
pc-deployment-675d469f8b   0         0         0       14m     nginx        nginx:1.17.2
pc-deployment-6c9f56fcfb   2         2         2       3m16s   nginx        nginx:1.17.4
[root@k8s-master ~]# kubectl get pods -n dev
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-5d89bdfbf9-rj8sq   1/1     Running   0          7m33s
pc-deployment-5d89bdfbf9-ttwgg   1/1     Running   0          7m35s
pc-deployment-5d89bdfbf9-v4wvc   1/1     Running   0          7m34s
pc-deployment-6c9f56fcfb-996rt   1/1     Running   0          3m31s
pc-deployment-6c9f56fcfb-j2gtj   1/1     Running   0          3m31s

# 确保更新的pod没问题了,继续更新
[root@k8s-master ~]# kubectl rollout resume deploy pc-deployment -n dev
deployment.apps/pc-deployment resumed

# 查看最后的更新情况
[root@k8s-master ~]# kubectl get rs -n dev -o wide
NAME                       DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES
pc-deployment-5d89bdfbf9   0         0         0       21m     nginx        nginx:1.17.1
pc-deployment-675d469f8b   0         0         0       16m     nginx        nginx:1.17.2
pc-deployment-6c9f56fcfb   4         4         4       5m11s   nginx        nginx:1.17.4

[root@k8s-master ~]# kubectl get pods -n dev
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-6c9f56fcfb-7bfwh   1/1     Running   0          37s
pc-deployment-6c9f56fcfb-996rt   1/1     Running   0          5m27s
pc-deployment-6c9f56fcfb-j2gtj   1/1     Running   0          5m27s
pc-deployment-6c9f56fcfb-rf84v   1/1     Running   0          37s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

删除Deployment:

# 删除deployment,其下的rs和pod也将被删除
[root@k8s-master ~]# kubectl delete -f pc-deployment.yaml
deployment.apps "pc-deployment" deleted
1
2
3

# 8.StatefulSet

StatefulSet 作为 Controller 为 Pod 提供唯一的标识。它可以保证部署和 scale 的顺序

StatefulSet 是为了解决有状态服务的问题(对应 Deployments 和 ReplicaSets.是为无状态服务而设计),其应用场景包括:

  • 稳定的持久化存储,即 Pod 重新调度后还是能访问到相同的持久化数据,基于 PVC 来实现
  • 稳定的网络标志,即 Pod 重新调度后其 PodName 和 HostName.不变,基于 Headless Service(即没有

Cluster IP 的 Service)来实现

  • 有序部署,有序扩展,即 Pod 是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从 0 到 N-1,在下一个 Pod 运行之前所有之前的 Pod 必须都是 Runningi 和 Ready 状态),基于 init containers 来实现有序收缩,有序删除(即从 N-1 到 0)

image-20230315191612415

deployment 控制器相关命令

# 创建pod命令格式: kubectl create deployment 名称  [参数]
# --image  指定pod的镜像
# --port   指定端口
# --replicas  指定创建pod数量
# --namespace  指定namespace
[root@k8s-master ~]# kubectl create deploy nginx --image=nginx:latest -n dev
deployment.apps/nginx created
1
2
3
4
5
6
7
# 查看创建的Pod
[root@master ~]# kubectl get pods -n dev
NAME                     READY   STATUS    RESTARTS   AGE
nginx-5ff7956ff6-6k8cb   1/1     Running   0          19s
nginx-5ff7956ff6-jxfjt   1/1     Running   0          19s
nginx-5ff7956ff6-v6jqw   1/1     Running   0          19s
1
2
3
4
5
6
# 查看deployment的信息
[root@k8s-master ~]# kubectl get pods -n dev
NAME                   READY   STATUS    RESTARTS   AGE
nginx                  1/1     Running   0          3h42m
nginx-674ff86d-jggtc   1/1     Running   0          8m36s
1
2
3
4
5
# 删除
[root@k8s-master ~]# kubectl delete deploy nginx -n dev
deployment.apps "nginx" deleted
1
2
3
# UP-TO-DATE:成功升级的副本数量
# AVAILABLE:可用副本的数量
[root@k8s-master ~]# kubectl get deploy -n dev -o wide
NAME    READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES         SELECTOR
nginx   1/1     1            1           9m16s   nginx        nginx:latest   app=nginx

# 查看deployment的详细信息
[root@k8s-master ~]# kubectl get deploy -n dev
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           8m58s
[root@k8s-master ~]# kubectl get deploy -n dev -o wide
NAME    READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES         SELECTOR
nginx   1/1     1            1           9m16s   nginx        nginx:latest   app=nginx
[root@k8s-master ~]# kubectl describe deploy nginx -n dev
Name:                   nginx
Namespace:              dev
CreationTimestamp:      Fri, 10 Sep 2021 19:56:45 +0800
Labels:                 app=nginx
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=nginx
Replicas:               1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:        nginx:latest
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   nginx-674ff86d (1/1 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  11m   deployment-controller  Scaled up replica set nginx-674ff86d to 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 五.service 详解

# 1.什么是 service?

虽然每个 Pod 都会分配一个单独的 Pod IP,然而却存在如下两问题:

  • Pod IP 会随着 Pod 的重建产生变化
  • Pod IP 仅仅是集群内可见的虚拟 IP,外部无法访问

这样对于访问这个服务带来了难度。因此,kubernetes 设计了 Service 来解决这个问题。

Service 可以看作是一组同类 Pod对外的访问接口。借助 Service,应用可以方便地实现服务发现和负载均衡

Service 是由 kube-proxy 组件,加上 iptables 来共同实现的. kube-proxy 通过 iptables 处理 Service 的过程,需要在宿主机上设置相当多的 iptables 规则,如果宿主机有大量的 Pod,不断刷新 iptables 规则,会消耗大量的 CPU 资源。

# 2.Service 的类型

Service 的资源清单文件:

kind: Service # 资源类型
apiVersion: v1 # 资源版本
metadata: # 元数据
  name: service # 资源名称
  namespace: dev # 命名空间
spec: # 描述
  selector: # 标签选择器,用于确定当前service代理哪些pod
    app: nginx
  type: # Service类型,指定service的访问方式
  clusterIP: # 虚拟服务的ip地址
  sessionAffinity: # session亲和性,支持ClientIP、None两个选项
  ports: # 端口信息
    - protocol: TCP
      port: 3017 # service端口
      targetPort: 5003 # pod端口
      nodePort: 31122 # 主机端口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

K8S 中 Service 分为四类,分别是 ClusterIP,NodePort,LoadBalancer 以及 ExternalName

  • ClusterIP:默认值,它是 Kubernetes 系统自动分配的虚拟 IP,只能在集群内部访问
  • NodePort:将 Service 通过指定的 Node 上的端口暴露给外部,通过此方法,就可以在集群外部访问服务
  • LoadBalancer:使用外接负载均衡器完成到服务的负载分发,注意此模式需要外部云环境支持
  • ExternalName: 把集群外部的服务引入集群内部,在集群你内部直接使用. 没有任何类型代理被创建, 这里只有 kubernetes 1.7 或更高版本的 kube-dns 才支持

其中绿色的代表从外向内的访问模式;蓝色的代表从内向外的访问模式,黄色代表集群内部的访问模式。可以看到,除了 ExternalName 类型之外,其余三种类型都是逐层封装而来的。

image-20230820165648855

# ClusterIP

这是 K8S 默认的服务类型,只能在 K8S 中进行服务通信。在 ClientIP 中,K8S 会在 Service 创建完毕后提供一个内部 IP 作为 ClientIP 属性,K8S 内部服务可以通过 ClientIP 或者 ServiceName 来访问该服务。

# NodePort

NodePort 则是 Service type 是 Nodeport 的实现,NodePort 通过配置 nodePort 属性,外部用户可以通过 NodeIP:NodePort 的方式单独访问每个 Node 上的服务。

# LoadBalancer

LoadBalancer 类型的 service 是可以实现集群外部访问服务的另外一种解决方案。不过并不是所有的 k8s 集群都会支持,大多是在公有云托管集群中会支持该类型。负载均衡器是异步创建的,被提供的负载均衡器的信息将会通过 Service 的 status.loadBalancer 字段被发布出去。

# ExternalName

Service 的 ExternalName 方式实现,即设置 Service 的 type 为 ExternalName。这样做的好处就是内部服务访问外部服务的时候是通过别名来访问的,屏蔽了外部服务的真实信息,外部服务对内部服务透明,外部服务的修改基本上不会影响到内部服务的访问,做到了内部服务和外部服务解耦合。

# 3.service 的工作机制

image-20230820165712155

# 4.kube-proxy 工作模式

userspace 模式:

userspace 模式下,kube-proxy 会为每一个 Service 创建一个监听端口,发向 Cluster IP 的请求被 Iptables 规则重定向到 kube-proxy 监听的端口上,kube-proxy 根据 LB 算法选择一个提供服务的 Pod 并和其建立链接,以将请求转发到 Pod 上。 该模式下,kube-proxy 充当了一个四层负责均衡器的角色。由于 kube-proxy 运行在 userspace 中,在进行转发处理时会增加内核和用户空间之间的数据拷贝,虽然比较稳定,但是效率比较低。

image-20230820165737149

iptables 模式:

iptables 模式下,kube-proxy 为 service 后端的每个 Pod 创建对应的 iptables 规则,直接将发向 Cluster IP 的请求重定向到一个 Pod IP。 该模式下 kube-proxy 不承担四层负责均衡器的角色,只负责创建 iptables 规则。该模式的优点是较 userspace 模式效率更高,但不能提供灵活的 LB 策略,当后端 Pod 不可用时也无法进行重试。

image-20230820165752050

ipvs 模式:

ipvs 模式和 iptables 类似,kube-proxy 监控 Pod 的变化并创建相应的 ipvs 规则。ipvs 相对 iptables 转发效率更高。除此以外,ipvs 支持更多的 LB 算法。

image-20230820165807584

# 此模式必须安装ipvs内核模块,否则会降级为iptables
# 开启ipvs
[root@k8s-master01 ~]# kubectl edit cm kube-proxy -n kube-system
# 修改mode: "ipvs"
[root@k8s-master01 ~]# kubectl delete pod -l k8s-app=kube-proxy -n kube-system
[root@node1 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.97.97.97:80 rr
  -> 10.244.1.39:80               Masq    1      0          0
  -> 10.244.1.40:80               Masq    1      0          0
  -> 10.244.2.33:80               Masq    1      0          0
1
2
3
4
5
6
7
8
9
10
11
12
13

# 4.Headless Service

有时候我们不需要负载均衡,比如下面的两个场景:

  • K8S 部署某个 kafka 集群,此时就不需要 service 来负载均衡,客户端需要的是一组 pod 所有 ip 的列表。

  • 客户端自己处理负载均衡的逻辑,比如 K8S 部署两个 mysql,客户端自己处理负载请求,或者根本不处理这种负载,就要两套 mysql 然后手动控制读写请求。

基于上面的两个场景,K8S 提供了 headless serivce 功能,字面意思是无头 service,其实就是该 service 不显式的对外提供 IP。headless service 一般结合 StatefulSet 来部署有状态的应用,比如大数据组件或者 nosql 数据库等,这种分布式的系统需要 headless service 来获取所有节点 ip 的列表供业务场景使用。

apiVersion: v1
kind: Service
metadata:
  name: service-headless
spec:
  ports:
    - port: 3000
      protocol: TCP
      targetPort: 443
      nodePort: 30080
      clusterIP: None ##如此配置即开启了headless serivce
  selector:
    app: pod-headless
  type: NodePort
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 5.集群内部访问的 Service

# 暴露Service
[root@k8s-master ~]# kubectl expose deploy nginx --name=svc-nginx1 --type=ClusterIP --port=80 --target-port=80 -n dev
service/svc-nginx1 exposed

# 查看service
[root@k8s-master ~]# kubectl get svc svc-nginx1 -n dev -o wide
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR
svc-nginx1   ClusterIP   10.107.72.255   <none>        80/TCP    33s   run=nginx


# 这里产生了一个CLUSTER-IP,这就是service的IP,在Service的生命周期中,这个地址是不会变动的
# 可以通过这个IP访问当前service对应的POD
[root@k8s-master ~]# curl 10.107.72.255:80
<!DOCTYPE html>
<html>
....
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

#同时也可以通过服务名来访问。
#注意使用域名的方式只能在Pod容器内部使用。域名规则:deploy名称.名称空间.svc
curl my-dep.default.svc:8000
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 6.外部可访问的 Service

# 上面创建的Service的type类型为ClusterIP,这个ip地址只用集群内部可访问
# 如果需要创建外部也可以访问的Service,需要修改type为NodePort
[root@master ~]# kubectl expose deploy nginx --name=svc-nginx2 --type=NodePort --port=80 --target-port=80 -n dev
service/svc-nginx2 exposed

# 此时查看,会发现出现了NodePort类型的Service,而且有一对Port(80:31928/TC)
[root@k8s-master ~]# kubectl get svc  svc-nginx2  -n dev -o wide
NAME         TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE   SELECTOR
svc-nginx2   NodePort   10.110.252.114   <none>        80:31926/TCP   10s   run=nginx

# 接下来就可以通过集群外的主机访问 主机节点IP:31928访问服务了
# 例如在的电脑主机上通过浏览器访问下面的地址
http://112.124.232.206:31926/


# ClusterIP  在集群内部访问
kubectl expose deployment my-dep --port=8000 --target-port=80 --type=ClusterIP
# NodePort  可以使用公网访问,可以在集群内访问		NodePort范围在 30000-32767 之间
kubectl expose deployment my-dep --port=8000 --target-port=80 --type=NodePort
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 7.删除 service

[root@k8s-master ~]# kubectl delete svc svc-nginx1 -n dev
service "svc-nginx1" deleted
1
2

# 六.Ingress

# 1.Ingress 概念

通俗来讲,ingress 和之前提到的 Service、Deployment,也是一个 k8s 的资源类型,ingress 用于实现用域名的方式访问 k8s 内部应用。

Ingress 为 Kubernetes 集群中的服务提供了入口,可以提供负载均衡、SSL 终止和基于名称的虚拟主机,在生产环境中常用的 Ingress 有 Treafik、Nginx、HAProxy、Istio 等。

Ingress 可以配置提供服务外部访问的 URL、负载均衡、终止 SSL,并提供基于域名的虚拟主机。但 Ingress 不会暴露任意端口或协议。

# 2.为什么引入 Ingress?

Service 对集群之外暴露服务的主要方式有两种:NotePortLoadBalancer,但是这两种方式,都有一定的缺点:

  • NodePort 方式的缺点是会占用很多集群机器的端口,那么当集群服务变多的时候,这个缺点就愈发明显
  • LB 方式的缺点是每个 service 需要一个 LB,浪费、麻烦,并且需要 kubernetes 之外设备的支持

基于这种现状,kubernetes 提供了 Ingress 资源对象,Ingress 只需要一个 NodePort 或者一个 LB 就可以满足暴露多个 Service 的需求。

# 3.Ingress 工作机制?

image-20230820165915026

实际上,Ingress 相当于一个 7 层的负载均衡器,是 kubernetes 对反向代理的一个抽象,它的工作原理类似于 Nginx,可以理解成在Ingress 里建立诸多映射规则,Ingress Controller 通过监听这些配置规则并转化成 Nginx 的反向代理配置 , 然后对外部提供服务。在这里有两个核心概念:

  • ingress:kubernetes 中的一个对象,作用是定义请求如何转发到 service 的规则
  • ingress controller:具体实现反向代理及负载均衡的程序,对 ingress 定义的规则进行解析,根据配置的规则来实现请求转发,实现方式有很多,比如 Nginx, Contour, Haproxy 等等

Ingress(以 Nginx 为例)的工作原理如下:

  1. 用户编写 Ingress 规则,说明哪个域名对应 kubernetes 集群中的哪个 Service
  2. Ingress 控制器动态感知 Ingress 服务规则的变化,然后生成一段对应的 Nginx 反向代理配置
  3. Ingress 控制器会将生成的 Nginx 配置写入到一个运行着的 Nginx 服务中,并动态更新
  4. 到此为止,其实真正在工作的就是一个 Nginx 了,内部配置了用户定义的请求转发规则

image-20230820165951725

image-20230820170006672

# 4.搭建 ingress 环境

# 创建文件夹
[root@k8s-master01 ~]# mkdir ingress-controller
[root@k8s-master01 ~]# cd ingress-controller/

# 获取ingress-nginx,本次案例使用的是0.30版本
[root@k8s-master01 ingress-controller]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
[root@k8s-master01 ingress-controller]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml

# 修改mandatory.yaml文件中的仓库
# 修改quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
# 为quay-mirror.qiniu.com/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
# 创建ingress-nginx
[root@k8s-master01 ingress-controller]# kubectl apply -f ./

# 查看ingress-nginx
[root@k8s-master01 ingress-controller]# kubectl get pod -n ingress-nginx
NAME                                           READY   STATUS    RESTARTS   AGE
pod/nginx-ingress-controller-fbf967dd5-4qpbp   1/1     Running   0          12h

# 查看service
[root@k8s-master01 ingress-controller]# kubectl get svc -n ingress-nginx
NAME            TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx   NodePort   10.98.75.163   <none>        80:32240/TCP,443:31335/TCP   11h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 5.准备 service 和 pod

为了后面的实验比较方便,创建如下图所示的模型

image-20230820170021798

创建tomcat-nginx.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: tomcat-pod
  template:
    metadata:
      labels:
        app: tomcat-pod
    spec:
      containers:
      - name: tomcat
        image: tomcat:8.5-jre10-slim
        ports:
        - containerPort: 8080

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 80

---

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
  namespace: dev
spec:
  selector:
    app: tomcat-pod
  clusterIP: None
  type: ClusterIP
  ports:
  - port: 8080
    targetPort: 8080
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# 创建
[root@k8s-master01 ~]# kubectl create -f tomcat-nginx.yaml

# 查看
[root@k8s-master01 ~]# kubectl get svc -n dev
NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
nginx-service    ClusterIP   None         <none>        80/TCP     48s
tomcat-service   ClusterIP   None         <none>        8080/TCP   48s
1
2
3
4
5
6
7
8

# 6.Http 代理

创建ingress-http.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-http
  namespace: dev
spec:
  rules:
    - host: nginx.itheima.com
      http:
        paths:
          - path: /
            backend:
              serviceName: nginx-service
              servicePort: 80
    - host: tomcat.itheima.com
      http:
        paths:
          - path: /
            backend:
              serviceName: tomcat-service
              servicePort: 8080
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 创建
[root@k8s-master01 ~]# kubectl create -f ingress-http.yaml
ingress.extensions/ingress-http created

# 查看
[root@k8s-master01 ~]# kubectl get ing ingress-http -n dev
NAME           HOSTS                                  ADDRESS   PORTS   AGE
ingress-http   nginx.itheima.com,tomcat.itheima.com             80      22s

# 查看详情
[root@k8s-master01 ~]# kubectl describe ing ingress-http  -n dev
...
Rules:
Host                Path  Backends
----                ----  --------
nginx.itheima.com   / nginx-service:80 (10.244.1.96:80,10.244.1.97:80,10.244.2.112:80)
tomcat.itheima.com  / tomcat-service:8080(10.244.1.94:8080,10.244.1.95:8080,10.244.2.111:8080)
...

# 接下来,在本地电脑上配置host文件,解析上面的两个域名到192.168.109.100(master)上
# 然后,就可以分别访问tomcat.itheima.com:32240  和  nginx.itheima.com:32240 查看效果了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 七.数据存储

# 1.Volume 介绍?

Volume 是 Pod 中能够被多个容器访问的共享目录,它被定义在 Pod 上,然后被一个 Pod 里的多个容器挂载到具体的文件目录下,kubernetes 通过 Volume 实现同一个 Pod 中不同容器之间的数据共享以及数据的持久化存储。Volume 的生命容器不与 Pod 中单个容器的生命周期相关,当容器终止或者重启时,Volume 中的数据也不会丢失。

kubernetes 的 Volume 支持多种类型,比较常见的有下面几个:

  • 简单存储:EmptyDir、HostPath、NFS
  • 高级存储:PV、PVC
  • 配置存储:ConfigMap、Secret

# 2.EmptyDir

EmptyDir 是最基础的 Volume 类型,一个EmptyDir 就是 Host 上的一个空目录

EmptyDir 是在 Pod 被分配到 Node 时创建的,它的初始内容为空,并且无须指定宿主机上对应的目录文件,因为 kubernetes 会自动分配一个目录,当 Pod 销毁时, EmptyDir 中的数据也会被永久删除。

EmptyDir 用途如下:

  • 临时空间,例如用于某些应用程序运行时所需的临时目录,且无须永久保留
  • 一个容器需要从另一个容器中获取数据的目录(多容器共享目录)

接下来,通过一个容器之间文件共享的案例来使用一下 EmptyDir。

在一个 Pod 中准备两个容器 nginx 和 busybox,然后声明一个 Volume 分别挂在到两个容器的目录中,然后 nginx 容器负责向 Volume 中写日志,busybox 中通过命令将日志内容读到控制台。

image-20230820170045272

# 3.HostPath

EmptyDir 中数据不会被持久化,它会随着 Pod 的结束而销毁,如果想简单的将数据持久化到主机中,可以选择 HostPath。

HostPath 就是将 Node 主机中一个实际目录挂在到 Pod 中,以供容器使用,这样的设计就可以保证 Pod 销毁了,但是数据依据可以存在于 Node 主机上。

image-20230820170058832

# 4.NFS

HostPath 可以解决数据持久化的问题,但是一旦 Node 节点故障了,Pod 如果转移到了别的节点,又会出现问题了,此时需要准备单独的网络存储系统,比较常用的用 NFS、CIFS。

NFS 是一个网络文件存储系统,可以搭建一台 NFS 服务器,然后将 Pod 中的存储直接连接到 NFS 系统上,这样的话,无论 Pod 在节点上怎么转移,只要 Node 跟 NFS 的对接没问题,数据就可以成功访问。

image-20230820170112900

# 5.什么是 PV 和 PVC?

PV(Persistent Volume)是持久化卷的意思,是对底层的共享存储的一种抽象。一般情况下 PV 由 kubernetes 管理员进行创建和配置,它与底层具体的共享存储技术有关,并通过插件完成与共享存储的对接。

PVC(Persistent Volume Claim)是持久卷声明的意思,是用户对于存储需求的一种声明。换句话说,PVC 其实就是用户向 kubernetes 系统发出的一种资源需求申请。

image-20230820170133754

使用了 PV 和 PVC 之后,工作可以得到进一步的细分:

  • 存储:存储工程师维护
  • PV: kubernetes 管理员维护
  • PVC:kubernetes 用户维护

# 6.PV 详解?

PV 是存储资源的抽象,下面是资源清单文件:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv2
spec:
  nfs: # 存储类型,与底层真正存储对应
  capacity: # 存储能力,目前只支持存储空间的设置
    storage: 2Gi
  accessModes: # 访问模式
  storageClassName: # 存储类别
  persistentVolumeReclaimPolicy: # 回收策略
1
2
3
4
5
6
7
8
9
10
11

PV 的 spec 关键配置参数说明:

  • 存储类型底层实际存储的类型,kubernetes 支持多种存储类型,每种存储类型的配置都有所差异

  • 存储能力(capacity)

  • **访问模式(accessModes)**用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:需要注意的是,底层不同的存储类型可能支持的访问模式不同

    • ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
    • ReadOnlyMany(ROX): 只读权限,可以被多个节点挂载
    • ReadWriteMany(RWX):读写权限,可以被多个节点挂载
  • **回收策略(persistentVolumeReclaimPolicy)**当 PV 不再被使用了之后,对其的处理方式。目前支持三种策略:需要注意的是,底层不同的存储类型可能支持的回收策略不同

    • Retain (保留) 保留数据,需要管理员手工清理数据
    • Recycle(回收) 清除 PV 中的数据,效果相当于执行 rm -rf /thevolume/*
    • Delete (删除) 与 PV 相连的后端存储完成 volume 的删除操作,当然这常见于云服务商的存储服务
  • 存储类别PV 可以通过 storageClassName 参数指定一个存储类别

    • 具有特定类别的 PV 只能与请求了该类别的 PVC 进行绑定
    • 未设定类别的 PV 则只能与不请求任何类别的 PVC 进行绑定
  • **状态(status)**一个 PV 的生命周期中,可能会处于 4 中不同的阶段:

    • Available(可用): 表示可用状态,还未被任何 PVC 绑定
    • Bound(已绑定): 表示 PV 已经被 PVC 绑定
    • Released(已释放): 表示 PVC 被删除,但是资源还未被集群重新声明
    • Failed(失败): 表示该 PV 的自动回收失败

# 7.PVC 详解?

PVC 是资源的申请,用来声明对存储空间、访问模式、存储类别需求信息。下面是资源清单文件:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc
  namespace: dev
spec:
  accessModes: # 访问模式
  selector: # 采用标签对PV选择
  storageClassName: # 存储类别
  resources: # 请求空间
    requests:
      storage: 5Gi
1
2
3
4
5
6
7
8
9
10
11
12

PVC 的关键配置参数说明:

  • **访问模式(accessModes)**用于描述用户应用对存储资源的访问权限

  • **选择条件(selector)**通过 Label Selector 的设置,可使 PVC 对于系统中己存在的 PV 进行筛选

  • **存储类别(storageClassName)**PVC 在定义时可以设定需要的后端存储的类别,只有设置了该 class 的 pv 才能被系统选出

  • **资源请求(Resources )**描述对存储资源的请求

# 8.pv 和 pvc 的生命周期

PVC 和 PV 是一一对应的,PV 和 PVC 之间的相互作用遵循以下生命周期:

  • 资源供应:管理员手动创建底层存储和 PV

  • 资源绑定:用户创建 PVC,kubernetes 负责根据 PVC 的声明去寻找 PV,并绑定在用户定义好 PVC 之后,系统将根据 PVC 对存储资源的请求在已存在的 PV 中选择一个满足条件的 PV 一旦绑定到某个 PVC 上,就会被这个 PVC 独占,不能再与其他 PVC 进行绑定了

    • 一旦找到,就将该 PV 与用户定义的 PVC 进行绑定,用户的应用就可以使用这个 PVC 了
    • 如果找不到,PVC 则会无限期处于 Pending 状态,直到等到系统管理员创建了一个符合其要求的 PV
  • 资源使用:用户可在 pod 中像 volume 一样使用 pvcPod 使用 Volume 的定义,将 PVC 挂载到容器内的某个路径进行使用。

  • 资源释放:用户删除 pvc 来释放 pv 当存储资源使用完毕后,用户可以删除 PVC,与该 PVC 绑定的 PV 将会被标记为“已释放”,但还不能立刻与其他 PVC 进行绑定。通过之前 PVC 写入的数据可能还被留在存储设备上,只有在清除之后该 PV 才能再次使用。

  • 资源回收:kubernetes 根据 pv 设置的回收策略进行资源的回收对于 PV,管理员可以设定回收策略,用于设置与之绑定的 PVC 释放资源之后如何处理遗留数据的问题。只有 PV 的存储空间完成回收,才能供新的 PVC 绑定和使用

image-20230820170151560

# 9.配置存储 ConfigMap

ConfigMap 是一种比较特殊的存储卷,它的主要作用是用来存储配置信息的。

创建 configmap.yaml,内容如下:

apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap
  namespace: dev
data:
  info: |
    username:admin
    password:123456
1
2
3
4
5
6
7
8
9

接下来,使用此配置文件创建 configmap

# 创建configmap
[root@k8s-master01 ~]# kubectl create -f configmap.yaml
configmap/configmap created

# 查看configmap详情
[root@k8s-master01 ~]# kubectl describe cm configmap -n dev
Name:         configmap
Namespace:    dev
Labels:       <none>
Annotations:  <none>

Data
====
info:
----
username:admin
password:123456

Events:  <none>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

接下来创建一个 pod-configmap.yaml,将上面创建的 configmap 挂载进去

apiVersion: v1
kind: Pod
metadata:
  name: pod-configmap
  namespace: dev
spec:
  containers:
    - name: nginx
      image: nginx:1.17.1
      volumeMounts: # 将configmap挂载到目录
        - name: config
          mountPath: /configmap/config
  volumes: # 引用configmap
    - name: config
      configMap:
        name: configmap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 创建pod
[root@k8s-master01 ~]# kubectl create -f pod-configmap.yaml
pod/pod-configmap created

# 查看pod
[root@k8s-master01 ~]# kubectl get pod pod-configmap -n dev
NAME            READY   STATUS    RESTARTS   AGE
pod-configmap   1/1     Running   0          6s

#进入容器
[root@k8s-master01 ~]# kubectl exec -it pod-configmap -n dev /bin/sh
# cd /configmap/config/
# ls
info
# more info
username:admin
password:123456

# 可以看到映射已经成功,每个configmap都映射成了一个目录
# key--->文件     value---->文件中的内容
# 此时如果更新configmap的内容, 容器中的值也会动态更新
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 10.配置存储 Secret

在 kubernetes 中,还存在一种和 ConfigMap 非常类似的对象,称为 Secret 对象。它主要用于存储敏感信息,例如密码、秘钥、证书等等。

首先使用 base64 对数据进行编码

[root@k8s-master01 ~]# echo -n 'admin' | base64 #准备username
YWRtaW4=
[root@k8s-master01 ~]# echo -n '123456' | base64 #准备password
MTIzNDU2
1
2
3
4

接下来编写 secret.yaml,并创建 Secret

apiVersion: v1
kind: Secret
metadata:
  name: secret
  namespace: dev
type: Opaque
data:
  username: YWRtaW4=
  password: MTIzNDU2
1
2
3
4
5
6
7
8
9
# 创建secret
[root@k8s-master01 ~]# kubectl create -f secret.yaml
secret/secret created

# 查看secret详情
[root@k8s-master01 ~]# kubectl describe secret secret -n dev
Name:         secret
Namespace:    dev
Labels:       <none>
Annotations:  <none>
Type:  Opaque
Data
====
password:  6 bytes
username:  5 bytes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

创建 pod-secret.yaml,将上面创建的 secret 挂载进去:

apiVersion: v1
kind: Pod
metadata:
  name: pod-secret
  namespace: dev
spec:
  containers:
    - name: nginx
      image: nginx:1.17.1
      volumeMounts: # 将secret挂载到目录
        - name: config
          mountPath: /secret/config
  volumes:
    - name: config
      secret:
        secretName: secret
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 创建pod
[root@k8s-master01 ~]# kubectl create -f pod-secret.yaml
pod/pod-secret created

# 查看pod
[root@k8s-master01 ~]# kubectl get pod pod-secret -n dev
NAME            READY   STATUS    RESTARTS   AGE
pod-secret      1/1     Running   0          2m28s

# 进入容器,查看secret信息,发现已经自动解码了
[root@k8s-master01 ~]# kubectl exec -it pod-secret /bin/sh -n dev
/ # ls /secret/config/
password  username
/ # more /secret/config/username
admin
/ # more /secret/config/password
123456
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
上次更新: 11/29/2024, 10:12:16 AM