美文网首页
kubernetes资源对象之pod

kubernetes资源对象之pod

作者: 一舍 | 来源:发表于2020-03-26 14:15 被阅读0次

Pod 是Kubernetes 集群中的基本单元,是最小并且最简单的 Kubernetes 对象,是 Kubernetes 调度的基本单位。

Pod 的设计理念是,支持多个容器在一个 Pod 中共享网络、存储以及 CPU、内存等资源,其具体特性如下:

  • 多个容器共享 IPC、Network 和 UTC namespace
  • 多个容器可直接通过 localhost 通信
  • 多个容器共享Volume,可以访问共享数据
  • 优雅终止,Pod 删除的时候先给其内的进程发送 SIGTERM,等待一段时间后才强制停止
  • 特权容器具有改变系统配置的权限

生命周期

pod的生命周期包括了pod的状态、init container、hooks、重启策略、健康检查

pod状态

Kubernetes 以 PodStatus.Phase 抽象 Pod 的状态,包括:

  • Pending 等待中
  • Running 运行中
  • Succeeded 正常终止
  • Failed 异常终止
  • Unknonwn 未知状态

Kubernetes以PodStatus.Conditions.type表示Pod更详细的condition状态,包括:

  • PodScheduled 调度中
  • Initialized 容器初始化完成
  • Ready 准备就绪,可以正常服务
  • Unschedulable 不能被调度

Kubernetes以PodStatus.containerStatuses.state表示容器的状态,包括:

  • waiting
  • created
  • running
  • exited
  • unknown

Kubernetes以PodStatus.containerStatuses.state.reason表示容器状态出现的可能原因,包括:

  • CrashLoopBackOff 容器退出,kubelet正在将它重启

  • InvalidImageName 无法解析镜像名称

  • ImageInspectError 无法校验镜像

  • ErrImageNeverPull 策略禁止拉取镜像

  • ImagePullBackOff 正在重试拉取

  • RegistryUnavailable 连接不到镜像中心

  • ErrImagePull 通用的拉取镜像出错

  • CreateContainerConfigError 不能创建kubelet使用的容器配置

  • CreateContainerError 创建容器失败

  • RunContainerError 启动容器失败

  • PostStartHookError 执行hook报错

  • ContainersNotInitialized 容器没有初始化完

  • ContainersNotReady 容器没有准备就绪

  • ContainerCreating 容器创建中

  • PodInitializing pod 初始化中

  • DockerDaemonNotReady Docker没有启动

  • NetworkPluginNotReady 网络插件没有启动

在Pod的生命周期里通常会产生各种事件Events,kubernetes事件的种类总共有4种,包括:

  • ADDED
  • MODIFIED
  • DELETED
  • ERROR

生命周期钩子

容器生命周期钩子(Container Lifecycle Hooks),监听容器生命周期的特定事件,并在事件发生时执行已注册的回调函数,支持两种钩子:

  • postStart 容器创建后立即执行,如果执行失败,容器会被杀死
  • preStop 容器终止前执行,如果执行失败,容器会被杀死

钩子的回调函数支持两种方式:

  • exec 在容器中执行命令,返回 0 则表示成功,否则表示失败
  • httpGet 对指定的容器 IP、端口和路径执行 HTTP Get 请求,返回状态码在 [200, 400] 之间则表示成功,否则表示失败
apiVersion: v1
kind: Pod
metadata:
  name: lifecycle
spec:
  containers:
  - name: lifecycle
    image: nginx
    lifecycle:
      postStart:
        httpGet:
          path: /
          port: 80
      preStop:
        exec:
          command: ["/usr/sbin/nginx","-s","quit"]

Init Container

Init 容器在所有容器运行之前执行,常用来初始化配置。

Init 容器会按顺序一次运行一个,每个 Init 容器必须运行成功,下一个才能够运行。

apiVersion: v1
kind: Pod
metadata:
  name: init
spec:
  initContainers:
  - name: install
    image: busybox
    command:
    - wget
    - "-O"
    - "/work-dir/index.html"
    - http://kubernetes.io
  containers:
  - name: nginx
    image: nginx

重启策略

Kubernetes 以PodSpec.restartPolicy设置是否对退出的 Pod 重启,包括:

  • Always
  • OnFailture
  • Never

注意,这里的重启是指在 Pod 所在 Node 上面本地重启,并不会调度到其他 Node 上去。

健康检查

Kubernetes 提供了两种探针(Probe)方式来探测容器的健康状态:

  • LivenessProbe 应用是否处于健康状态,如果不健康则重启容器
  • ReadinessProbe 应用是否处于正常服务状态,如果不正常则不接收来自Service 的流量

Kubernetes 提供了三种方式来执行探针:

  • exec 在容器中执行命令,返回 0 则表示探测成功,否则表示失败
  • tcpSocket 对指定的IP 和端口执行 TCP 检查,端口是开放的则表示探测成功,否则表示失败
  • httpGet 对指定的容器 IP、端口和路径执行 HTTP Get 请求,返回状态码在 [200, 400] 之间则表示探测成功,否则表示失败
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: nginx
  name: nginx
spec:
    containers:
    - image: nginx
      imagePullPolicy: Always
      name: http
      livenessProbe:
        httpGet:
          path: /
          port: 80
        initialDelaySeconds: 15
        periodSeconds: 20
        timeoutSeconds: 5
      readinessProbe:
        exec:
          command:
          - cat
          - /usr/share/nginx/html/index.html
        initialDelaySeconds: 5
        periodSeconds: 20
        timeoutSeconds: 5

私有镜像

在使用私有镜像时,需要创建一个 docker registry secret,并在容器中引用。

kubectl create secret docker-registry <your-registry-secret-name> --docker-server=<your-registry-server> --docker-username=<your-name> --docker-password=<your-pword> --docker-email=<your-email>

在引用 docker registry secret 时,有两种方法:

  • 直接在 Pod 描述文件中引用
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
    - name: nginx
      image: nginx
  imagePullSecrets:
    - name: <your-registry-secret-name>
  • 把 secret 添加到 service account 中,再通过 service account 引用
kubectl patch serviceaccount <your-serviceaccount> -p '{"imagePullSecrets": [{"name": "<your-registry-secret-name>"}]}'

拉取镜像时,支持三种拉取策略ImagePullPolicy,包括:

  • Always
  • IfNotPresent (默认)
  • Never

资源限制

Kubernetes 通过 cgroups 限制容器的 CPU 和内存等计算资源,包括 requests和limits。

requests.cpurequests.memory是调度cpu和内存的依据。

apiVersion: v1
kind: Pod
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  containers:
    - image: nginx
      name: nginx
      resources:
        requests:
          cpu: "300m"
          memory: "56Mi"
        limits:
          cpu: "1"
          memory: "128Mi"

带宽限制

Kubernetes通过注解(annotation )来限制 Pod 的网络带宽,包括:

  • kubernetes.io/ingress-bandwidth
  • kubernetes.io/egress-bandwidth
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  annotations:
    kubernetes.io/ingress-bandwidth: 3M
    kubernetes.io/egress-bandwidth: 4M
spec:

调度限制

Kubernetes通过nodeSelector、nodeAffinity、podAffinity 、Taints 和 tolerations 等来将 Pod 调度到需要的 Node 上。

限制Pod 调度到指定的 Node 节点上,有三种方式:

  • nodeSelector 选择指定标签的节点
  • nodeAffinity 选择指定亲和性的节点
  • podAffinity 指pod 间亲和与反亲和

限制Pod不允许调度到不合适的Node节点上,有两种方式:

  • Taints
  • Tolerations

nodeSelector

首先给节点打标签

kubectl label nodes node-1 app=nginx

然后在 nodeSelector中指定标签

spec:
  nodeSelector:
    app: nginx

除了自己添加的标签外,Kubernetes还预置了一组标准标签:

  • kubernetes.io/hostname
  • failure-domain.beta.kubernetes.io/zone
  • failure-domain.beta.kubernetes.io/region
  • beta.kubernetes.io/instance-type
  • kubernetes.io/os
  • kubernetes.io/arch

nodeAffinity

Affinity,即亲和性。亲和功能包含两种类型:

  • 节点亲和。约束节点标签,提供了比nodeSelector更为灵活的调度控制能力。
  • pod 间亲和/反亲和。约束 pod 标签。

调度策略分为软策略和硬策略:

  • 软策略指,如果节点没有满足调度条件,pod 会忽略这条规则,继续完成调度,即满足条件最好,没有满足也无所谓;
  • 硬策略指,如果没有满足条件的节点,就不断重试直到满足条件为止,即必须满足条件,不满足不行;

nodeAffinity目前支持两种条件选择:

  • requiredDuringSchedulingIgnoredDuringExecution 表示 pod 部署时节点必须满足的条件,如果没有满足条件的节点,就不断重试,即硬策略,仅将 pod 运行在满足条件的节点上
  • preferredDuringSchedulingIgnoredDuringExecution 表示优先选择满足条件的节点进行部署,如果没有满足条件的节点,就忽略这些条件,按照正常逻辑部署,即软策略,尝试将 pod 运行在满足条件的节点上

IgnoredDuringExecution,表示pod 部署之后,进入运行态时,如果节点标签发生了变化,不再满足 pod 指定的条件,pod 也还会继续运行,即亲和选择只在 pod 调度期间有效

节点亲和通过 PodSpec 的 affinity 字段下的 nodeAffinity 字段进行指定

apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/e2e-az-name
            operator: In
            values:
            - e2e-az1
            - e2e-az2
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: another-node-label-key
            operator: In
            values:
            - another-node-label-value

如果你指定了多个与 nodeAffinity 类型关联的 nodeSelectorTerms,则如果其中一个 nodeSelectorTerms 满足的话,pod将可以调度到节点上;

如果你指定了多个与 nodeSelectorTerms 关联的 matchExpressions,则只有当所有 matchExpressions 满足的话,pod 才会可以调度到节点上;

preferredDuringSchedulingIgnoredDuringExecution 中的 weight 字段值的范围是 1-100

节点亲和语法支持下面的操作符: InNotInExistsDoesNotExistGtLt,可以使用 NotInDoesNotExist 来实现节点反亲和行为

podAffinity

pod 间亲和与反亲和,podAffinitypodAntiAffinity,指可以基于pod的标签来约束 pod 可以调度到的节点,而不是基于节点的标签。

pod 间亲和与反亲和的规则是,基于已经在节点上运行的 pod 的标签来约束 pod 可以调度到的节点,可以这样理解,pod调度的时候选择(或者不选择)节点 N,取决于已经在这些节点上运行的pod的标签,和这些pod的标签是否满足条件 X,条件 X 是一组标签选择器,它必须指明作用的 namespace。

pod 间亲和与反亲和目前支持两种条件选择:

  • requiredDuringSchedulingIgnoredDuringExecution
  • preferredDuringSchedulingIgnoredDuringExecution

pod 间亲和与反亲和的设计需求来自哪里,我们可以看看它的一些实际使用场景:

  • 我们希望一些服务的pod可以调度到同一个节点,因为这些服务有比较强的关联性,比如webserver和redis;
  • 我们希望一些服务的pod副本可以分布到不同节点上,因为我们想要保证这些副本的可靠性,比如redis;

pod 间亲和与反亲和通过 PodSpec 的 affinity 字段下的podAffinitypodAntiAffinity字段进行指定

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server
spec:
  selector:
    matchLabels:
      app: web-store
  replicas: 3
  template:
    metadata:
      labels:
        app: web-store
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - web-store
            topologyKey: "kubernetes.io/hostname"
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - store
            topologyKey: "kubernetes.io/hostname"

Pod 亲和与反亲和的合法操作符有 InNotInExistsDoesNotExist

原则上,topologyKey 可以是任何合法的标签键。然而,出于性能和安全原因,topologyKey 受到一些限制:

  • 对于亲和与 requiredDuringSchedulingIgnoredDuringExecution 要求的 pod 反亲和,topologyKey 不允许为空;
  • 对于 requiredDuringSchedulingIgnoredDuringExecution 要求的 pod 反亲和,准入控制器 LimitPodHardAntiAffinityTopology 被引入来限制 topologyKey 不为 kubernetes.io/hostname。如果你想使它可用于自定义拓扑结构,你必须修改准入控制器或者禁用它;
  • 对于 preferredDuringSchedulingIgnoredDuringExecution 要求的 pod 反亲和,空的 topologyKey 被解释为“所有拓扑结构”(这里的“所有拓扑结构”限制为 kubernetes.io/hostnamefailure-domain.beta.kubernetes.io/zonefailure-domain.beta.kubernetes.io/region 的组合);
  • 除上述情况外,topologyKey 可以是任何合法的标签键;

Taints 和 tolerations

Taints 和 tolerations 用于保证 Pod 不被调度到不合适的 Node 上,其中 Taint 应用于 Node 上,而 toleration 则应用于 Pod 上。

目前支持的 taint 类型:

  • NoSchedule:新的 Pod 不允许调度到该 Node 上,不影响正在运行的 Pod
  • PreferNoSchedule:新的 Pod尽量不调度到该 Node 上
  • NoExecute:新的 Pod 不调度到该 Node 上,并且删除(evict)已在运行的 Pod,Pod 可以增加一个时间(tolerationSeconds)

首先,给节点打标签

kubectl taint nodes node1 key1=value1:NoSchedule

然后,在PodSpec 中中指定tolerations

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"

优先级调度

kube-scheduler 支持定义 Pod 的优先级,从而保证高优先级的 Pod 优先调度。

首先,定义一个 PriorityClass

apiVersion: v1
kind: PriorityClass
metadata:
  name: high-priority
value: 100
globalDefault: false
description: ""

value 为 32 位整数的优先级,该值越大,优先级越高

然后,在 PodSpec 中通过 PriorityClassName 设置 Pod 的优先级

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  priorityClassName: high-priority

增强功能

设置DNS访问策略

通过设置 dnsPolicy 参数可以设置pod访问DNS的策略,支持三种模式:

  • ClusterFirst 优先从coreDNS 查询 (默认策略)
  • Default 优先从Node 中配置的 DNS查询
  • None

设置pod子域名

通过subdomain 参数设置 Pod 的子域名,默认为空

设置pod的DNS选项

通过dnsConfig设置pod的DNS选项

apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: dns-example
spec:
  containers:
    - name: test
      image: nginx
  dnsPolicy: "None"
  dnsConfig:
    nameservers:
      - 1.2.3.4
    searches:
      - ns1.svc.cluster.local
      - my.dns.search.suffix

设置主机名

通过hostname参数设置主机名,如果未设置默认使用 metadata.name 参数的值作为 Pod 的 hostname

设置hosts文件

通过hostAliases增加/etc/hosts下的内容

apiVersion: v1
kind: Pod
metadata:
  name: hostaliases
spec:
  hostAliases:
  - ip: "10.0.0.1"
    hostnames:
    - "foo.local"
    - "bar.local"

设置使用Capabilities

默认情况下,容器都是以非特权容器的方式运行。比如,不能在容器中创建虚拟网卡、配置虚拟网络。

Kubernetes 提供了修改 Capabilities的机制,可以按需要给容器增加或删除。

apiVersion: v1
kind: Pod
metadata:
  name: cap-pod
spec:
  containers:
  - name: friendly-container
    image: "alpine:3.4"
    command: ["/bin/sleep", "3600"]
    securityContext:
      capabilities:
        add:
        - NET_ADMIN
        drop:
        - KILL

设置内核参数

通过securityContext.sysctls设置容器内核参数

apiVersion: v1
kind: Pod
metadata:
  name: sysctl-example
spec:
  securityContext:
    sysctls:
    - name: kernel.shm_rmid_forced
      value: "0"
    - name: net.ipv4.route.min_pmtu
      value: "552"

设置使用主机的IPC命名空间

通过设置 hostIPC 参数为 true,使用主机的 IPC 命名空间,默认为 false

设置使用主机的PID命名空间

通过设置 hostPID 参数为 true,使用主机的 PID 命名空间,默认为 false

设置使用主机的Network命名空间

通过设置 hostNetwork参数为 true,使用主机的Network命名空间,默认为 false

相关文章

网友评论

      本文标题:kubernetes资源对象之pod

      本文链接:https://www.haomeiwen.com/subject/yyhcuhtx.html