Pod是Kubernetes应用程序的最基本执行单元—是你创建或部署Kubernetes对象模型中的最小和最简单的单元。 Pod表示在集群上运行的进程。Pod封装了应用程序的容器(或者在某些情况下是多个容器)、存储资源、唯一的网络标识(IP地址)以及控制容器应该如何运行的选项。 Pod表示一个部署单元:Kubernetes中的应用程序的单个实例,该实例可能由单个容器或少量紧密耦合并共享资源的容器组成。Docker是Kubernetes Pod中最常见的容器,但Pods也支持其他容器。 Kubernetes集群中的Pod是如何管理容器的:
1)pod里运行单个容器: pod里只运行一个容器是最常见的Kubernetes使用案例。在这种情况下,你可以将Pod视为单个容器的封装,Kubernetes直接管理Pod,而不是直接管理容器。
2)pod里运行多个需要协同工作的容器:Pod可能封装了一个应用程序,该应用程序由紧密关联并且需要共享资源的多个共同协作的容器组成。这些共同协作的容器可能形成一个统一的服务单元-一个容器将文件从共享卷提供给所有容器使用,而一个单独的“ sidecar”容器则刷新或更新这些文件。Pod将这些容器和存储资源包装在一起,成为一个可管理的实体。
一个Pod就相当于一个共享context的配置组,在同一个context下,应用可能还会有独立的cgroup隔离机制,一个Pod是一个容器环境下的“逻辑主机”,它可能包含一个或者多个紧密相连的应用,这些应用可能是在同一个物理主机或虚拟机上。
Pod 的context可以理解成多个linux命名空间的联合:
Pod和相互独立的容器一样,Pod是一种相对短暂的存在,而不是持久存在的,正如我们在Pod的生命周期中提到的,Pod被安排到节点上,并且保持在这个节点上直到被终止(根据重启的设定)或者被删除,当一个节点死掉之后,节点上运行的所有Pod均会被删除。
Kubernetes v1.8+ 还支持容器间共享 PID namespace,需要 docker >= 1.13.1,并配置 kubelet --docker-disable-shared-pid=false。
1) 透明:Pod中的容器对基础设施可见,使得基础设施可以给容器提供服务,例如线程管理和资源监控,这为用户提供很多便利;
2) 解耦:解除软件依赖关系,独立的容器可以独立的进行重建和重新发布,Kubernetes 甚至会在将来支持独立容器的实时更新;
3) 易用:用户不需要运行自己的线程管理器,也不需要关心程序的信号以及异常结束码等;
4) 高效:因为基础设施承载了更多的责任,所以容器可以更加高效;
Pod中可以同时运行多个容器。同一个Pod中的容器会自动的分配到同一个 node 上。同一个Pod中的容器共享资源、网络环境,它们总是被同时调度,在一个Pod中同时运行多个容器是一种比较高级的用法,只有当你的容器需要紧密配合协作的时候才考虑用这种模式。例如,你有一个容器作为web服务器运行,需要用到共享的volume,有另一个“sidecar”容器来从远端获取资源更新这些文件,如下图所示:
一些Pods有init容器和应用容器。 在应用程序容器启动之前,运行初始化容器。Pods为它组成的容器提供两种共享资源:网络和存储。
网络:
每个pod都被分配唯一的IP地址,POD中的每个容器共享网络名称空间,包括IP地址和网络端口。 Pod内部的容器可以使用localhost相互通信。 当POD中的容器与POD之外的实体通信时,它们必须使用共享网络资源(如端口)。
存储:
Pod可以指定一组共享存储卷。 POD中的所有容器都可以访问共享卷,允许这些容器共享数据。 卷也允许Pod中的持久数据在需要重新启动的情况下存活。 有关Kubernetes如何在POD中实现共享存储的更多信息,可参考Volumes | Kubernetes
我们很少在Kubernetes中直接创建单个Pod。这是因为Pods被设计成相对短暂的、一次性的实体。 当一个POD被创建(直接创建,或间接由控制器创建)时,它被安排在集群中的节点上运行。 在进程终止、pod对象被删除、pod由于缺乏资源而被驱逐或节点失败之前,POD仍然位于该节点上。
注意:不要将重新启动Pod中的容器与重新启动Pod混淆。POD不是一个进程,而是一个运行容器的环境。Pod一直存在直到被删除为止。
pod本身无法自我修复。如果将Pod调度到发生故障的节点,或者调度操作本身失败,则将Pod删除;同样,由于缺乏资源或Node维护,Pod也被删除。Kubernetes使用称为控制器的更高级别的抽象来统一处理相对一次性的Pod实例的生命周期相关工作。因此,虽然可以直接使用Pod,但在Kubernetes中使用控制器来管理Pod更为常见。
你可以使控制器创建和管理多个pod。控制器在pod失败的情况下可以处理副本、更新以及自动修复。例如,如果某个节点发生故障,则控制器会注意到该节点上的Pod已停止工作,并创建了一个替换Pod。调度程序将替换的Pod放置到健康的节点上。可以使用deployment、statefulset、daemonset等控制器管理pod。
Pod 可以用于托管垂直集成的应用程序栈(例如,LAMP),但最主要的目的是支持位于同一位置的、共同管理的程序,例如:
通常,不会用单个 Pod 来运行同一应用程序的多个实例。
一般来说,用户不需要直接创建 Pod。他们几乎都是使用控制器进行创建,即使对于单例的 Pod 创建也一样使用控制器,例如Deployments控制器提供集群范围的自修复以及副本数和滚动管理。 像StatefulSet这样的控制器还可以提供支持有状态的Pod。
目前,Kubernetes 仅支持使用 Docker 镜像来创建容器,但并非支持 Dockerfile 定义的所有行为。如下表所示:
Dockerfile 指令 | 描述 | 支持 | 说明 |
---|---|---|---|
ENTRYPOINT | 启动命令 | 是 | containerSpec.command |
CMD | 命令的参数列表 | 是 | containerSpec.args |
ENV | 环境变量 | 是 | containerSpec.env |
EXPOSE | 对外开放的端口 | 否 | 使用 containerSpec.ports.containerPort 替代 |
VOLUME | 数据卷 | 是 | 使用 volumes 和 volumeMounts |
USER | 进程运行用户以及用户组 | 是 | securityContext.runAsUser/supplementalGroups |
WORKDIR | 工作目录 | 是 | containerSpec.workingDir |
STOPSIGNAL | 停止容器时给进程发送的信号 | 是 | SIGKILL |
HEALTHCHECK | 健康检查 | 否 | 使用 livenessProbe 和 readinessProbe 替代 |
SHELL | 运行启动命令的 SHELL | 否 | 使用镜像默认 SHELL 启动命令 |
维护整个Pod网络和存储空间。
启动一个容器时,k8s会自动启动一个基础容器
cat /opt/kubernetes/cfg/kubelet
......
--pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0"
每次创建Pod 时候就会创建,运行的每一个 容器都有一个pause-amd64 的基础容器自动会运行,对于用户是透明的:
docker ps -a
registry .cn-hangzhou .aliyuncs. com/ google-containers/pause- amd64:3.0 "/pause "
Pod 能够具有多个容器,应用运行在容器里面,但是它也可能有一个或多个先于应用容器启动的 Init 容器。Init 容器在所有容器运行之前执行(run-to-completion),常用来初始化配置。
如果为一个 Pod 指定了多个 Init 容器,那些容器会按顺序一次运行一个。 每个 Init 容器必须运行成功,下一个才能够运行。 当所有的 Init 容器运行完成时,Kubernetes 初始化 Pod 并像平常一样并行运行应用容器,所以Init容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法。
Init容器与普通的容器非常像,除了以下两点:
Init 容器的资源计算,选择一下两者的较大值:
Init 容器的重启策略:
因为init容器具有与应用容器分离的单独镜像,其启动相关代码具有如下优势:
下面是一个 Init 容器的示例:
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: workdir
mountPath: /usr/share/nginx/html
# These containers are run during pod initialization
initContainers:
- name: install
image: busybox
command:
- wget
- "-O"
- "/work-dir/index.html"
- http://kubernetes.io
volumeMounts:
- name: workdir
mountPath: "/work-dir"
dnsPolicy: Default
volumes:
- name: workdir
emptyDir: {}
并行启动
busybox轻量级linux内核
官网示例:
https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
cd /optdemo/
vim demo.yaml
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;']
这个例子是定义了一个具有 2 个 Init 容器的简单 Pod。 第一个等待 myservice 启动, 第二个等待 mydb 启动。 一旦这两个 Init容器都启动完成,Pod 将启动 spec 中的应用容器。
kubectl describe pod myapp-pod
kubectl logs myapp-pod -c init-myservice
vim myservice.yaml
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
kubectl create -f myservice.yaml
kubectl get svc
kubectl get pods -n kube-system
kubectl get pods
---------------------------------------------------------------------------------------
vim mydb.yaml
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
kubectl create -f mydb.yaml
kubectl get pods
特别说明:.
我们一般将pod对象从创建至终的这段时间范围称为pod的生命周期,它主要包含下面的过程:
pod的终止过程:
Kubernetes 以 PodStatus.Phase 抽象 Pod 的状态(但并不直接反映所有容器的状态)。可能的 Phase 包括:
可以用 kubectl 命令查询 Pod Phase:
$ kubectl get pod reviews-v1-5bdc544bbd-5qgxj -o jsonpath="{.status.phase}" Running
PodSpec 中的 restartPolicy 可以用来设置是否对退出的 Pod 重启,可选项包括 Always、OnFailure、以及 Never。比如:
容器生命周期钩子:对于pod资源来说,容器生命周期钩子是在pods.spec.containers.lifecycle下定义的,监听容器生命周期的特定事件,并在事件发生时执行已注册的回调函数。初始化容器启动之后,开始启动主容器,在主容器启动之前有一个post start hook(容器启动后钩子)和pre stop hook(容器结束前钩子)。
postStart:该钩子在容器被创建后立刻触发,通知容器它已经被创建。如果该钩子对应的hook handler执行失败,则该容器会被杀死,并根据该容器的重启策略决定是否要重启该容器,这个钩子不需要传递任何参数。注意由于是异步执行,它无法保证一定在 ENTRYPOINT 之前运行。如果失败,容器会被杀死,并根据 RestartPolicy 决定是否重启。
preStop:该钩子在容器被删除前触发,其所对应的hook handler必须在删除该容器的请求发送给Docker daemon之前完成。在该钩子对应的hook handler完成后不论执行的结果如何,Docker daemon会发送一个SGTERN信号量给Docker daemon来删除该容器,这个钩子不需要传递任何参数。
而钩子的回调函数支持两种方式:
查看postStart怎么定义的,可以用如下命令:
kubectl explain pods.spec.containers.lifecycle.postStart
查看preStop怎么定义的,可以用如下命令:
kubectl explain pods.spec.containers.lifecycle.preStop
postStart 和 preStop 钩子示例:
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx
lifecycle:
postStart:
httpGet:
path: /
port: 80
preStop:
exec:
command: ["/usr/sbin/nginx","-s","quit"]
Kubernetes中pod详解_人间不值得-的博客-CSDN博客