K8s|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=

【K8s|K8s Pod和namespace】覆盖默认的宽限时间。
可以使用如下命令强制删除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

    推荐阅读