k8s☞03Pod

阅读量: zyh 2020-08-26 21:19:04
Categories: > Tags:

前言

pod 可以说是 k8s 的基础单元. 我觉得可以类比云环境的ecs/ec2这一类的基本计算单元.而 pod 上运行的容器, 可以类比为ecs/ec2上的app程序.

你总能在k8s的各类资源中找到云环境对应的资源影子. 如果你用过GCP,你会更有这种感觉.

https://kubernetes.io/docs/concepts/workloads/pods/

Pod与容器

一个pod可以拥有多个容器。

pod 内包含多个容器,所以多个容器共享以下资源。

另外,Pod可以包含一个init的特殊容器,它始终首先运行。

若pod只有一个容器,那么pod就是一个包装器

若pod有多个容器,则一般主容器提供服务;边车/挂斗/附属容器提供额外功能,例如刷新主容器的文件,收集日志。

ℹ️上述的功能的实现基于pod内的容器共享网络命名空间和存储空间.

example pod diagram

如果你玩过星际争霸,那么应该知道一个人族建筑物,总是会有一个附属建筑物,它很小,但提供了主建筑物所需的科技。

因此,除非你两个容器必须放在一起,否则你应该用多个单容器pod.

Pod与负载控制器

生产环境中,pod 一般不单独使用,因为单独使用意味着没有高可用,且难以管理。k8s建议 pod 要始终和负载控制器一起使用。负载控制器可以批量创建pod。

k8s将负载控制器主要分为三种:

还有CronJob、Jobs任务类型的.

负载控制器需要依托于镜像模板创建 pod 和依托于缩放规则控制 pod 数量。

镜像模板即 pod 模板(pod template).

负载控制器 - Pod模板

一个构建nginx的例子

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

如何寻找最合适的kind所属的apiVersion

在这里可能有人不知道如何选择apiVersion。你可以通过kubectl api-versions来找到kind所属的apiGroup,然后再通过

kubectl get --raw “/apis” 的输出找 preferredVersion。

➜   kubectl api-resources | grep deployment
deployments                       deploy       apps/v1                                true         Deployment
➜   kubectl get --raw "/apis"|jq '.groups[]|select(.name=="apps")'
{
  "name": "apps",
  "versions": [
    {
      "groupVersion": "apps/v1",
      "version": "v1"
    }
  ],
  "preferredVersion": {
    "groupVersion": "apps/v1",
    "version": "v1"
  }
}

如上命令所示,在我的k8s版本中kind: Deployment的最合适apiVersion是apps/v1

pod 存储

这是一个大问题. 如果你想真正的使用k8s的pod资源, 那么需要先看这一部分的内容.

简单来说, 存储资源主要分网络和本地两大类.

细致的说明, 参考官方文档https://kubernetes.io/docs/concepts/storage/

pod 网络

鉴于前面提到的pod类同于ecs/ec2. 因此. pod中的容器就如同ecs/ec2里的app一样,都有相同的ip, 端口范围, 主机名.

k8s的网络基于各种插件.每一种插件的实现详情见官网. https://kubernetes.io/docs/concepts/cluster-administration/networking/#how-to-implement-the-kubernetes-networking-model

如果你是本地搭建, 那么常用的插件是Flannel. 如果你是在云服务上搭建,那么建议使用云服务已有的k8s服务.

如果你必须在云服务上自己搭建,那么aws/azure/gcp都有对应的网络插件.它可以让你在k8s中结合使用云服务的网络组件.
当然你依然可以用 flannel 网络插件。

静态pod

特点:

  1. 永远运行在固定节点
  2. 由所在节点的kubelet管理,但只负责保活,即pod崩溃重生
  3. kubelet会让apiserver创建一个镜像pod,便于可以通过kubectl查询到静态pod

配置:

  1. 存放在 /etc/kubernetes/manifests 当采用kubeadm安装的时候,一般位于此目录。具体需要去看kubelet配置。
  2. 配置本身可以按照标准pod方式来创建

检测:

  1. kubelet会定期检测配置目录加载配置创建/重建pod

当你通过kubeadm创建的时候,那么k8s的几个重要组件均会以静态pod的方式在master节点上创建,你可以在/etc/kubernetes/manifests/这里找到他们的配置

➜   ll /etc/kubernetes/manifests/
total 16
-rw------- 1 root root 1848 Aug 25 16:28 etcd.yaml
-rw------- 1 root root 2709 Aug 25 16:28 kube-apiserver.yaml
-rw------- 1 root root 2564 Aug 25 16:33 kube-controller-manager.yaml
-rw------- 1 root root 1120 Aug 25 16:33 kube-scheduler.yaml

容器生命周期

Pod-生命周期

pod生命周期包含5个状态:

pod是通过uid来鉴别,而不是pod名,pod被替换时名称可以不变。

重启策略

https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#lifecycle

pod重启策略的间隔时间是10s,成指数上涨,但不超过5分钟。一旦重启成功且运行10分钟,则重置为10s。

状况

通过kubectl describe pod/<pod_name>查看Conditions字段条件

Conditions:
  Type              Status
  Initialized       True
  Ready             False
  ContainersReady   False
  PodScheduled      True

Ready为True,即表示【应该】被加入到svc的端点列表中。

但极端情况下有可能因为其它服务没准备好,导致及时Pod的Ready为True,svc也无法正常的转发流量到Pod。

这种行为,可能在滚动更新的时候,会导致丢数据。

针对上述问题,kubernetes允许在上面4个默认状态的基础上自定义就绪状态类型。

https://kubernetes.io/zh/docs/concepts/workloads/pods/pod-lifecycle/#pod-readiness-gate

终止

https://kubernetes.io/zh/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination

  1. Apiserver拿到删除请求、Apiserver更新pod状态,转为Terminating。默认Pod有30 秒优雅终止时间。

  2. kubelet推送preStop事件到容器中执行,如果设置了preStop的话

  3. kubelet通过container runtime发送TERM信号(kill-14)给每个容器中pid为1的进程号,并同时将pod从svc端点中剥离。

    1. 如果容器在30秒内没有停止成功,则kubelet会发送SIGKILL信号(kill -9)给容器,强行杀掉。
  4. 容器关闭状态转为Terminated,Apiserver将Pod删除。

  • 2和3是并行的,并且执行时间取决于Pod终止宽限期terminationGracePeriodSeconds
  • kubectl 添加--grace-period=0 --force可以立即删除Pod

ℹ️失败的pod状态会根据kube-controller-manager 参数 terminated-pod-gc-threshold阈值设置保存一定数量。默认这个值是12500,不清楚为何设置这么高。https://github.com/kubernetes/kubernetes/pull/79047这是一个被驳回的修正,它提议设置为500

容器Terminated

通过下方命令可以查找Terminated的原因。

kubectl get pod -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}'  <pod_name:simmemleak>
simmemleak
Container Name: simmemleak
LastState: map[terminated:map[exitCode:137 reason:OOM Killed startedAt:2015-07-07T20:58:43Z finishedAt:2015-07-07T20:58:43Z containerID:docker://0e4095bba1feccdfe7ef9fb6ebffe972b4b14285d5acdec6f0d3ae8a22fad8b2]]