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是终止过程。
- 用户发出删除pod指令,默认pod删除宽限时间为30秒。
- API server中该pod的状态被更新。Pod在宽限时间之后会被认为dead。
- Pod进入Terminating状态。
- 和步骤3同时进行。当kubelet发现API server中Pod被标记为terminating,开始终止pod的过程。如果pod定义了preStop hook,调用preStop hook的逻辑。如果preStop过程在宽限时间到之后仍在运行,稍后步骤运行,并多出2秒宽限时间。接下来发送TERM信号到container。
- 和步骤3同时进行。pod从endpoint中移除。service不会再转发流量到这个pod。并且controller不再认为这个pod处于运行状态。
- 当宽限时间到达之时,发送SIGKILL指令到pod中所有进程。
- 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的不同之处
- 资源限制不同,详情参见https://kubernetes.io/docs/concepts/workloads/pods/init-containers/#resources
- 不支持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