searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Kubernetes:深入浅出Pod

2023-07-24 02:52:59
25
0

Pod 的基本用法

Kubernetes 系统中对长时间运行的容器的要求是: 其主程序需要一直在前台执行

对于无法改造为前台执行的应用, 可以使用开源工具 Supervisor 辅助进行前台运行的功能

Supervisor 提供了一种可以同时启动多个后台应用, 并保持 Supervisor 自身在前台执行的机制

静态 Pod

静态 Pod 是由 kubelet 进行管理的仅存在于特定 Node 上的 Pod

它们不能通过 API Server 管理, 无法与 ReplicationController, Deployment 或者 DaemonSet 进行关联

kubelet 无法对它们进行健康检查

静态 Pod 总是由 kubelet 创建的, 并且总是在 kubelet 所在的 Node 上运行

创建静态 Pod 有两种方式: 配置文件方式和 HTTP 方式

Pod 容器共享 Volume

同一个 Pod 中的多个容器能够共享Pod 级别的存储卷 Volume

Volume 可以被定义为各种类型, 多个容器各自进行挂载操作

Pod 的配置管理

ConfigMap 供容器使用的典型用法:

  1. 生成为容器内的环境变量
  2. 设置容器启动命令的启动参数 (需设置为环境变量)
  3. 以 Volume 的形式挂载为容器内部的文件或目录

ConfigMap 以键值对的形式保存配置

value 可以是普通值, 也可以是一个完整的配置文件的内容

key 为配置文件的别名, value 为配置文件的全部文本内容:

 

data:
  key-serverxml: |
    <?xml version="1.0" encoding="UTF-8"?>
    <Server>
    ......
    </Server>
  key-loggingproperties: "
  ....
  "

直接通过 kubectl create configmap 方式创建

使用参数 --from-file 或 --from-literal 指定内容, 可以指定参数多次

使用 --from-file 参数从文件中进行创建:

  • $ kubectl create configmap cm-server.xml --from-file=server.xml

使用 --from-file 从目录中进行创建. 该目录下的每个配置文件名都被设置为 key, 文件内容被设置为 value:

  • $ kubectl create configmap cm-appconf --from-file=configfiles

容器应用对 ConfigMap 的使用有以下两种方法:

  1. 通过环境变量获取 ConfigMap 中的内容
  2. 通过 Volume 挂载的方式将 ConfigMap 中的内容挂载为容器内部的文件目录

在 Pod 中使用 ConfigMap

使用字段 envFrom, 实现在 Pod 环境中将 ConfigMap 中所定义的 key=value 自动生成为环境变量:

 

apiVersion: v1
kind: Pod
metadata:
  name: cm-test-pod
spec:
  containers:
  - name: cm-test
    image: busybox
    command: ["/bin/bash", "-c", "env"]
    envFrom:
    - configMapRef
      name: cm-appvars

通过 volumeMount 使用 ConfigMap

apiVersion: v1
kind: Pod
metadata:
  name: cm-test-app
spec:
  containers:
  - name: cm-test-app
    image: kubeguide/tomcat-app:v1
    imagePullPolicy: Never
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: serverxml
      mountPath: /configfiles
  volumes:
  - name: serverxml
    configMap:
      name: cm-appconfigfiles

配置的 key 作为文件名, 配置的 value 作为文件内容

 

使用 ConfigMap 的限制条件

  • ConfigMap 必须在 Pod 之前创建
  • ConfigMap 受 Namespace 限制, 只有处于相同 Namespace 中的 Pod 才可以引用它
  • ConfigMap 中的配额管理还未实现
  • kubelet 只支持可以被 API Server 管理的 Pod 使用 ConfigMap
  • 在 Pod 对 ConfigMap 进行挂载 (volumeMount) 操作时, 在容器内部只能挂载为”目录”, 无法挂载为”文件”. 容器内的该目录将被挂载的 ConfigMap 覆盖

在容器内获取 Pod 信息 (Downward API)

Downward API 可以通过以下两种方式将 Pod 信息注入容器内部

  1. 环境变量: 用于单个变量, 可以将 Pod 信息和 Container 信息注入容器内部
  2. Volume 挂载: 将数组类信息生成为文件并挂载到容器内部

在某些集群中, 集群中的每个节点都需要将自身的标识 (ID) 及进程绑定的 IP 地址等信息事先写入配置文件中, 进程在启动时会读取这些信息, 然后将这些信息发布到某个类似服务注册中心的地方, 以实现集群节点的自动发现功能

Pod 健康检查和服务可用性检查

通过两类探针来检查 Pod 的健康状态:

  • LivenessProbe
  • ReadinessProbe

LivenessProbe

用于判断容器是否存活 (Running状态)

如果 LivenessProbe 探针探测到容器不健康, 则 kubelet 将杀掉该容器, 并根据容器的重启策略做相应的处理

如果容器没有这个探针, 则 kubelet 认为这个容器的 LivenessProbe 探针返回的值永远是 Success

ReadinessProb

用于判断容器是否可用 (Ready状态)

达到 Ready状态 的 Pod 才可以接收请求

如果在运行中 Ready状态 变为 False, 则系统自动将这个 Pod 从 Service 的后端 Endpoint 列表中隔离出去

确保请求不会发送到 Ready状态 为 False 的 Pod

这两种探针都支持三种实现方式

  • ExecAction: 在容器内部执行命令, 如果命令返回码为0, 则表明容器健康
  • TCPSocketAction: 通过容器的 IP 地址和端口号执行 TCP 检查, 如果能够建立 TCP 连接, 则表明容器健康
  • HTTPGetAction: 通过容器的 IP 地址, 端口号和路径, 调用 HTTP Get 方法, 如果响应的状态码大于等于 200 且小于 400, 则认为容器健康

Example - HTTPGetAction:

apiVersion: v1
kind: Pod
metadata:
  name: pod-with-healthcheck
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    livenessProbe:
      httpGet:
        path: /_status/healthz
        port: 80
      initialDelaySeconds: 30
      timeoutSeconds: 1

对于每种实现方式, 都需要设置 initialDelaySeconds 和 timeoutSeconds 两个参数

  • initialDelaySeconds: 启动容器后进行首次健康检查的等待时间, 单位为秒
  • timeoutSeconds: 健康检查发送请求后等待响应的超时时间, 单位为秒

Pod Readiness Gates 机制

通过 Pod Readiness Gates 机制, 用户可以将自定义的 ReadinessProbe 探测方式设置在 Pod 上, 辅助 Kubernetes 设置 Pod 合适达到服务可用状态 (Ready)

为了使自定义的 ReadinessProbe 生效, 用户需要提供一个外部的控制器 (Controller) 来设置相应的 Condition 状态

Pod 的 Readiness Gates 在 Pod 定义中的 ReadinessGate 字段进行设置

玩转 Pod 调度

ReplicaSet 拥有集合式的标签选择器, 可以选择多个 Pod 标签

ReplicaSet 被设计成能控制多个不同标签的 Pod 副本:

selector:
  matchLabels:
    version: v2
  matchExpressions:
    - {key: version, operator: In, values:[v1, v2]}

Kubernetes 的滚动升级就是巧妙运用 ReplicaSet 的这个特性来完成的

通过给 Node 打标签, 在 Pod 模板中使用 NodeSelector 可以将这些 Pod 副本调度到标签对应的 Node 上

Deployment 全自动调度

自动部署一个容器应用的多份副本, 以及持续监控副本的状态, 在集群内始终维持用户指定的副本数量

Deployment 会创建一个 ReplicaSet 来关联 Pod

Example:

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

可以在 Pod 中使用 NodeSelector,NodeAffinity,PodAffinity,Pod 驱逐 等更加细粒度的调度策略设置

NodeSelector 定向调度

Kubernetes Master 上的 Scheduler 服务 (kube-scheduler进程) 负责实现 Pod 的调度

通过 Node 的 Label 和 Pod 的 NodeSelector 属性, 可以将 Pod 调度到指定的 Node 上

首先, 给 Node 添加 Label:

$ kubectl label node <node-name> <label-key>=<label-value>

如果指定了 Pod 的 NodeSelector 条件, 且在集群中不存在包含响应标签的 Node, 则即使在集群中还有其他可用的 Node, 这个 Pod 也无法被成功调度

Kubernetes 给 Node 预定义了一些标签:

  • kubernetes.io.hostname
  • kubernetes.io/os
  • kubernetes.io/arch

可以使用亲和性调度来改善 NodeSelector 不够灵活的缺点

NodeAffinity Node亲和性调度

Node 亲和性调度策略

用于替换 NodeSelector 的全新调度策略

目前有两种节点亲和性表达:

  • RequiredDuringSchedulingIgnoredDuringExecution
  • PreferredDuringSchedulingIgnoredDuringExecution

末尾的 IgnoredDuringExecution 的意思是: 如果一个 Pod 所在的节点在 Pod 运行期间标签发生了变更, 不再符合该 Pod 的节点亲和性需求, 则系统将忽略 Node 上的 Label 变化, 该 Pod 能继续在该节点运行

RequiredDuringSchedulingIgnoredDuringExecution:

  • 必须满足指定的规则才可以调度 Pod 到 Node 上
  • 相当于硬限制

PreferredDuringSchedulingIgnoredDuringExecution:

  • 强调优先满足指定规则
  • 调度器会尝试调度 Pod 到 Node 上, 但并不强求
  • 相当于软限制
  • 多个优先级规则可以设置权重 (weight) 值, 以定义执行的先后顺序

Example:

apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/arch
            operator: In
            values:
            - amd64
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: disk-type
            operator: In
            values:
            - ssd
  containers:
  - name: with-node-affinity
    image: gcr.io/google_containers/pause:2.0

Taints 和 Tolerations (污点和容忍)

通过 Taint 设置让 Node 拒绝 Pod 的运行

通过 Tolerations 在 Pod 上声明此 Pod 可以在声明了指定 Taint 的 Node 上运行

Taint 和 Toleration 是一种处理节点并且让 Pod 进行规避或者驱逐 Pod 的弹性处理方式

通过自动在故障 Node 上设置 Taint 来驱逐 Pod, 维持集群的正常运行

Pod Priority Preemption (Pod 优先级调度)

当发生资源不足的情况时, 系统可以选择释放一些不重要的负载 (优先级最低的), 保障最重要的负载能够获取足够的资源稳定运行

首先, 创建 kind: PriorityClass 的资源对象

然后, 将这个资源对象在 Pod 的 spec.priorityClassName 中使用

使用优先级抢占的调度策略可能导致某些 Pod 永远无法被成功调度

使用优先级抢占的调度策略增加了系统的复杂性, 运维的难度

DaemonSet (在每个 Node 上都调度一个 Pod)

用于管理在集群中每个 Node 上运行一份 Pod 的副本实例

适合用于 GlusterFS存储 或者 Ceph存储 的 Daemon进程

适合用于 日志采集程序, 例如 Fluentd 或者 Logstach

适合用于 性能监控程序, 采集该 Node 的运行性能数据, 例如 Prometheus Node Exporter

支持设置 updateStrategy, 默认 RollingUpdate

Job (批处理调度)

通过 Kubernetes Job 资源对象来定义并启动一个批处理任务

批处理任务可以分为以下几种模式:

  • Job Template Expansion 模式: 一个 Job 对象对应一个待处理的 Work item, 有几个 Work item 就产生几个独立的 Job
  • Queue with Pod Per Work Item 模式: 采用一个任务队列存放 Work item, 一个 Job 对象作为消费者去完成这些 Work item, Job 会启动 N 个 Pod, 每个 Pod 都对应一个 Work item
  • Queue with Variable Pod Count 模式: 采用一个任务队列存放 Work item, 一个 Job 对象作为消费者去完成这些 Work item, Job 启动的 Pod 数量是可变的

CronJob (定时任务)

类似 Linux Cron 的定时任务

自定义调度器

一般情况下, 每个新 Pod 都会由默认的调度器进行调度

如果 Pod 中提供了自定义的调度器名称, 那么默认的调度器会忽略该 Pod, 转由指定的调度器完成 Pod 的调度

使用 spec.schedulerName 来指定

Init Container (初始化容器)

在启动 app contianer 之前启动一个或多个 init contianer, 完成 app container 所需的预置条件

init container 与 app container 本质上是一样的, 但它们是仅运行一次就结束的任务, 并且必须在成功执行完成后, 系统才能继续执行下一个容器

使用 spec.initContainers 来声明 init container

 

 

Pod 的升级和回滚

 

Deployment 的升级

 

假设有名称为 nginx-deployment, 镜像为 nginx:1.7.9 的 Deployment

 

通过 kubectl set image 命令为 Deployment 设置新的镜像名称: $ kubectl set image deployment/nginx-deployment nginx=:1.9.1

 

或者, 使用 kubectl edit 命令: $ kubectl edit deployment/nginx-deployment

 

使用 kubectl rollout status 命令查看 Deployment 的更新过程: $ kubectl rollout status deployment/nginx-deployment

 

默认的 spec.strategy Pod 更新策略为 RollingUpdate

 

RollingUpdate 可以设置 maxUnavailable 和 maxSurge, 分别默认为 25%

 

maxUnavailable 表示更新过程中最多不可用的 Pod 数量

 

maxSurge 表示更新过程中 Pod 总数超过 Pod 期望副本数部分的最大值

 

以上两个参数均以 期望副本数 为基础进行计算

 

spec.strategy 还可以设置为 Recreate, 表示先杀掉所有在运行的 Pod, 然后创建新的 Pod

 

不鼓励更新 Deployment 的标签选择器

 

Deployment 的回滚

 

首先, 使用 kubectl rollout history 命令检查 Deployment 的历史记录: $ kubectl rollout history deployment/nginx-deployment

 

在创建 Deployment 时使用 --record 参数, 就可以在 CHANGE-CAUSE 列看到每个版本使用的命令

 

Deployment 的更新操作是在 Deployment 进行部署 (Rollout) 时被触发的, 意味着当且仅当 Deployment 的 Pod 模板 (spec.template) 被更改时才会创建新的修订版本

 

这也意味着我们将 Deployment 回滚到之前的版本时, 只有 Deployment 的 Pod 模板部分会被修改

 

使用 --revision=<N> 参数查看特定版本的详细信息: $ kubectl rollout history deployment/nginx-deployment --revision=3

 

回滚到上一个版本: $ kubectl rollout undo deployment/nginx-deployment

 

使用 --to-revision 参数指定回滚到的部署版本号: $ kubectl rollout undo deployment/nginx-deployment --to-revision=2

 

暂停和恢复 Deployment 的部署操作

 

使用 kubectl rollout pause 命令暂停 Deployment 的更新操作: $ kubectl rollout pause deployment/nginx-deployment

 

然后可以修改 Deployment 的信息

 

最后, 使用 $ kubectl rollout resume deploy nginx-deployment 恢复这个 Deployment 的部署操作

 

在恢复暂停的 Deployment 之前, 无法回滚该 Deployment

 

0条评论
0 / 1000
李****灏
3文章数
0粉丝数
李****灏
3 文章 | 0 粉丝