3.2 部署应用程序
让我们开始部署一个应用程序并使其在互联网上可用。稍后,我们将用新版本更新它。换句话说,我们将使用 Kubernetes 执行基本的应用程序开发-发布-更新周期。为此,我们将使用前一部分讨论的 Kubernetes 对象:一个 Pod,它将由 Deployment 管理,并通过 Service 暴露。
3.2.1 创建集群
在部署应用程序之前,您需要一个可用的 Kubernetes 集群。我建议在公共云上创建一个,因为设置起来更简单,并且人们可以立即查看您的创作,因为您可以共享任何您部署的服务的公共 IP。许多云服务提供商都有免费试用,以帮助降低学习成本。
在本地 Kubernetes 集群上进行开发是另一个选择,但本地 Kubernetes 集群和基于云的集群之间存在一些固有差异,特别是在负载均衡等方面。我更倾向于学习可以在第一天就用于生产的环境,因此我建议选择一个云服务提供商并从中开始。
更喜欢本地集群吗?
如果您更愿意使用本地的 Kubernetes 发行版,我可以为您提供帮助。请按照第 3.4 节中的步骤将您的 kubectl 命令连接到本地集群,然后返回第 3.2.3 节关于部署到 Kubernetes 的内容并继续。
请注意,当您部署自己本地构建的容器镜像时,有一些考虑事项在第 3.4 节中进行了概述,以确保 Kubernetes 能够找到您的镜像,并且由于缺少公共负载均衡器,您访问任何创建的服务的方式将会有所不同(该节中也有概述)。
在一天结束时,您所需的只是一个托管在某处的 Kubernetes 集群和经过身份验证以使用该集群的 Kubernetes 命令行工具 kubectl (发音:“cube cuttle”),这应该可以通过任何入门指南获得。接下来的两个步骤使用 Google Cloud,但我也会在此过程中提供一些关于如何替换为您选择的平台的说明。
谷歌 Kubernetes 引擎
谷歌 Kubernetes 引擎 (GKE) 是首个上市的 Kubernetes 产品,由于其成熟性和易用性,成为尝试 Kubernetes 的热门选择。我在 GKE 团队工作,对这个平台最为熟悉,因此在本书中涉及平台特定要求的几个地方,我将使用它。
我写这本书是为了适用于任何使用 Kubernetes 的地方,我希望它能帮助学习 Kubernetes,无论你使用的是 GKE、OpenShift、Azure Kubernetes Service (AKS)、Elastic Kubernetes Service (EKS)还是其他任何 Kubernetes 平台和发行版。在一些平台发挥作用的地方(比如现在创建集群时),我会用 GKE 的指令演示操作,但我也会提供如何在其他平台上找到等效操作的提示。
在任何云上创建 Kubernetes 集群
要在本章的设置部分之后运行示例,您所需的仅是经过身份验证的 kubectl 工具,连接到您选择的 Kubernetes 集群。创建和验证 kubectl 是目标,正如您将看到的,对于 GKE,这可以通过两个命令完成。您可以将这些命令替换为您选择的平台的等效集群创建和身份验证命令。
要在任何提供商上运行以下示例,请按照您选择的提供商的集群创建指南进行操作,然后继续到第 3.2.2 节。上传容器也是一个特定于提供商的操作,但我为您提供了一些通用提示,以帮助您在任何平台上完成此操作。
要开始使用 GKE,您需要一个 Google 帐户(如果您有 @gmail.com 的电子邮件地址,那么您就有一个 Google 帐户)。前往 https://console.cloud.google.com/,选择您的帐户并查看条款。如果您尚未激活免费试用,请激活它,或者添加账单信息以便您可以运行这些示例(如果您希望在本地运行示例,您可以按照第 3.4 节中的步骤获取仅限本地的集群)。
设置好您的帐户后,前往控制台中的 GKE(直接链接:https://console.cloud.google.com/kubernetes)并创建一个集群。我推荐使用自动驾驶模式,它会为您处理节点的配置和管理。在自动驾驶模式下,您可以设置名称,选择区域(如图 3.8 所示),并将网络和高级设置保留为默认值。
接下来,设置命令行工具。您需要云服务提供商的 CLI(在本例中为 gcloud ,用于 Google Cloud)来执行集群操作,如创建和认证,以及 kubectl 用于与 Kubernetes API 交互。请在 https://cloud.google.com/sdk/install 下载 gcloud CLI,并按照安装说明进行操作。
安装后,运行 gcloud init 命令以登录。如果您有多个 Google 帐户,请确保选择您之前创建集群时使用的相同帐户:
gcloud init
Kubernetes CLI, kubectl ,可以单独安装(按照 https://kubernetes.io/docs/tasks/tools/ 上的说明)或通过 gcloud 安装。安装方式无所谓,但由于这个例子使用了 gcloud ,我们可以方便地使用它来安装 kubectl ,如下所示:
gcloud components install kubectl
一旦集群准备就绪并且 gcloud 已配置,点击 UI 中的连接并将提供的 gcloud 命令(如图 3.9 所示)复制到您的终端以验证 kubectl 。或者,使用您自己的集群详细信息运行以下命令:
CLUSTER_NAME=my-cluster
REGION=us-west1
gcloud container clusters get-credentials $CLUSTER_NAME --region $REGION
该命令是 Google Cloud 世界与 Kubernetes 世界之间的粘合剂,并使用正确的凭据对 kubectl CLI 进行身份验证,以访问您的 GKE 集群。
在命令行界面中创建集群
与其使用用户界面,您可以通过命令行执行创建和连接步骤,如下所示:
CLUSTER_NAME=my-cluster
REGION=us-west1
gcloud container clusters create-auto $CLUSTER_NAME --region $REGION
gcloud container clusters get-credentials $CLUSTER_NAME --region $REGION
创建好集群并且 kubectl 已认证后,您可以开始您的第一个应用程序了!为了确保一切正常,请运行 kubectl get pods 。它应该显示没有资源(因为我们还没有部署任何 Pod):
$ kubectl get pods
No resources found in default namespace.
如果您遇到错误,可能是您的集群未正确创建或验证。请尝试重复之前的步骤或查找错误消息。
3.2.2 上传您的容器
直到现在,我们创建的容器一直存储并在您的机器上本地运行。在将容器部署到云中运行的 Kubernetes 之前,您需要将容器镜像上传到容器注册表。这只是一个存储容器镜像数据的地方,并为 Kubernetes 提供获取镜像的方式。大多数注册表支持公共镜像的选项,任何人都可以使用(例如开源项目和书籍示例),或私有镜像,这需要身份验证(您将用于自己的专有应用程序)。
如果您愿意,可以跳过此步骤,使用以下示例中提到的公开可用图像。不过,我建议您构建并上传自己的容器,以便在需要时可以部署自己的应用程序。
Docker Hub 是一个流行的容器注册中心,特别是在公共容器镜像方面。这包括基础镜像(如我们在上一章中使用的那些)、开源软件如 MariaDB,或者您希望与世界分享的自己的软件和演示。您还可以从任何 Kubernetes 平台访问 Docker Hub(和其他注册中心)的私有容器镜像,只需进行一些额外的配置以设置凭据。
大多数希望保持图像私密的用户的默认选择是使用云服务提供商的容器注册表,因为这通常在图像拉取时间、降低网络数据成本和简化身份验证方面提供了效率。对于 Google Cloud,这是 Artifact Registry;对于亚马逊网络服务(AWS),这是 Amazon Elastic Container Registry;对于 Azure,这是 Azure Container Registry;等等。
一旦您选择了首选位置,请按照以下步骤上传您的容器。
账户设置
要开始,首先在您首选的服务提供商处创建一个帐户(如果您还没有帐户),然后创建一个您将上传图像的存储库。对于 Docker Hub,请访问 https://hub.docker.com/,登录,然后导航到创建存储库。
对于 Artifact Registry,请访问 https://console.cloud.google.com/artifacts 并在您希望的位置创建一个新的 Docker 类型的存储库。请记下生成的路径,格式类似于 us-docker.pkg.dev/my-project/my -repository 。
认证
接下来,您需要对 docker 命令行工具进行身份验证,以便它可以将图像上传到您新创建的存储库。请按照您的容器注册表的说明对 docker 命令行工具进行身份验证。
要在 Docker Hub 中执行此操作,您需要运行
docker login
对于 Artifact Registry,请回忆您之前创建的存储库的路径。取该路径的主机部分(例如, us-docker.pkg.dev ),并运行以下命令以将凭证助手安装到 Docker 工具中,以便您可以在此处上传镜像。您可以多次运行此命令,每个单独的主机运行一次:
HOST_NAME=us-docker.pkg.dev
gcloud auth configure-docker $HOST_NAME
提示 使用您选择的云服务提供商对 Docker 进行身份验证通常是一个简单的操作。只需查找特定于云的命令,以使用正确的凭据配置 Docker CLI。搜索查询“使用 [您的云服务提供商] 容器注册表进行 Docker 身份验证”应该可以解决问题!
标签
当您构建镜像时,它们会被分配一个基于随机哈希的名称,例如 82ca16cefe84 。通常,添加一个有意义的标签是个好主意,这样您可以轻松地引用自己的镜像。在上一章中,我们使用了这些标签,以便我们可以使用像 docker run timeserver 这样的好名称在本地运行我们的镜像,而不是 docker run 82ca16cefe84 。
当您将容器上传到容器注册表时,标签具有额外的含义。您需要使用遵循容器注册表规定的特定路径约定的名称来标记图像,以便它知道将图像存储在哪个帐户和路径中(并且您的本地 Docker 客户端知道将其上传到哪个注册表)。使用像 timeserver 这样的简单名称标记您的图像在上传到这些存储库时是行不通的。
Docker Hub 使用约定
docker.io/$USERNAME/$REPOSITORY_NAME:$VERSION_TAG
其中 $USERNAME 是您的 Docker 用户名, $REPOSITORY_NAME 是您在 Docker Hub 中创建的仓库名称, $VERSION_TAG 是一个任意字符串(通常包含一个数字)。结合起来,在我自己的情况下,我的用户名是“wdenniss”,我的仓库是“timeserver”,我得到的字符串是 docker.io/wdenniss/timeserver:1 。
版本标签
版本标签是一个非结构化字符串,用于引用镜像的版本。约定是使用版本号(可能构造为主.次.补丁)并可选地带有后缀:例如, 2 . 2.1 , 2.1.5 , 2.1.5-beta 。特殊版本标签 latest 可用于在运行容器时引用最新镜像,但在标记上传镜像时不要使用 latest ,因为它是由容器仓库自动应用的。
每个仓库都有其自己的格式。对于 Google Cloud 的 Artifact Registry,该格式由以下结构组成:
$LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY_NAME/
$VERSION_TAG
在您在 UI 控制台中创建 Artifact Registry 存储库后,您应该会看到此字符串的第一部分显示(例如, us-docker.pkg.dev/wdenniss/ts ),您可以复制它(或者您可以使用之前的公式构建字符串)。在这个前缀后,附加您喜欢的任何镜像名称和标签,例如 timeserver:1 。将它们组合在一起,您将得到一些东西,对我来说,看起来像以下内容:
us-docker.pkg.dev/wdenniss/ts/timeserver:1
容器注册表标签约定
每个私有容器注册表都有其独特的字符串连接方式,你需要使用它来创建正确的标签,而且它们各不相同。例如,Azure 文档 $REGISTRY_NAME.azurecr.io/$REPOSITORY_NAME:$VERSION_TAG 和 AWS 文档 $AWS_ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$REPOSITORY_NAME: $VERSION_TAG 。我可以确定的一件事是:确保遵循你所使用的任何容器注册表的指南;否则,Kubernetes 将不知道将镜像推送到哪里。我使用的搜索词是“[云服务提供商] 注册表容器标签名称。”
一旦您确定了要使用的正确镜像标签(在后续示例中我们将其称为 $IMAGE_TAG ),您可以标记任何现有的 Docker 镜像以进行上传。要将我们在前一章中构建的其中一个镜像上传到容器注册表,您可以引用其先前的标签并添加一个容器注册表标签(镜像可以有多个标签)。如果您使用 docker build . -t timeserver 构建了第 2.2.1 节中的示例,则该镜像将具有标签 timeserver ,这意味着我们可以将其重新标记为容器注册表,如下所示:
IMAGE_TAG=us-docker.pkg.dev/wdenniss/ts/timeserver:1
docker tag timeserver $IMAGE_TAG
注意 如果您收到错误“没有这样的图像”,请继续阅读,因为我们将再次从头开始构建它。
您可以查看生成的图像列表,如下所示:
$ docker images
REPOSITORY TAG IMAGE ID CREATED
timeserver latest c07e34564aa0 2 minutes ago
us-docker.pkg.dev/wdenniss/ts/timeserver 1 c07e34564aa0 2 minutes ago
python 3.10 cf0643aafe49 1 days ago
您还可以根据图像 ID ( docker tag $IMAGE_ID $IMAGE_TAG ) 查找现有图像并对其进行标记,但我建议在构建时进行标记以避免混淆。实际上,我通常发现重新构建图像比事后尝试找到正确的图像 ID 更快。
要构建和标记示例容器,请将 $IMAGE_TAG 替换为您自己的仓库镜像名称,然后从根示例目录运行
IMAGE_TAG=us-docker.pkg.dev/wdenniss/ts/timeserver:1
cd Chapter02/timeserver
docker build . -t $IMAGE_TAG
推送
一旦我们的仓库设置完成,Docker 已经通过身份验证,并且您的镜像已被标记,您可以使用以下命令将镜像推送到仓库:
docker push $IMAGE_TAG
上一步的身份验证在 Docker 配置中安装了一个助手,使 Docker 能够与您的云容器注册表进行通信,无论它是什么。如果您收到权限被拒绝的错误,可能是您没有正确地对 Docker 进行身份验证,或者您的镜像标签字符串构造错误。请验证您是否已将 Docker 身份验证到适当的存储库,并设置正确的镜像标签。请参考您选择的容器注册表的最新文档以获取指导。
如果一切顺利,您应该会看到如下输出。请特别注意最后一行,因为任何身份验证错误将在此处显示:
$ docker push $IMAGE_TAG
The push refers to repository [us-docker.pkg.dev/wdenniss/ts/timeserver]
9ab1337ca015: Pushed
3eaafa0b4285: Layer already exists
a6a5635d5171: Layer already exists
8c25977a7f15: Layer already exists
1cad4dc57058: Layer already exists
4ff8844d474a: Layer already exists
b77487480ddb: Layer already exists
cd247c0fb37b: Layer already exists
cfdd5c3bd77e: Layer already exists
870a241bfebd: Layer already exists
1: digest: sha256:edb99776ae47b...97f7a9f1864afe7 size: 2425
一旦图像上传完成,您现在可以将代码部署到 Kubernetes 中!
3.2.3 部署到 Kubernetes
创建集群并认证 kubectl 后,我们可以部署我们的第一个应用程序。为此,我们将创建一个恰如其分的部署对象。Kubernetes 使用声明式配置,您在配置文件中声明所需的状态(例如“我希望在集群中运行 3 个容器副本”)。然后,将该配置提交给集群,Kubernetes 将努力满足您指定的要求。
对于配置文件,大多数开发者使用 YAML,因为它更容易手动编辑。JSON 是另一种选择(主要用于自动访问),一些配置可以以命令式方式创建(在 3.3 节中讨论)。列表 3.1 是第 2 章中 timeserver 应用程序的最小部署规范。它引用了一个公共容器镜像,该镜像是从包含的示例应用程序构建的,我已将其上传到 Docker Hub。如果您有自己的镜像,例如在上一节中推送到容器库的镜像,请编辑此文件并用您的镜像替换我的镜像。
清单 3.1 Chapter03/3.2_部署到 Kubernetes/deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: timeserver
spec:
replicas: 3 ?
selector:
matchLabels:
pod: timeserver-pod
template:
metadata:
labels:
pod: timeserver-pod
spec:
containers:
- name: timeserver-container
image: docker.io/wdenniss/timeserver:1 ?
? 部署多少个 Pod 副本(实例)
? 选择哪个容器镜像进行部署和运行
此清单将创建我们容器的三个副本。稍后,我们将看到如何配置负载均衡器以将传入请求分配到这三个运行实例上。在这个极简主义的部署配置示例中,三行最重要的内容是名称,这对于检查、修改和删除部署是必需的;副本数量;以及容器名称。其余部分基本上是为了使其正常工作而存在的粘合剂(别担心,我会解释粘合剂是如何工作的)。
容器镜像路径类似于一个 URL,用于引用容器的位置。如果您按照前面的部分上传了容器,您已经在该步骤中获得了这个镜像路径。我的容器镜像带有 docker.io 前缀,托管在 Docker Hub 上,这是一个流行的公共镜像托管平台,包括基础镜像。需要注意的是,如果您看到没有域名的镜像路径,例如 ubuntu 或 wdenniss/timeserver ,这只是 Docker Hub 上托管的镜像的简写。
好的,这就是部署。让我们在集群中创建它。从根样本目录中运行
cd Chapter03/3.2_DeployingToKubernetes/
kubectl create -f deploy.yaml
这指示 Kubernetes 创建由配置文件定义的对象。如果您需要在部署后进行更改(例如更改镜像版本),您可以在本地进行更改,并使用以下命令更新集群中的 Deployment。
kubectl apply -f deploy.yaml
要观察部署状态,请运行
$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
timeserver 3/3 3 3 36s
如前所述,Deployment 是您所需要求的声明性语句,例如,“3 个此 Pod 的副本。”当您创建 Deployment 并且系统返回成功响应时,这仅意味着 Kubernetes 接受了您的 Deployment 进行调度——并不意味着它已按照您所期望的方式完成调度。使用 kubectl get 查询 Deployment 将显示当前状态,例如有多少 Pods 准备好提供流量( READY 列中的数字),以及稍后当您更新 Deployment 时,在新版本的滚动更新过程中有多少 Pods 正在运行最新版本( UP-TO-DATE 列中的数字)。要查看有关构成您 Deployment 的 Pods 的更多详细信息,您还可以查询 Pods 本身:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
timeserver-6df7df9cbb-7g4tx 1/1 Running 0 68s
timeserver-6df7df9cbb-kjg4d 1/1 Running 0 68s
timeserver-6df7df9cbb-lfq6w 1/1 Running 0 68s
注意 如果这里的 Pods 显示为待定,这可能意味着您的集群没有足够的资源。在动态配置的环境中,通常等待一分钟左右就足以看到它们被调度。如果它们仍然处于待定状态,请查看后面“故障排除:卡在待定状态”部分的建议。
kubectl get pods 命令返回活动命名空间中所有 Pod 的状态,因此一旦您有很多 Deployments,这可能会变得有些混乱。相反,您可以使用更详细的形式,在其中将 Pod 的标签(在 3.2.4 节中讨论)作为选择器传递。以下是使用我们示例 Deployment 的标签的完整示例:
$ kubectl get pods --selector=pod=timeserver-pod
NAME READY STATUS RESTARTS AGE
timeserver-6df7df9cbb-7g4tx 1/1 Running 0 2m13s
timeserver-6df7df9cbb-kjg4d 1/1 Running 0 2m13s
timeserver-6df7df9cbb-lfq6w 1/1 Running 0 2m13s
一旦 Pod 运行起来,我们就可以与之互动!要连接到我们新创建的 Deployment,并访问我们在创建公共 IP 之前部署的服务器,我们可以简单地将本地机器的一个端口转发到容器,如下所示:
$ kubectl port-forward deploy/timeserver 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
这允许您通过浏览到 http://localhost:8080 从本地主机与部署进行交互。当您尝试容器化应用程序时,您可以在新的命令行窗口中查看日志输出,如下所示:
$ kubectl logs -f deploy/timeserver
Found 3 pods, using pod/timeserver-8bbb895dc-kgl8l
Listening on 0.0.0.0:80
127.0.0.1 - - [09:59:08] “GET / HTTP/1.1” 200 -
日志命令使用 -f (跟随)参数,将从部署中的一个 Pod 流式传输日志。在您的应用程序启动时记录一条语句到 stdout 是个好主意,就像这里的“监听 0.0.0.0:80”一样,这样您可以确保容器确实按预期启动。
在 Kubernetes 中,大多数操作并不是瞬时的。创建一个 Pod 需要时间来配置新的计算能力(这取决于您使用的 Kubernetes 平台)、从容器注册表下载容器以及启动您的容器。如果一切顺利,您应该在几分钟内拥有正在运行的容器。
当事情成功时,您的部署中的 Pod 在查询 kubectl get pods 时将报告状态 Running 。您可能会看到其他状态,如 Pending ,当它在等待容量时,以及 ContainerCreating ,一旦容器已被调度到您的节点并正在启动。令人困惑的是,有时 Pod 可能会卡在 Pending ——这是一种有点模糊的状态——并且可能会出现其他错误。以下是常见错误情况的列表。
故障排除:镜像拉取错误(ErrImagePull/ErrImagePullBackoff)
此错误表示 Kubernetes 无法下载容器镜像。这通常意味着在您的配置中镜像名称拼写错误,镜像在镜像仓库中不存在,或者您的集群没有访问该仓库所需的凭据。
检查您的镜像拼写并验证该镜像是否在您的仓库中。为了快速修复以使部署运行,可以尝试使用我提供的公共容器镜像。您对部署配置所做的任何修复都可以使用 kubectl apply -f deploy.yaml 应用。
故障排除:卡在待处理状态
如果您看到一个 Pod 在 Pending 状态下卡住超过一分钟,这通常意味着 Kubernetes 调度器无法在您的集群中找到空间来部署该 Pod。通常,通过向您的集群添加额外的资源,例如额外的或更大的计算节点,可以解决此问题。
您可以通过以下方式“描述”待处理的 Pod 以查看其详细信息:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
timeserver-6df7df9cbb-7g4tx 1/1 Pending 0 1m16s
$ POD_NAME=timeserver-6df7df9cbb-7g4tx
$ kubectl describe pod $POD_NAME
Events 部分包含 Kubernetes 遇到的任何错误的列表。如果您尝试调度一个 Deployment 而没有可用资源,您将看到类似 FailedScheduling 的警告。以下是我看到的事件文本,针对我尝试调度但资源不足的 Pod:
Warning FailedScheduling 26s (x2 over 26s) default-scheduler
? 0/2 nodes are available: 2 Insufficient cpu.
只要您的至少一个 Pod 处于 Running 状态,您暂时不需要担心,因为只要存在一个 Pod 来响应请求,您的服务应该仍然可以运行。然而,如果它们都处于待处理状态,您需要采取行动——可能是通过增加更多的计算资源。
故障排除:崩溃的容器(CrashLoopBackOff)
另一个常见错误是容器崩溃。容器崩溃可能有多种原因,包括容器未能启动(例如,由于配置错误)或容器在启动后不久崩溃。
在 Kubernetes 部署中,崩溃是指任何终止的容器过程——即使是以成功退出代码终止的过程。部署旨在用于长时间运行的过程,而不是一次性任务(Kubernetes 确实有一种方式来表示应该调度为一次性任务的 Pod,那就是作业对象,详见第 10 章)。
在像我们在这里部署的那种由 Deployment 管理的 Pod 中,偶尔发生的容器崩溃会通过重启来优雅地处理。实际上,当你运行 kubectl get pods 时,你可以看到一个容器被重启了多少次。你可以有一个每小时崩溃一次的容器,就 Kubernetes 而言,这完全没问题;它会不断重启该容器,并继续正常运行。
一个在启动时立即崩溃或快速崩溃的容器,会进入一个指数退避循环,在这个循环中,Kubernetes 并不是持续不断地重启它(消耗系统资源),而是在重启尝试之间引入一个指数增加的延迟(即,10 秒,然后 20 秒,40 秒,依此类推)。
当一个容器第一次崩溃时,它将具有类似 RunContainerError 的状态(对于在启动时出错的容器)或 Completed 对于已退出的容器。一旦崩溃重复几次,状态将变为 CrashLoopBackOff 。很可能,处于 CrashLoopBackOff 状态的任何容器都有需要您关注的问题。一个可能性是,当外部依赖(如数据库)未满足时,容器可能会退出,在这种情况下,您应该确保外部服务正在运行并且可以连接。
要调试崩溃的容器,我总是从 kubectl describe pod $POD_NAME 开始,就像之前的问题一样,以查看事件以获取线索。容器的日志是另一个检查的好地方。您可以通过 kubectl logs $POD_NAME 来检索这些日志。当处理崩溃的容器时,您可能希望查看容器之前实例化的日志(在崩溃后重新启动之前),以查看崩溃时打印的任何错误,因为这通常会指示原因。要做到这一点,请在您的日志请求中添加 --previous (或仅 -p ):
kubectl logs -p $POD_NAME