Pod基础原理
yaml文件
在 Docker 环境下面我们是直接通过命令 docker run 来运行我们的应用的,在 Kubernetes 环境下面我们同样也可以用类似 kubectl run 这样的命令来运行我们的应用,但是在 Kubernetes 中却是不推荐使用命令行的方式,而是希望使用我们称为资源清单的东西来描述应用,资源清单可以用 YAML 或者 JSON 文件来编写,一般来说 YAML 文件更方便阅读和理解,所以我们的课程中都会使用 YAML 文件来进行描述。
通过一个资源清单文件来定义好一个应用后,我们就可以通过 kubectl 工具来直接运行它:
kubectl create -f xxxx.yaml
# 或者
kubectl apply -f xxxx.yaml
-
create: 在集群中 新建资源对象。只能创建 不存在的资源。不会更新已有资源,即它 不会改已有对象。
-
apply:以 声明式方式管理资源,可以 创建或更新。
Pod创建流程:
我们知道 kubectl 是直接操作 APIServer 的,所以就相当于把我们的清单提交给了 APIServer,然后集群获取到清单
描述的应用信息后存入到 etcd 数据库中,然后 kube-scheduler 组件发现这个时候有一个 Pod 还没有绑定到节点上,就会对这个 Pod 进行一系列的调度,把它调度到一个最合适的节点上,然后把这个节点和 Pod 绑定到一起(写回到etcd),然后节点上的 kubelet 组件这个时候 watch 到有一个 Pod 被分配过来了,就去把这个 Pod 的信息拉取下来,然后根据描述通过容器运行时把容器创建出来,最后当然同样把 Pod 状态再写回到 etcd 中去,这样就完成了一整个的创建流程。
第一个容器化应用(yaml编写)
编写yaml,文件名为:nginx-deployment.yaml
apiVersion: apps/v1 # 指定 API 版本,这里使用 apps/v1
kind: Deployment # 资源类型,这里是 Deployment(用于管理 Pod 副本)
metadata:name: nginx-deploy # Deployment 的名字labels:chapter: first-app # 自定义标签,可用于选择和管理资源
spec:replicas: 2 # Pod 副本数量,即期望运行 2 个 Podselector:matchLabels:app: nginx # Deployment 根据这个标签选择它管理的 Podtemplate: # Pod 模板,定义 Deployment 要创建的 Podmetadata:labels:app: nginx # Pod 的标签,必须与 selector.matchLabels 一致spec:containers:- name: nginx # 容器名字image: dockerpull.cn/library/nginx # 容器镜像,这里使用官方 nginx 镜像ports:- containerPort: 80 # 容器暴露的端口
启动:
ubuntu@ubuntu:~$ ls
kube-flannel.yml kubeadm.yaml nginx-deployment.yaml
ubuntu@ubuntu:~$ kubectl apply -f nginx-deployment.yaml
deployment.apps/nginx-deploy created
ubuntu@ubuntu:~$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deploy-7d998f9bcf-4kzbs 1/1 Running 0 54s
nginx-deploy-7d998f9bcf-cn2r6 1/1 Running 0 50s# 改成nodeprot模式
kubectl expose deployment nginx-deploy --port=80 --type=NodePort
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 19h
nginx-deploy NodePort 10.100.216.180 <none> 80:31596/TCP 47s
# 访问 (这里只暴露了一个端口,是因为service做了负载均衡)
http://192.168.236.101:31596/
# 删除
kubectl delete -f nginx-deployment.yaml
我们可以看到会在集群中生成两个 Pod 出来。而整个资源清单文件对应到 Kubernetes 中就是一个 API Object(API对象),我们按照这些对象的要求填充上对应的属性后,提交给 Kubernetes 集群,就可以为我们创建出对应的资源对象,比如我们这里定义的是一个 Deployment 类型的 API 对象,我们按照这个 API 对象的要求填充了一些属性,就会为我们创建出对应的资源对象,我们可以通过下面的命令来获取这些对象:
ubuntu@ubuntu:~$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 2/2 2 2 18s
Deployment 这个资源对象就是用来定义多副本应用的对象,而且还支持对每个副本进行滚动更新,上面我们的资源清单中的描述中有一个属性 replicas: 2,所以最后生成两个副本的 Pod。而这个 Deployment 定义的副本 Pod 具体是什么样的,是通过下面的 Pod 模板来定义的,就是 template 下面的定
义,这个模板中定义了我们的 Pod 中只有一个名为 nginx 的容器,容器使用的镜像是 nginx:1.7.9(spec.containers[0].image),并且这个容器监听的端口是 80
(spec.containers[0].ports[0].containerPort),另外我们还为 Pod 添加了一个 app: nginx 这样的Label 标签,这里需要非常注意的是上面的 selector.matchLabels 区域就是来表示我们的 Deployment 来管理哪些 Pod 的,所以这个地方需要和 Pod 模板中的 Label 标签保持一致,这个 Label 标签之前我们也提到过是非常重要的。
另外我们也可以发现每个 API 对象都有一个 Metadata 的字段,用来表示该对象的元数据的,比如定义 name、namespace 等,比如上面 Deployment 和 Pod 模板中都有这个字段,至于为什么 Pod 模板中没有 name 这个元信息呢,这是因为 Deployment 这个控制器会自动在他自己的 name 基础上生成 Pod 名,不过 Deployment 下面定义的Label 标签就没有 Pod 中定义的 Label 标签那么重要了,只是起到一个对该对象标识和过滤的作用。比如我们在查询对象的时候可以带上标签来进行过滤:
ubuntu@ubuntu:~$ kubectl get deployment -l chapter=first-app
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 2/2 2 2 2m39s
ubuntu@ubuntu:~$ kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
nginx-deploy-7d998f9bcf-gz6ps 1/1 Running 0 2m49s
nginx-deploy-7d998f9bcf-hrkw5 1/1 Running 0 2m49s
到这里我们就完成了我们的第一个应用的容器化部署,但是往往我们在部署应用的过程中或多或少会遇到一些问题,这个时候我们可以使用一个 kubectl describe 命令来查看资源对象的详细信息,比如我们用下面的命令来查看 Pod 的详细信息:
kubectl describe pod nginx-deploy-7d998f9bcf-gz6ps
我们可以看到看到很多这个 Pod 的详细信息,比如调度到的节点、状态、IP 等,一般我们比较关心的是下面的 Events部分,就是我们说的事件。
在 Kubernetes 创建资源对象的过程中,对该对象的一些重要操作,都会被记录在这个对象的 Events 里面,可以通过kubectl describe 指令查看对应的结果。所以这个指令也会是以后我们排错过程中会经常使用的命令,一定要记住这个重要的命令。比如上面我们描述的这个 Pod,我们可以看到它被创建之后,被调度器调度(Successfully assigned)到了 demo-worker 节点上,然后拉取对应的镜像,再然后创建我们定义的 nginx 容器,最后启动定义的容器。另外一个方面如果我们相对我们的应用进行升级的话应该怎么办呢?这个操作在我们日常工作中还是非常常见的,而在Kubernetes 这里也是非常简单的,我们只需要修改我们的资源清单文件即可,比如我们把镜像升级到最新版本(修改yaml的image就好)。
查询命令
ubuntu@ubuntu:~$ kubectl explain -h
Describe fields and structure of various resources.This command describes the fields associated with each supported API resource. Fields are identified via a simple
JSONPath identifier:<type>.<fieldName>[.<fieldName>]Information about each field is retrieved from the server in OpenAPI format.Use "kubectl api-resources" for a complete list of supported resources.Examples:# Get the documentation of the resource and its fieldskubectl explain pods# Get all the fields in the resourcekubectl explain pods --recursive# Get the explanation for deployment in supported api versionskubectl explain deployments --api-version=apps/v1# Get the documentation of a specific field of a resourcekubectl explain pods.spec.containers# Get the documentation of resources in different formatkubectl explain deployment --output=plaintext-openapiv2Options:--api-version='':Get different explanations for particular API version (API group/version)-o, --output='plaintext':Format in which to render the schema (plaintext, plaintext-openapiv2)--recursive=false:Print the fields of fields (Currently only 1 level deep)Usage:kubectl explain TYPE [--recursive=FALSE|TRUE] [--api-version=api-version-group]
[-o|--output=plaintext|plaintext-openapiv2] [options]Use "kubectl options" for a list of global command-line options (applies to all commands).
ubuntu@ubuntu:~$
具体字段
ubuntu@ubuntu:~$ kubectl explain deployment.spec
GROUP: apps
KIND: Deployment
VERSION: v1FIELD: spec <DeploymentSpec>DESCRIPTION:Specification of the desired behavior of the Deployment.DeploymentSpec is the specification of the desired behavior of theDeployment.FIELDS:minReadySeconds <integer>Minimum number of seconds for which a newly created pod should be readywithout any of its container crashing, for it to be considered available.Defaults to 0 (pod will be considered available as soon as it is ready)paused <boolean>Indicates that the deployment is paused.progressDeadlineSeconds <integer>The maximum time in seconds for a deployment to make progress before it isconsidered to be failed. The deployment controller will continue to processfailed deployments and a condition with a ProgressDeadlineExceeded reasonwill be surfaced in the deployment status. Note that progress will not beestimated during the time a deployment is paused. Defaults to 600s.replicas <integer>Number of desired pods. This is a pointer to distinguish between explicitzero and not specified. Defaults to 1.revisionHistoryLimit <integer>The number of old ReplicaSets to retain to allow rollback. This is a pointerto distinguish between explicit zero and not specified. Defaults to 10.selector <LabelSelector> -required-Label selector for pods. Existing ReplicaSets whose pods are selected bythis will be the ones affected by this deployment. It must match the podtemplate's labels.strategy <DeploymentStrategy>The deployment strategy to use to replace existing pods with new ones.template <PodTemplateSpec> -required-Template describes the pods that will be created. The only allowedtemplate.spec.restartPolicy value is "Always".
如果一个字段显示的是 -required- ,这就证明该自动是必填的,也就是我们在创建这个资源对象的时候必须声明这个字段,每个字段的类型也都完全为我们进行了说明,所以有了 kubectl explain 这个命令我们就完全可以写出一个不熟悉的资源对象的清单说明了,这个命令我们也是必须要记住的,会在以后的工作中为我们提供很大的帮助。
Pod概念
Pod 是 Kubernetes 中最小的部署单位(atomic unit of deployment)。
一个 Pod 可以包含 一个或多个容器(通常是 Docker 容器),它们共享以下资源:
- 网络命名空间:同一个 Pod 内的容器共享 IP 和端口。
- 存储卷(Volume):Pod 内容器可以共享卷,用于数据持久化或通信。
Pod 是 短生命周期对象,它只是容器的封装,不负责自我修复,通常由 Deployment、StatefulSet、DaemonSet 等控制器管理。
YAML 示例:两个容器共享网络和文件
apiVersion: v1
kind: Pod
metadata:name: shared-pod
spec:containers:- name: app-containerimage: nginxports:- containerPort: 80 # 网络共享volumeMounts:- name: shared-datamountPath: /usr/share/nginx/html # 挂载共享卷- name: sidecar-containerimage: busyboxcommand: ["sh", "-c", "while true; do echo 'Hello from sidecar' > /shared/index.html; sleep 5; done"]volumeMounts:- name: shared-datamountPath: /shared # 挂载同一个卷volumes:- name: shared-dataemptyDir: {} # Pod 生命周期内共享的临时目录