pod和其他Kubernetes资源通常是通过向Kubernetes REST API提供JSON或YAML描述文件来创建的。此外还有其他更简单的创建资源的方法,比如在前一章中使用的 kubectl run
命令,但这些方法通常只允许你配置一组有限的属性。另外,通过YAML文件定义所有的Kubernetes对象之后,还可以将它们存储在版本控制系统中,充分利用版本控制所带来的便利性。
因此,为了配置每种类型资源的各种属性,我们需要了解并理解Kubernetes API对象定义。通过本书学习各种资源类型时,我们将会了解其中的大部分内容。需要注意的是,我们并不会解释每一个独立属性,因此在创建对象时还应参考 http://kubernetes.io/docs/reference/ 中的Kubernetes API参考文档。
3.2.1 检查现有pod的YAML描述文件
假设我们已经在上一章中创建了一些pod,接下来就来看看这些pod的YAML文件是如何定义的。我们将使用带有 -o yaml
选项的 kubectl get
命令来获取pod的整个YAML定义,正如下面的代码清单所示。
代码清单3.1 已部署pod的完整YAML
# kubectl get po kubia-767f9bc59d-6qvxz -o yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2021-07-05T00:52:28Z"
generateName: kubia-767f9bc59d-
labels:
app: kubia
pod-template-hash: 767f9bc59d
name: kubia-767f9bc59d-6qvxz
namespace: default
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: kubia-767f9bc59d
uid: 7739d7a5-aa22-4c3f-a27f-7413ce52d6f1
resourceVersion: "31264"
uid: e0c8c5ad-3973-4d16-875c-04784011ddf4
spec:
containers:
- image: luksa/kubia:1.0
imagePullPolicy: IfNotPresent
name: kubia
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-j66fw
readOnly: true
dnsPolicy: ClusterFirst
enableServiceLinks: true
nodeName: minikube
preemptionPolicy: PreemptLowerPriority
priority: 0
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- name: default-token-j66fw
secret:
defaultMode: 420
secretName: default-token-j66fw
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2021-07-05T00:52:28Z"
status: "True"
type: Initialized
- lastProbeTime: null
lastTransitionTime: "2021-07-05T01:00:18Z"
status: "True"
type: Ready
- lastProbeTime: null
lastTransitionTime: "2021-07-05T01:00:18Z"
status: "True"
type: ContainersReady
- lastProbeTime: null
lastTransitionTime: "2021-07-05T00:52:28Z"
status: "True"
type: PodScheduled
containerStatuses:
- containerID: docker://c257a532fd97feefb05425d56a1748d127ba99a736982760c0e8404fa807d304
image: luksa/kubia:1.0
imageID: docker-pullable://luksa/kubia@sha256:a961dc8f377916936fa963508726d77cf77dcead5c97de7e5361f0875ba3bef7
lastState: {}
name: kubia
ready: true
restartCount: 0
started: true
state:
running:
startedAt: "2021-07-05T01:00:16Z"
hostIP: 172.17.0.2
phase: Running
podIP: 172.18.0.5
podIPs:
- ip: 172.18.0.5
qosClass: BestEffort
startTime: "2021-07-05T00:52:28Z"
上述代码清单的内容看上去较为复杂,但一旦我们理解了基础知识并知道如何区分重要部分和细枝末节时,它就变得非常简单。此外,稍后我们将看到,当创建一个新的pod时,需要写的YAML相对来说则要短得多。
介绍pod定义的主要部分
pod定义由这么几个部分组成:首先是YAML中使用的Kubernetes API版本和YAML描述的资源类型;其次是几乎在所有Kubernetes资源中都可以找到的三大重要部分:
- metadata 包括名称、命名空间、标签和关于该容器的其他信息。
- spec包含pod内容的实际说明,例如pod的容器、卷和其他数据。
- status 包含运行中的pod的当前信息,例如pod所处的条件、每个容器的描述和状态,以及内部IP和其他基本信息。
代码清单3.1展示了一个正在运行的pod的完整描述,其中包含了它的状态。status部分包含只读的运行时数据,该数据展示了给定时刻的资源状态。而在创建新的pod时,永远不需要提供status部分。
上述三部分展示了Kubernetes API对象的典型结构。正如你将在整本书中看到的那样,其他对象也都具有相同的结构,这使得理解新对象相对来说更加容易。
对上述YAML中的每个属性进行深究的意义并不大,因此接下来我们将关注如何创建pod的最基本的YAML。
3.2.2 为pod创建一个简单的YAML描述文件
我们将创建一个名为kubia.yaml的文件(可以在任意目录下创建该文件),或者下载本书的代码档案文件,然后在Chapter03文件夹中找到该文件。下面的清单展示了该文件的全部内容。
代码清单3.2 一个基本的pod manifest:kubia.yaml
apiVersion: v1
kind: Pod
metadata:
name: kubia
spec:
containers:
- name: kubia
image: luksa/kubia:1.0
ports:
- containerPort: 8080
很明显,我们能够感受到该代码清单比代码清单3.1中的定义要简单得多。接下来我们就对整个描述文件进行深入探讨,该文件遵循Kubernetes API的v1版本。我们描述的资源类型是pod,名称为kubia-manual;该pod由基于 luksa/kubia
镜像的单个容器组成。此外我们还给该容器命名,并表示它正在监听8080端口。
指定容器端口 在pod定义中指定端口纯粹是展示性的(informational)。忽略它们对于客户端是否可以通过端口连接到pod不会带来任何影响。如果容器通过绑定到地址 0.0.0.0
的端口接收连接,那么即使端口未明确列出在pod spec中,其他pod也依旧能够连接到该端口。但明确定义端口仍是有意义的,在端口定义下,每个使用集群的人都可以快速查看每个pod对外暴露的端口。此外,我们将在本书的后续内容中看到,明确定义端口还允许你为每个端口指定一个名称,这样一来更加方便我们使用。
使用kubectl explain
来发现可能的API对象字段
在准备manifest时,可以转到http://kubernetes.io/docs/api上的Kubernetes参考文档查看每个API对象支持哪些属性,也可以使用kubectl explain
命令。
例如,当从头创建一个pod manifest时,可以从请求kubectl 来解释pod开始:
# kubectl explain pods
KIND: Pod
VERSION: v1
DESCRIPTION:
Pod is a collection of containers that can run on a host. This resource is
created by clients and scheduled onto hosts.
FIELDS:
apiVersion <string>
APIVersion defines the versioned schema of this representation of an
object. Servers should convert recognized schemas to the latest internal
value, and may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
kind <string>
Kind is a string value representing the REST resource this object
represents. Servers may infer this from the endpoint the client submits
requests to. Cannot be updated. In CamelCase. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
metadata <Object>
Standard object's metadata. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
spec <Object>
Specification of the desired behavior of the pod. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
status <Object>
Most recently observed status of the pod. This data may not be up to date.
Populated by the system. Read-only. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
Kubectl打印出对象的解释并列出对象可以包含的属性,接下来就可以深入了解各个属性的更多信息。例如,可以这样查看spec属性:
# kubectl explain pod.spec
KIND: Pod
VERSION: v1
RESOURCE: spec <Object>
DESCRIPTION:
Specification of the desired behavior of the pod. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
PodSpec is a description of a pod.
FIELDS:
activeDeadlineSeconds <integer>
Optional duration in seconds the pod may be active on the node relative to
StartTime before the system will actively try to mark it failed and kill
associated containers. Value must be a positive integer.
affinity <Object>
If specified, the pod's scheduling constraints
automountServiceAccountToken <boolean>
AutomountServiceAccountToken indicates whether a service account token
should be automatically mounted.
......
3.2.3 使用kubectl create来创建pod
我们使用kubectl create
命令从YAML文件创建pod:
$ kubectl create -f kubia.yaml
kubectl create -f
命令用于从YAML或JSON文件创建任何资源(不只是pod)。
得到运行中pod的完整定义
pod创建完成后,可以请求Kubernetes来获得完整的YAML,可以看到它与我们之前看到的YAML文件非常相似。在下一节中我们将了解返回定义中出现的其他字段,接下来就直接使用以下命令来查看该pod的完整描述文件:
$ kubectl get po kubia -o yaml
也可以让kubectl返回JSON格式而不是YAML格式(显然,即使你使用YAML创建pod,同样也可以获取JSON格式的描述文件):
$ kubectl get po kubia -o json
在pod列表中查看新创建的pod
创建好pod之后,如何知道它是否正在运行?此时可以列出pod来查看它们的状态:
# kubectl get pods
这里可以看到kubia-manual这个pod,状态显示它正在运行。有可能你像笔者一样想要通过与pod的实际通信来确认其正在运行,但该方法将在之后进行讨论。现在我们先查看应用的日志来检查是否存在错误。
3.2.4 查看应用程序日志
小型Node.js应用将日志记录到进程的标准输出。容器化的应用程序通常会将日志记录到标准输出和标准错误流,而不是将其写入文件,这就允许用户可以通过简单、标准的方式查看不同应用程序的日志。
容器运行时(在我们的例子中为Docker)将这些流重定向到文件,并允许我们运行以下命令来获取容器的日志:
$ docker logs <container id>
使用ssh命令登录到pod正在运行的节点,并使用docker logs命令查看其日志,但Kubernetes提供了一种更为简单的方法。
使用kubectl logs命令获取pod日志
为了查看pod的日志(更准确地说是容器的日志),只需要在本地机器上运行以下命令(不需要ssh到任何地方):
$ kubectl logs kubia
在我们向Node.js应用程序发送任何Web请求之前,日志只显示一条关于服务器启动的语句。正如我们所见,如果该pod只包含一个容器,那么查看这种在Kubernetes中运行的应用程序的日志则非常简单。
注意 每天或者每次日志文件达到10MB大小时,容器日志都会自动轮替。 kubectl logs
命令仅显示最后一次轮替后的日志条目。
获取多容器pod的日志时指定容器名称
如果我们的pod包含多个容器,在运行 kubectl logs
命令时则必须通过包含-c <容器名称>选项来显式指定容器名称。在kubia-manual pod中,我们将容器的名称设置为kubia,所以如果该pod中有其他容器,可以通过如下命令获取其日志:
$ kubectl logs kubia -c kubia
这里需要注意的是,我们只能获取仍然存在的pod的日志。当一个pod被删除时,它的日志也会被删除。如果希望在pod删除之后仍然可以获取其日志,我们需要设置中心化的、集群范围的日志系统,将所有日志存储到中心存储中。在第17章中我们将会解释如何设置集中的日志系统。
3.2.5 向pod发送请求
kubectl get
命令和我们的应用日志显示该pod正在运行,但我们如何在实际操作中看到该状态呢?在前一章中,我们使用kubectl expose
命令创建了一个service,以便在外部访问该pod。由于有一整章专门介绍service,因此本章并不打算使用该方法。此外,还有其他连接到pod以进行测试和调试的方法,其中之一便是通过端口转发。
将本地网络端口转发到pod中的端口
如果想要在不通过service的情况下与某个特定的pod进行通信(出于调试或其他原因),Kubernetes将允许我们配置端口转发到该pod。可以通过 kubectl port-forward
命令完成上述操作。例如以下命令会将机器的本地端口8888转发到我们的kubia pod的端口8080:
$ kubectl port-forward kubia 8888:8080
此时端口转发正在运行,可以通过本地端口连接到我们的pod。
通过端口转发连接到pod
在另一个终端中,通过运行在localhost:8888上的kubectl portforward代理,可以使用curl 命令向pod发送一个HTTP请求:
$ curl localhost:8888
实际上,kubectl进程和pod之间还有一些额外的组件,但现在暂时不关注它们。
像这样使用端口转发是一种测试特定pod的有效方法,而我们也将在这本书中学习其他类似的方法。
网友评论