Kubernetes指南:深入理解pod

发布于 2018-11-25 · 本文总共 18587 字 · 阅读大约需要 54 分钟

定义

pod定义:

apiVersion: v1
kind: Pod
metadata:
  name: string
  namespce: string
  labels:
    - nane: string
  annotations:
    - name: string
spec:
  containers:
  - name: string
    image: string
    imagePullPolicy: Always/Never/IfnotPresent
    command: [string]
    args: [string]
    workingDir: string
    volumeMounts:
    - name: string
      mountPath: string
      readOnly: boolean
    ports:
    - name: string
      containerPort: int
      hostPort: int
      protocol: string
    env:
    - name: string
      value: string
    resources:
      limits:
        cpu: string
        memory: string
      requests:
        cpu: string
        memory: string
    livenessprobe:
      exec:
        command: [string]
      httpGet:
        path: string
        port: number
        host: string
        scheme: string
        httpHeaders:
        - name: string
          value: string
      tcpSocket:
        port: number
      initialDelaySeconds: int
      timeoutSeconds: int
      periodSeconds: int
      successThreshold: int
      failureThreshold: int
    securityContext:
      privileged: false
  restartPolicy: Always/Never/OnFailure
  nodeSelector: object
  imagePullSecrets:
  - name: string
  hostNetwork: boolean
  volumes:
  - name: string
    emptyDir: []
    hostPath:
      path: string
    secret:
      secretName: string
      items:
      - key: string
        path: string
    configMap:
      name: string
      items:
      - key: string
        path: string

属性说明:

属性名称 类型 是否必选 取值说明
spec.containers.command list   容器的启动命令列表,如果不指定,则使用镜像打包时使用的启动命令
spec.containers.args list   容器启动命令参数列表
spec.containers.workingDir string   容器工作目录
spec.containers.volumeMounts list   挂载到容器内部的存储卷配置
spec.containers.volumeMounts.name string   引用Pod定义的共享存储卷的名称,需使用volumes部分定义的共享存储卷名称
spec.containers.volumeMounts.mountPath string   存储卷在容器内Mount的绝对路径
spec.containers.volumeMounts.readOnly boolean   是否为只读模式,默认为读写模式
spec.containers.ports list   容器需要暴露的端口号列表
spec.containers.ports.name string   端口名称
spec.containers.ports.containerPort int   容器需要监听的端口号
spec.containers.ports.hostPort int   容器所在主机需要监听的端口号
spec.containers.ports.protocol string   端口协议,支持TCP和UDP,默认为TCP
spec.containers.resources object   资源限制和资源请求的设置
spec.containers.resources.limits object   资源限制的设置
spec.containers.resources.limits.cpu string   CPU限制,单位为core数,将用于docker run –cpu-shares参数
spec.containers.resources.limits.memory string   内存限制,单位可以是MiB、GiB等,将用于docker run –memory参数
spec.containers.resources.requests object   资源限制的设置
spec.containers.resources.requests.cpu string   CPU请求,单位为core数,容器启动的初始可用数量
spec.containers.resources.requests.memory string   内存请求,单位可以为MiB、GiB等,容器启动的初始可用数量
spec.volumes List   在Pod上定义的共享存储卷列表
spec.volumes.name string   共享存储卷的名称,在一个Pod中每个存储卷定义一个名称
spec.volumes.emptyDir object   类型为emptyDir的存储卷,表示与Pod同生命周期的一个临时目录,其值为一个空对象,emptyDir:{}
spec.volumes.hostPath object   类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录,通过volumes.hostPath.path指定
spec.volumes.hostPath.path string   Pod所在主机的目录,将被用于容器中mount的目录
spec.volumes.secret object   类型为secret的存储卷,表示挂载集群预定义的secret对象到容器内部
spec.volumes.configMap object   类型为configMap的存储卷,表示挂载集群预定义的configMap对象到容器内部
spec.volumes.livenessProbe object   健康检查设置,当探测无响应几次之后,系统将自动重启该容器
spec.volumes.livenessProbe.exec object   对Pod内各容器健康检查的设置,exec方式
spec.volumes.livenessProbe.exec.command string   exec方式需要指定的命令或者脚本
spec.volumes.livenessProbe.httpGet object   对Pod内各容器健康检查的设置,HTTP GET方式,需指定path、port
spec.volumes.livenessProbe.tcpSocket objcet   tcpSocket方式
spec.volumes.livenessProbe.initialDelaySecond number   容器启动完成后首次探测的时间,单位为s
spec.volumes.livenessProbe.timeoutSeconds number   探测等待响应的超时时间设置,单位s,默认为1s,若超过该时间,则认为容器不健康,会重启该容器
spec.volumes.livenessProbe.periodSeconds number   定期探测时间设置,单位s,默认10s探测一次
spec.restartPolicy string   Pod重启策略,可选值为Always、OnFailure、Never
spec.nodeSelector object   设置node的label,以key:value格式指定,Pod将被调度到具有这些Label的Node上
spec.imagePullSecrets object   pull镜像时使用的Secret名称,以name:secretkey格式指定
spec.hostNetwork boolean   是否使用主机网络模式,默认为false,设置true表示容器使用宿主机网络,不再使用Docker网桥

基本用法

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

对于无法改造为前台执行的应用,也可以使用开源工具Supervisor辅助进行前台运行的功能。 Supervisor提供了一种可以同时启动多个后台应用,并保持Supervisor自身在前台执行的机制;

Pod可以由1个或多个容器组合而成;

当多个容器应用为紧耦合的关系, 并组合成一个整体对外提供服务时, 应将这两个容器打包为一个Pod;

apiVersion: v1
kind: Pod
metadata:
 name: api-server
 labels:
  name: api-server
spec:
 containers:
 - name: backend
   image: xxx/xxx:v1
   ports:
   - containerPort: 80
 - name: db
   image: xxx/xxx:v1
   ports:
   - containerPort: 3306

属于同一个Pod的多个容器应用之间相互访问时仅需要通过localhost就可以通信,使得这一组容器被“绑定”在了一个环境中;

静态Pod

静态Pod是由kubelet进行管理的仅存在于特定Node上的Pod。 它们不能通过API Server进行管理,无法与ReplicationController、Deployment或者DaemonSet进行关联, 并且kubelet无法对它们进行健康检查。 静态Pod总是由kubelet创建的,并且总在kubelet所在的Node上运行;

Pod共享Volume

同一个Pod中的多个容器能够共享Pod级别的存储卷Volume。 Volume可以被定义为各种类型,多个容器各自进行挂载操作,将一个Volume挂载为容器内部需要的目录;

apiVersion: v1
kind: Pod
metadata:
 name: api-server
 labels:
  name: api-server
spec:
 containers:
 - name: backend
   image: xxx/xxx:v1
   ports:
   - containerPort: 80
   volumeMounts:
   - name: app-logs
     mountPath: /var/api/logs
 - name: log-reader
   image: xxx/xxx:v1
   command: ["sh", "-c", "tail -f /logs/xxx*.log"]
   volumeMounts:
   - name: app-logs
     mountPath: /logs
 volumes:
  - name: app-logs
    emptyDir: {}

设置的Volume名为app-logs,类型为emptyDir(也可以设置为其他类型), 挂载到backend容器内的/var/api/logs目录,同时挂载到log-reader容器内的/logs目录;

backend容器在启动后会向/var/api/logs目录写文件,log-reader容器就可以读取其中的文件了;

Pod配置管理

从Kubernetes 1.2开始提供了一种统一的应用配置管理方案—ConfigMap;

ConfigMap

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

1.生成为容器内的环境变量;

2.设置容器启动命令的启动参数(需设置为环境变量);

3.以Volume的形式挂载为容器内部的文件或目录;

ConfigMap以一个或多个key:value的形式保存在Kubernetes系统中供应用使用,既可以用于表示一个变量的值(例如apploglevel=info), 也可以用于表示一个完整配置文件的内容;

可以通过YAML配置文件或者直接使用kubectl create configmap命令行的方式来创建ConfigMap:

  • yaml文件创建:
    apiVersion: v1
    kind: ConfigMap
    metadata:
     name: cm-test
    data:
     app-log-level: info
     app-data-dir: /var/data
    
  • 使用kubectl命令直接创建:
kubectl create configmap configmap_test --from-literal=server_port=8001
kubectl create configmap configmap_test --from-literal=server_port=8001 --from-literal=server_host=127.0.0.1
kubectl get configmap configmap_test -o yaml
kubectl create -f configmap_test.yaml
  • 从文件内容创建configmap:
kubectl create config my_config --from-file=config_file.conf

key:config_file.conf, value: file data

kubectl create config my_config --from-file=test_key=config_file.conf

key:test_key, value: file data

  • 从文件夹创建:
kubectl create config my_config --from-file=test_key=/path/to/dir

在Pod中使用ConfigMap

1.给容器传递configmap条目作为环境变量

env:
- name: SERVER_PORT
  valueFrom:
    configMapKeyRef:
      name:my_config
      key:test_key

在pod中引用不存在的configmap容器会启动失败,可以设置configMapKeyRef.optional:true解决

2.一次性传递configmap的所有条目作为环境变量

envFrom:
- prefix: CONFIG_
  configMapKeyRef:
    name:my_config

3.传递configmap内容作为命令行参数

env:
- name: SERVER_PORT
  valueFrom:
    configMapKeyRef:
      name:my_config
      key:test_key
args: ["$(SERVER_PORT)"]

4.使用configmap卷将条目暴露为文件

volumeMounts:
- name: config
  mountPath: /etc/nginx/conf.d // 也可以挂载至某一文件/etc/nginx/my.conf
  subPath: myconfig.conf //仅挂载指定的条目
  readOnly: true

- name: config
  configMap:
    name: my_config
    defaultMode: "6600" // 设置所有文件的权限为-rw-rw-----

更新配置是否需要重启程序?

1.使用环境变量或者命令行参数作为配置—-需要重启

2.将configmap暴露为卷—-可以热更新,无需重新创建pod或者重启容器

使用ConfigMap的限制条件

使用ConfigMap的限制条件如下:

  • ConfigMap必须在Pod之前创建;

  • ConfigMap受Namespace限制,只有处于相同Namespace中的 Pod才可以引用它;

  • ConfigMap中的配额管理还未能实现;

  • kubelet只支持可以被API Server管理的Pod使用ConfigMap。 kubelet在本Node上通过–manifest-url或–config自动创建的静态Pod将无法引用ConfigMap;

  • 在Pod对ConfigMap进行挂载(volumeMount)操作时,在容器内部只能挂载为“目录”,无法挂载为“文件”; 在挂载到容器内部后,在目录下将包含ConfigMap定义的每个item,如果在该目录下原来还有其他文件,则容器内的该目录将被挂载的ConfigMap覆盖。 如果应用程序需要保留原来的其他文件,则需要进行额外的处理。 可以将ConfigMap挂载到容器内部的临时目录,再通过启动脚本将配置文件复制或者链接到(cp或link命令)应用所用的实际配置目录下;

Pod生命周期和重启策略

  • Pending:创建pod的请求已经被k8s接受,但是容器并没有启动成功, 可能处在:写数据到etcd,调度,pull镜像,启动容器这四个阶段中的任何一个阶段, pending伴随的事件通常会有:ADDED, Modified这两个事件的产生。

  • Running:pod已经绑定到node节点,并且所有的容器已经启动成功, 或者至少有一个容器在运行,或者在重启中。

  • Succeeded:pod中的所有的容器已经正常的自行退出,并且k8s永远不会自动重启这些容器, 一般会是在部署job的时候会出现。

  • Failed:pod中的所有容器已经终止,并且至少有一个容器已经终止于失败(退出非零退出代码或被系统停止)。

  • Unknown:由于某种原因,无法获得pod的状态,通常是由于与pod的主机通信错误。

Pod的重启策略(RestartPolicy)应用于Pod内的所有容器,并且仅在Pod所处的Node上由kubelet进行判断和重启操作。 当某个容器异常退出或者健康检查失败时,kubelet将根据RestartPolicy的设置来进行相应的操作;

Pod的重启策略包括Always、OnFailure和Never,默认值为Always;

  • Always: 当容器失效时,由kubelet自动重启该容器;

  • OnFailure: 当容器终止运行且退出码不为0时,由kubelet自动重启该容器;

  • Never: 不论容器运行状态如何,kubelet都不会重启该容器;

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

LivenessProbe探针: 用于判断容器是否存活(Running状态),如果LivenessProbe探针探测到容器不健康, 则kubelet将杀掉该容器,并根据容器的重启策略做相应的处理; 如果一个容器不包含LivenessProbe探针,那么kubelet认为该容器的LivenessProbe探针返回的值永远是Success;

ReadinessProbe探针: 用于判断容器服务是否可用(Ready状态),达到Ready状态的Pod才可以接收请求。 对于被Service管理的Pod,Service与Pod Endpoint的关联关系也将基于Pod是否Ready进行设置。 如果在运行过程中Ready状态变为False,则系统自动将其从Service的后端Endpoint列表中隔离出去, 后续再把恢复到Ready状态的Pod加回后端Endpoint列表。这样就能保证客户端在访问Service时不会被转发到服务不可用的Pod实例上;

探针的三种实现方式;

1.ExecAction: 在容器内部执行一个命令,如果该命令的返回码为0,则表明容器健康;

2.TCPSocketAction: 通过容器的IP地址和端口号执行TCP检查,如果能够建立TCP连接,则表明容器健康;

3.HTTPGetAction: 通过容器的IP地址、端口号及路径调用HTTP Get方法,如果响应的状态码大于等于200且小于400,则认为容器健康;

Pod调度

控制器被删除后,归属于控制器的Pod副本该何去何从? 在Kubernates 1.9之前,在RC等对象被删除后,它们所创建的Pod 副本都不会被删除; 在Kubernates 1.9以后,这些Pod副本会被一并删除。 如果不希望这样做,则可以通过kubectl命令的–cascade=false参数来取消这一默认特性: kubectl delete replicaset my-repset --cascade=false

Deployment

Deployment或者RC的主要功能之一就是自动部署一个容器应用的多副本, 以及持续监控副本的数量,在集群内始终维持指定的副本数量;

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  repicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: xxx
        ports:
        - containerPort: 80

Deloyment的pod最终运行在那个节点上,完全由Master的scheduler经过一系列算法得出, 用户无法干预调度过程和结果;

Kubernetes也提供多种丰富的调度策略,用户只需在Pod的定义中使用NodeSelector、 NodeAffinity、PodAffinity、Pod驱逐等更加细粒度的调度策略设置, 就能完成对Pod的精准调度;

NodeSelector: 定向调度

如果需要将Pod调度到指定的某类Node上,可以通过Node的标签和pod的nodeSelector属性相匹配来实现;

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

亲和性调度

NodeSelector通过标签的方式,简单实现了限制Pod所在节点的方法; 亲和性调度机制则极大扩展了Pod的调度能力,主要增强功能包括:

1.不仅仅是“符合全部”的简单情况,更具表达力;

2.可以使用软限制、优先采用等限制方式,在调度器无法满足优先需求的情况下, 会退而求其次,继续运行该pod;

3.可以根据节点上正在运行的其他Pod标签来进行限制,而非节点本身的标签; (限制pod之间的亲和或者互斥关系)

NodeAffinity:Node亲和性调度

1.RequiredDuringSchedulingIgnoredDuringExecution

必须满足指定规则才可以调度Pod到Node上

2.PreferredDuringSchedulingIgnoredDuringExecution

优先满足指定规则,调度器会尝试调度Pod到Node上,但并不强求,相当于软限制;

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

spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - nodeSelectorTerms:
        - matchExpressions:
          - key: xxx
            operator: IN
            values:
            - xxxx

如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都得到满足, Pod才能最终运行在指定的Node上。

如果nodeAffinity指定了多个nodeSelectorTerms,那么其中一个能够匹配成功即可。

如果在nodeSelectorTerms中有多个matchExpressions, 则一个节点必须满足所有matchExpressions才能运行该Pod

PodAffinity:Pod亲和与互斥调度策略

Kubernetes1.4版本引入,可以根据节点上正在运行的Pod的标签而不是节点的标签进行判断和调度, 要求对节点和Pod两个条件进行匹配;

这种规则可以描述为:如果在具有标签X的Node上运行了一个或者多个符合条件Y的Pod, 那么Pod应该(如果是互斥,则拒绝)运行在这个Node上;

Pod亲和与互斥的条件设置也是 requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution; Pod的亲和性被定义于PodSpec的affinity字段下的podAffinity子字段中; Pod间的互斥性则被定义于同一层次的podAntiAffinity子字段中;

亲和性调度:

apiVersion: v1
kind: Pod
metadata:
  name: pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - xxx
        topologyKey: failure-domain.beta.kubernetes.io/zone
  containers:
  - name: xxxx
    image: xxxxxx

互斥性调度:

apiVersion: v1
kind: Pod
metadata:
  name: anti-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - xxx
        topologyKey: failure-domain.beta.kubernetes.io/zone
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - nginx
        topologyKey: kubernetes.io/hostname
  containers:
  - name: xxxx
    image: xxxxxx

Taints and Tolerations

Taints(污点)和Tolerations(容忍)

从Kubernetes 1.6开始提供的高级调度功能。

Node affinity, is a property of Pods that attracts them to a set of nodes (either as a preference or a hard requirement). Taints are the opposite – they allow a node to repel a set of pods.

Tolerations are applied to pods, and allow (but do not require) the pods to schedule onto nodes with matching taints.

Taints and tolerations work together to ensure that pods are not scheduled onto inappropriate nodes. One or more taints are applied to a node; this marks that the node should not accept any pods that do not tolerate the taints.

NoSchedule:表示k8s将不会将Pod调度到具有该污点的Node上

PreferNoSchedule:表示k8s将尽量避免将Pod调度到具有该污点的Node上

NoExecute:表示k8s将不会将Pod调度到具有该污点的Node上,同时会将Node上已经存在的Pod驱逐出去

实践

  • 设置污点

kubectl taint nodes node1 key1=value1:NoSchedule

  • 去除污点

kubectl taint nodes node1 key1:NoSchedule-

设置污点:不调度到master节点 kubectl taint nodes node-role.kubernetes.io/master=:NoSchedule

去除污点: kubectl taint nodes node-role.kubernetes.io/master:NoSchedule-

describe node:

root@qwq-test04:~# kubectl describe node qwq-test04
Name:               qwq-test04
Roles:              master
Labels:             beta.kubernetes.io/arch=arm64
                    beta.kubernetes.io/os=linux
                    kubernetes.io/arch=arm64
                    kubernetes.io/hostname=qwq-test04
                    kubernetes.io/os=linux
                    node-role.kubernetes.io/master=
Annotations:        flannel.alpha.coreos.com/backend-data: {"VtepMAC":"0e:98:26:74:72:69"}
                    flannel.alpha.coreos.com/backend-type: vxlan
                    flannel.alpha.coreos.com/kube-subnet-manager: true
                    flannel.alpha.coreos.com/public-ip: 12.0.0.192
                    kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock
                    node.alpha.kubernetes.io/ttl: 0
                    volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp:  Thu, 12 Nov 2020 16:00:16 +0800
Taints:             node-role.kubernetes.io/master:NoSchedule

Taints: node-role.kubernetes.io/master:NoSchedule

也可以使用–all:

qwq@qiuwenqi-node:~/go/src/KubeVMI$ kubectl taint nodes --all node-role.kubernetes.io/master-
node/qiuwenqi-node untainted

Pod Priority Preemption:Pod优先级调度

提高资源利用率的常规做法是采用优先级方案,即不同类型的负载对应不同的优先级, 同时允许集群中的所有负载所需的资源总量超过集群可提供的资源,在这种情况下, 当发生资源不足的情况时,系统可以选择释放一些不重要的负载(优先级最低的), 保障最重要的负载能够获取足够的资源稳定运行;

基于Pod优先级抢占的调度策略在Kubernetes 1.14版本中正式 Release;

apiVersion: scheduling.k8s.io/v1beta1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
description: "This priority class should be used for xxx service pods only"

value数字越大,优先级越高,超过一亿的数字被系统保留,用于指派给系统组件;

可以在pod中引用上述Pod优先级类别:

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

使用优先级抢占的调度策略可能会导致某些Pod永远无法被成功调度; 因此优先级调度不但增加了系统的复杂性,还可能带来额外不稳定的因素;

DaemonSet:在每个Node都调度一个Pod

DaemonSet是Kubernetes1.2版本新增的一种资源对象, 用于管理在集群中每个Node上仅运行一份Pod的副本实例;

一般用于存储、日志采集、性能监控等程序;

Job:批处理调度

Kubernetes从1.2版本开始支持批处理类型的应用, 可以通过Kubernetes Job资源对象来定义并启动一个批处理任务。 批处理任务通常并行(或者串行)启动多个计算进程去处理一批工作项(work item), 处理完成后,整个批处理任务结束;

Cronjob:定时任务

Kubernetes从1.5版本开始增加了一种新类型的Job, 即类似Linux Cron的定时任务Cron Job;

schedule格式:Minutes Hours DayofMonth Month DayofWeek year

apiVersion: batch/v1
kind: CronJob
metadata:
  name: xxx
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec: 
          containers:
          - name: xxx
            image: xxxxx
            args:
            - /bin/sh
            - -c
            - date;echo Hello,this is a cron job;
          restartPolicy: OnFailure

kubectl get jobs –watch

在Kubernetes 1.9版本后,kubectl命令增加了别名cj来表示cronjob, 同时kubectl set image/env命令也可以作用在CronJob对象上了;

自定义调度器

从1.6版本开始,Kubernetes的多调度器特性也进入了快速发展阶段;

一般情况下,每个新Pod都会由默认的调度器进行调度; 如果在Pod中提供了自定义的调度器名称,那么默认的调度器会忽略该Pod, 转由指定的调度器完成Pod的调度;

apiVersion: v1
kind: Pod
metadta:
  name: xxx
  labels:
    xxx: xxx
spec:
  schedulerName: xxxx
  containers:
  - name: xxxx
    image: xxxxxx

如果自定义的调度器还未在系统中部署,则默认的调度器会忽略这个Pod, 这个pod将一直处于Pending状态;

初始化容器(Init Container)

在很多应用场景中,应用在启动之前都需要进行如下初始化操作:

  • 等待其他关联组件正确运行(例如数据库或某个后台服务);

  • 基于环境变量或配置模板生成配置文件;

  • 从远程数据库获取本地所需配置,或者将自身注册到某个中央数据库中;

  • 下载相关依赖包,或者对系统进行一些预配置操作;

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

根据Pod的重启策略(RestartPolicy),当init container执行失败,而且设置了RestartPolicy=Never时,Pod将会启动失败; 而设置RestartPolicy=Always时,Pod将会被系统自动重启;

init container与应用容器的区别

1.init container的运行方式与应用容器不同,它们必须先于应用容器执行完成, 当设置了多个init container时,将按顺序逐个运行, 并且只有前一个init container运行成功后才能运行后一个init container; 当所有init container都成功运行后,Kubernetes才会初始化Pod的各种信息, 并开始创建和运行应用容器;

2.在init container的定义中也可以设置资源限制、Volume的使用和安全策略等等。 但资源限制的设置与应用容器略有不同;

如果多个init container都定义了资源请求/资源限制,则取最大的值作为所有init container的资源请求值/资源限制值;

Pod的有效(effective)资源请求值/资源限制值取以下二者中的较大值: a)所有应用容器的资源请求值/资源限制值之和; b)init container的有效资源请求值/资源限制值;

3.init container不能设置readinessProbe探针, 因为必须在它们成功运行后才能继续运行在Pod中定义的普通容器;

Pod升级和回滚

Deployment的升级

一旦镜像名(或Pod定义)发生了修改,则将触发系统完成Deployment所有运行Pod的滚动升级操作; 可以使用kubectl rollout status 命令查看Deployment的更新过程;

初始创建Deployment时,系统创建了一个ReplicaSet,并按用户的需求创建了3个Pod副本; 当更新Deployment时,系统创建了一个新的ReplicaSet,并将其副本数量扩展到1, 然后将旧的ReplicaSet缩减为2; 之后,系统继续按照相同的更新策略对新旧两个ReplicaSet进行逐个调整; 最后,新的ReplicaSet运行了3个新版本Pod副本,旧的ReplicaSet副本数量则缩减为0;

kubectl set image deployment/xxxx iamge_name

Deployment的回滚

kubectl rollout history deployment/xxxx

kubectl rollout history deployment/xxxxx –revision=3

撤销本次发布并回滚到上一个部署版本: kubectl rollout undo deployment/xxxxx

–to-revision指定回滚到的部署版本: kubectl rollout undo deployment/xxxx –to-revision=2

暂停和恢复Deployment部署操作

kubectl rollout pause deployment/xxx

kubectl set image deploy/xxxx image_name

kubectl rollout resume deploy xxxx

rolling-update滚动升级

kubectl rolling-update命令创建了一个新的RC, 然后自动控制旧的RC中的Pod副本数量逐渐减少到0, 同时新的RC中的Pod副本数量从0逐步增加到目标值,来完成Pod的升级;

kubectl rolling-update xxxxx –image=xxxx

RC的滚动升级不具有Deployment在应用版本升级过程中的历史记录、新旧版本数量的精细控制等功能, 在Kubernetes的演进过程中,RC将逐渐被RS和Deployment所取代, 建议优先考虑使用Deployment完成Pod的部署和升级操作;

其他管理对象的更新策略

从1.6版本开始,对DaemonSet和StatefulSet的更新策略也引入类似于Deployment的滚动升级;

DeamonSet

两种升级策略:

1.OnDelete:在创建好新的DaemonSet之后,新的Pod并不会被自动创建, 直到用户手动删除旧版本的Pod,才触发新建操作;

2.RollingUpdate:1.6版本之后引入; 更新时,旧版本的Pod将被自动杀掉,然后自动创建新版本的DaemonSet Pod;

StatefulSet

从1.6版本开始,针对StatefulSet的更新策略逐渐向Deployment和DaemonSet的更新策略看齐;

pod扩缩容

手动模式通过执行kubectl scale命令或通过RESTful API对一个Deployment/RC进行Pod副本数量的设置,即可一键完成; 自动模式则需要用户根据某个性能指标或者自定义业务指标,并指定Pod副本数量的范围, 系统将自动在这个范围内根据性能指标的变化进行调整;

手动扩缩容机制

kubectl scale deployment nginx-deployment --replicas 5

自动扩缩容机制

Kubernetes从1.1版本开始,新增了名为Horizontal Pod Autoscaler(HPA)的控制器, 用于实现基于CPU使用率进行自动Pod扩缩容的功能;

HPA控制器基于Master的kube-controller-manager服务启动参数 –horizontal-pod-autoscaler-sync-period定义的探测周期(默认值为 15s), 周期性地监测目标Pod的资源性能指标,并与HPA资源对象中的扩缩容条件进行对比,在满足条件时对Pod副本数量进行调整;

Kubernetes在早期版本中,只能基于Pod的CPU使用率进行自动扩缩容操作,关于CPU使用率的数据来源于Heapster组件。 Kubernetes从1.6版本开始,引入了基于应用自定义性能指标的HPA机制,并在1.9版本之后逐步成熟;

HPA工作原理

Kubernetes中的某个Metrics Server(Heapster或自定义Metrics Server)持续采集所有Pod副本的指标数据;

HPA控制器通过Metrics Server的API(Heapster的API或聚合API)获取这些数据, 基于用户定义的扩缩容规则进行计算,得到目标Pod副本数量;

当目标Pod副本数量与当前副本数量不同时,HPA控制器就向Pod的副本控制器 (Deployment、RC或ReplicaSet)发起scale操作, 调整Pod的副本数量,完成扩缩容操作;

指标类型

controller-manager服务持续监测目标Pod的某种性能指标,以计算是否需要调整副本数量; 目前支持的指标类型包括:

1.Pod资源使用率:Pod级别的性能指标,通常是一个比率值,如CPU使用率;

2.Pod自定义指标:通常是一个数值,如接收的请求数量;

3.Object自定义指标或外部自定义指标:通常是一个数值,需要容器应用以某种方式提供, 例如通过HTTP URL“/metrics”提供,或者使用外部服务提供的指标采集URL;

Kubernetes从1.11版本开始,弃用基于Heapster组件完成Pod的CPU使用率采集的机制, 全面转向基于Metrics Server完成数据采集; Metrics Server将采集到的Pod性能指标数据通过聚合API(Aggregated API)如metrics.k8s.io、 custom.metrics.k8s.io和external.metrics.k8s.io提供给HPA控制器进行查询;

扩缩容算法

Autoscaler控制器从聚合API获取到Pod性能指标数据之后, 基于一定的算法计算出目标Pod副本数量,与当前运行的Pod副本数量进行对比, 决定是否需要进行扩缩容操作;

HPA配置详解

Kubernetes将HorizontalPodAutoscaler资源对象提供给用户来定义扩缩容的规则;

1.基于autoscaling/v1版本的HorizontalPodAutoscaler配置,仅可以设置CPU使用率:

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: xxxx
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: xxxx
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50

为了使用autoscaling/v1版本的HorizontalPodAutoscaler, 需要预先安装Heapster组件或Metrics Server,用于采集Pod的CPU使用率; Heapster从Kubernetes1.11版本开始进入弃用阶段;

2.基于autoscaling/v2beta2的HorizontalPodAutoscaler配置:

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: xxxx
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: xxxx
  minReplicas: 1
  maxReplicas: 10
  metrics: 
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        avarageUtilization: 50

metrics:目标指标值; 在metrics中通过参数type定义指标的类型; 通过参数target定义相应的指标目标值,系统将在指标数据达到目标值时触发扩缩容操作;

metrics中的type(指标类型)设置为以下三种,可以设置一个或多个组合:

1.Resource:基于资源的指标值,可以设置的资源为CPU和内存;

2.Pods:基于Pod的指标,系统将对全部Pod副本的指标值进行平均值计算;

3.Object:基于某种资源对象(如Ingress)的指标或应用系统的任意自定义指标;

refs

https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/

https://blog.frognew.com/2018/05/taint-and-toleration.html

《Kubernetes:The Definitive Guide》

https://github.com/kubernetes/kubernetes/blob/master/docs/design/podaffinity.md




本博客所有文章采用的授权方式为 自由转载-非商用-非衍生-保持署名 ,转载请务必注明出处,谢谢。
声明:
本博客欢迎转发,但请保留原作者信息!
博客地址:邱文奇(qiuwenqi)的博客;
内容系本人学习、研究和总结,如有雷同,实属荣幸!
阅读次数:

文章评论

comments powered by Disqus


章节列表