K8s Pod和namespace

什么是Pod

Pod是Kubernetes中可以创建和部署的最小单位。

Pod为一个或多个container的组合,K8s为了便于管理container,将他们封装为pod。

Pod的特点

Pod的特点:

  • Pod包含1到多个container
  • 同一Pod中的container只会运行在同一个节点中。不可能跨节点。

每个container只运行一个应用进程。如果应用包含多个进程,需要使用多个container。Pod将这些相关的container组合到一起。

一个Pod中的所有container:

  • 使用同一个namespace
  • 共享同一个hostname和网络接口
  • 文件系统完全隔离,不共享

同一pod的container如果绑定同一个端口会存在端口冲突。但不同的pod中的container不会存在此问题。

pod是kubernetes管理的最小单位。pod当然也是应用水平扩展(运行多个实例)时的最小单位。

多层应用需要拆分到多个pod。

同一个pod包含的container用途需要紧密相关。

pod没有自愈能力,也没有横向扩展能力。因此生产中pod需要和controller配合使用。

在K8s中,pod被认为是一种临时的对象。

数据卷(volume)和pod具有相同的生命周期,如果pod删除后重新创建,这个pod关联的数据卷也会删除并重建。

网络

每一个pod分配一个独立的IP地址。同一个pod使用同一个网络namespace。位于同一个pod内的所有container都是用相同的网络namespace,包括IP地址和端口号。这些container可以通过localhost的方式访问其他的container。

存储

可以为pod指定一个或多个共享的数据卷(volume)。pod内的所有container都可以访问这个数据卷。

Pod终止过程

以pod的删除过程为例说明下pod是终止过程。

  1. 用户发出删除pod指令,默认pod删除宽限时间为30秒。
  2. API server中该pod的状态被更新。Pod在宽限时间之后会被认为dead。
  3. Pod进入Terminating状态。
  4. 和步骤3同时进行。当kubelet发现API server中Pod被标记为terminating,开始终止pod的过程。如果pod定义了preStop hook,调用preStop hook的逻辑。如果preStop过程在宽限时间到之后仍在运行,kubelet会请求额外的2秒宽限时间。接下来发送TERM信号到container。
  5. 和步骤3同时进行。pod从endpoint中移除。service不会再转发流量到这个pod。并且controller不再认为这个pod处于运行状态。
  6. 当宽限时间到达之时,发送SIGKILL指令到pod中所有进程。
  7. Kubelet完成删除pod过程,告诉API server设置宽限时间为0,意味着立即删除。Pod消失,再也不会被客户端查询到。

可以使用

kubectl delete pod ... --grace-period=<seconds>

覆盖默认的宽限时间。

可以使用如下命令强制删除pod

kubectl delete pod ... --grace-period=0 --force

Pod描述文件模板

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
apiVersion: v1
kind: Pod
metadata:
    name: kubia-manual
spec:
    containers:
        - image: luksa/kubia
          name: kubia
          ports:
          - containerPort: 8080
            protocol: TCP

注意:修改pod template不会对已经创建出的pod生效。

Pod Phase

PodStatus(pod 状态)具有一个phase字段。

PodPhase的可能值和解释:

描述
Pending k8s已接收到,但是container没有被创建。pod被调度或者在下载镜像的时候也是Pending状态
Running pod被分配到某个node,pod中所有container都被创建。至少一个container在运行中,或者处于启动中,重启中状态
Succeeded pod中所有的container以succeeded状态结束,不会再重启
Failed 所有的container已终止运行,其中至少一个container以failed状态结束
Unknown 无法获取pod状态,典型的情况为和pod所在主机通信异常

Pod Condition

PodStatus有一个PodConditions字段。该字段是一个数组,有如下6个部分:

  • lastProbeTime: 上一次更新pod情况的时间。
  • lastTransitionTime: 上一次pod状态变更的时间。
  • message: 状态变更的详细描述。
  • reason: 一个驼峰命名的单词描述上次状态变更的原因。
  • status: True False或Unknown。
  • type: 有如下值
    • PodScheduled: pod被调度到了node
    • Ready: pod可以接受请求。归service的负责均衡管理。
    • Initialized: 所有的init container启动成功。
    • Unschedulable: pod无法被调度,比如说资源不足或其他原因。
    • ContainersReady: 所有的container启动成功。

Container probes

Probe是kubelet针对container周期性触发的诊断操作。Kubelet调用container的handler进行诊断操作。Handler有如下三种类型:

  • ExecAction: 在container执行特定命令。命令的退出状态码为0会被认为诊断无异常。
  • TCPSocketAction: 发送TCP请求。如果目标端口开放则诊断无异常。
  • HTTPGetAction: 发送HTTP GET请求。返回200到400之间(包括200)的状态码表示诊断无异常。

Probe有3种:

  • livenessProbe: 检查container是否在运行。如果liveness probe失败,kubelet会kill掉container。接下来container会根据restartPolicy确定是否重启。如果没配置livenessProbe,默认状态是Success。
  • readinessProbe: 检查pod是否已就绪对外提供服务。如果fail,endpoint会移除该pod的IP地址。在initial delay之前,此probe的默认值为Failure。如果没配置readinessProbe,默认状态为Success。
  • startupProbe: 检查pod是否已启动。如果配置了startupProbe,其他的probe会被禁用,直到startupProbe状态为Success才会启用其他的probe。如果startupProbe失败,kubelet会kill掉container。接下来container会根据restartPolicy确定是否重启。如果没有配置startupProbe,默认状态为Success。

livenessProbe的例子

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - args:
    - /server
    image: k8s.gcr.io/liveness
    livenessProbe:
      httpGet:
        # when "host" is not defined, "PodIP" will be used
        # host: my-host
        # when "scheme" is not defined, "HTTP" scheme will be used. Only "HTTP" and "HTTPS" are allowed
        # scheme: HTTPS
        path: /healthz
        port: 8080
        httpHeaders:
        - name: X-Custom-Header
          value: Awesome
      initialDelaySeconds: 15
      timeoutSeconds: 1
    name: liveness

Container States

可以使用

kubectl describe pod [POD_NAME]

来查看container state。

Container state有如下值:

  • Waiting: container state默认值。如果container既没有运行又没有终止,它处于waiting状态。
  • Running: container在运行,没遇到任何问题。
  • Terminated: container运行完毕,已经终止。运行完毕成功退出或者运行失败都是Terminated状态。

Restart Policy

具有三个值:

  • Always
  • OnFailure
  • Never

RestartPolicy位于PodSpec配置中,对pod内所有的container生效。

Container的重启延迟时间会指数级增长(最多为5分钟),启动成功10分钟之后,重启延迟时间重置。

Init Container

Init Container在应用程序container之前运行。

一个pod可以具有一个或多个init container。

Init container具有如下特点:

  • 总是会运行完毕退出。
  • 每个init container依次运行,一个运行成功再运行下一个。

如果init container运行失败,kubenetes会反复重启pod直到运行成功。如果RestartPolicy配置为Never,pod不会被重启。

Init Container和应用Container的不同之处

  1. 资源限制不同,详情参见https://kubernetes.io/docs/concepts/workloads/pods/init-containers/#resources
  2. 不支持ReadinessProbe

Init Container使用例子

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox:1.28
    command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
  - name: init-mydb
    image: busybox:1.28
    command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']

Init Container的行为

如果pod的RestartPolicy为Always,它所有init container的RestartPolicy为OnFailure。

如果pod重启,pod的init container必须要重新执行。

使用activeDeadlineSeconds或livenessProbe避免init container永无休止的fail。

Pod重启的原因

  • pod参数更新导致init container的image改变。
  • pod基础container重启。这种情况不常见。
  • pod的所有container都已停止,同时RestartPolicy设置为Always

Pod的操作

获取pod信息

kubectl get po pod_name -o yaml

创建pod

kubectl create -f kubia-manual.yaml

其中kubia-manual.yaml为pod描述文件。

获取所有pod

kubectl get pods

查看更详细的pod信息列表

kubectl get pods -o wide

获取pod的日志

kubectl logs pod_name

如果pod内存在多个container,可以使用如下命令获取某一个特定container内的日志

kubectl logs pod_name -c container_name

删除pod

kubectl delete po kubia-gpu

向pod发送请求

绑定宿主机和pod端口的方式:

  • 使用k8s service(推荐)
  • 使用port forwarding

Port forwarding方式

kubectl port-forward kubia-manual 8888:8080

Label(标签)

label是key/value pair。可以对k8s中的资源对象(pod,controller,service等)进行分类和标记,供其他资源对象的相关selector进行操作。

label相关操作

创建带有label的pod

yaml

apiVersion: v1
kind: Pod
metadata:
    name: kubia-manual-v2
    labels:
        creation_method: manual
        env: prod
spec:
    containers:
    - image: luksa/kubia
      name: kubia
      ports:
      - containerPort: 8080
        protocol: TCP

查看pod的label信息

kubectl get po --show-labels

将指定label分列显示

kubectl get po -L creation_method,env

新增标签

kubectl label po kubia-manual creation_method=manual

修改标签

kubectl label po kubia-manual-v2 env=debug --overwrite

使用label selector列出pod信息

精确匹配

kubectl get po -l creation_method=manual

列出包含env标签的pod

kubectl get po -l env

列出不包含env标签的pod

kubectl get po -l '!env'

使用label selector删除pod

kubectl delete po -l creation_method=manual

label selector的运算符

  • creation_method!=manual 否定
  • env in (prod,devel) 范围
  • env notin (prod,devel) 范围否定
  • app=pc,rel=beta 使用多个selector

节点标签配置

可以为集群中的节点增加标签,这样就可以使用pod spec中的nodeSelector人工干预pod的schedule过程,控制pod可运行到哪些节点上。

节点操作

节点增加标签

kubectl label node gke-kubia-85f6-node-0rrx gpu=true

使用label selector列出节点

kubectl get nodes -l gpu=true

创建node时使用node selector。(以下pod中的container仅会在label为gpu=true的节点下运行)

apiVersion: v1
kind: Pod
metadata:
    name: kubia-gpu
spec:
    nodeSelector:
        gpu: "true"
    containers:
      - image: luksa/kubia
      name: kubia

查看pod描述

kubectl describe pod kubia-manual

Annotation

Annotation通常来说不会被k8s直接使用,主要为了便于集群维护者查看。

有一个例外是对于一些alpha或者beta的API,它们会从annotation中读取一些配置。

Annotation相关操作

增加annotation

kubectl annotate pods kubia-manual mycompany.com/someannotation="foo bar"

删除kubia-manual这个pod上key为description的annotation

kubectl annotate pods kubia-manual description-

Namespace

Namespace用于对k8s中资源对象的分组。namespace之间没有嵌套或层级关系。一个资源对象只能属于一个namespace。不同组之间的对象是隔离的,互相不可见。

Namespace 适合用于隔离不同用户创建的资源。

注意:namespace无法保证网络的隔离性,比如说service可以跨namespace访问。

默认来说Kubernetes具有如下3个namespace:

  • default: k8s默认的namespace,如果操作如果不指明namespace,默认会操作名为default的namespace。
  • kube-system: k8s系统自己运行所需的资源对象所在的namespace。
  • kube-public: k8s自动创建的namespace,对所有用户可见。适合放置集群范围都可见的服务。

namespace相关操作

列出所有的namespace

kubectl get ns

获取指定namespace下的所有pod

kubectl get po --namespace kube-system
# 或
kubectl get po -n kube-system

创建namespace

custom-namespace.yaml

apiVersion: v1
kind: Namespace
metadata:
    name: custom-namespace
kubectl create -f custom-namespace.yaml

或者使用

kubectl create namespace custom-namespace

在指定namespace下创建资源

kubectl create -f kubia-manual.yaml -n custom-namespace

k8s快速切换namespace

alias kcd='kubectl config set-context $(kubectl config currentcontext) --namespace '

kcd some-namespace

执行如下命令验证

kubectl config view --minify | grep namespace:

删除整个namespace,这样namespace下的所有pod都会被删除

kubectl delete ns custom-namespace

删除整个namespace下的所有pod,但不删除namespace

kubectl delete po --all

删除namespace中所有的资源

kubectl delete all --all

推荐阅读更多精彩内容

  • 在实践之前,必须先学习k8s的几个重要概念,它们是组成k8s集群的基石。 1. Cluster Cluster是计...
    wangfs阅读 343评论 0 0
  • 1.Pod Pod是k8s的最基本的操作单元,包含一个或多个紧密相关的容器,类似于豌豆荚的概念。一个Pod可以被一...
    jony456123阅读 6,274评论 0 5
  • 排错指南 - Pod 本文档介绍 Pod 的异常状态,可能原因和解决办法。 排查 Pod 异常的常用命令如下: 查...
    小孩子的童话2014阅读 5,611评论 0 2
  • 为什么 K8S 的节点上的资源会被 pod 和系统进程所使用,如果默认什么都不配置,那么节点上的全部资源都是可以分...
    徐亚松_v阅读 6,516评论 1 5
  • 玉温娴柳含嫶柔,黛螺縠波泛徐舟。 渚石润染苔琉绿,清流随澹阔屏悠。 稚子啕啕酡颜绶,鹣鲽脉脉海棠绸。 丽日逐兴通古...
    青石过客阅读 56评论 0 0