这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

学习 Kubernetes 基础知识

Kubernetes 基础

本教程介绍了 Kubernetes 集群编排系统的基础知识。每个模块包含关于 Kubernetes 主要特性和概念的一些背景信息,并包括一个在线互动教程。这些互动教程让你可以自己管理一个简单的集群及其容器化应用程序。

使用互动教程,你可以学习:

  • 在集群上部署容器化应用程序
  • 弹性部署
  • 使用新的软件版本,更新容器化应用程序
  • 调试容器化应用程序

这些教程使用 Katacoda 在你的浏览器中运行一个运行着 Minikube 的虚拟终端,Minikube 是 Kubernetes 的一个小规模本地部署,可以运行在任何地方。不需要安装任何软件或进行任何配置;每个交互性教程都直接从你的网页浏览器上运行。


Kubernetes 可以为你做些什么?

通过现代的 Web 服务,用户希望应用程序能够 24/7 全天候使用,开发人员希望每天可以多次发布部署新版本的应用程序。 容器化可以帮助软件包达成这些目标,使应用程序能够以简单快速的方式发布和更新,而无需停机。Kubernetes 帮助你确保这些容器化的应用程序在你想要的时间和地点运行,并帮助应用程序找到它们需要的资源和工具。Kubernetes 是一个可用于生产的开源平台,根据 Google 容器集群方面积累的经验,以及来自社区的最佳实践而设计。


1 - 创建集群

了解 Kubernetes 集群并使用 Minikube 创建一个简单的集群。

1.1 - 使用 Minikube 创建集群

了解 Kubernetes 集群。 了解 Minikube。 启动一个 Kubernetes 集群。

目标

  • 了解 Kubernetes 集群。
  • 了解 Minikube。
  • 在你的电脑上开启一个 Kubernetes 集群。

Kubernetes 集群

Kubernetes 协调一个高可用计算机集群,每个计算机作为独立单元互相连接工作。 Kubernetes 中的抽象允许你将容器化的应用部署到集群,而无需将它们绑定到某个特定的独立计算机。 为了使用这种新的部署模型,应用需要以将应用与单个主机分离的方式打包:它们需要被容器化。 与过去的那种应用直接以包的方式深度与主机集成的部署模型相比,容器化应用更灵活、更可用。 Kubernetes 以更高效的方式跨集群自动分发和调度应用容器。 Kubernetes 是一个开源平台,并且可应用于生产环境。

一个 Kubernetes 集群包含两种类型的资源:

  • 控制面调度整个集群
  • 节点负责运行应用

总结:

  • Kubernetes 集群
  • Minikube

Kubernetes 是一个生产级别的开源平台,可协调在计算机集群内和跨计算机集群的应用容器的部署(调度)和执行.


集群图


控制面负责管理整个集群。 控制面协调集群中的所有活动,例如调度应用、维护应用的所需状态、应用扩容以及推出新的更新。

节点是一个虚拟机或者物理机,它在 Kubernetes 集群中充当工作机器的角色。 每个节点都有 Kubelet,它管理节点而且是节点与控制面通信的代理。 节点还应该具有用于​​处理容器操作的工具,例如 Docker 或 rkt。 处理生产级流量的 Kubernetes 集群至少应具有三个节点,因为如果一个节点出现故障其对应的 etcd 成员和控制面实例都会丢失, 并且冗余会受到影响。你可以通过添加更多控制面节点来降低这种风险。

控制面管理集群,节点用于托管正在运行的应用。

在 Kubernetes 上部署应用时,你告诉控制面启动应用容器。 控制面就编排容器在集群的节点上运行。 节点使用控制面暴露的 Kubernetes API 与控制面通信。终端用户也可以使用 Kubernetes API 与集群交互。

Kubernetes 既可以部署在物理机上也可以部署在虚拟机上。你可以使用 Minikube 开始部署 Kubernetes 集群。 Minikube 是一种轻量级的 Kubernetes 实现,可在本地计算机上创建 VM 并部署仅包含一个节点的简单集群。 Minikube 可用于 Linux、macOS 和 Windows 系统。Minikube CLI 提供了用于引导集群工作的多种操作, 包括启动、停止、查看状态和删除。

既然你已经知道 Kubernetes 是什么,访问你好 Minikube, 在你的电脑上试试这个。

完成这一步之后,继续使用 kubectl 创建一个 Deployment

2 - 部署应用

2.1 - 使用 kubectl 创建 Deployment

学习应用的部署。 使用 kubectl 在 Kubernetes 上部署第一个应用。

目标

  • 学习应用的部署。
  • 使用 kubectl 在 Kubernetes 上部署第一个应用。

Kubernetes 部署

一旦运行了 Kubernetes 集群, 就可以在其上部署容器化应用。为此,你需要创建 Kubernetes Deployment。 Deployment 指挥 Kubernetes 如何创建和更新应用的实例。 创建 Deployment 后,Kubernetes 控制平面将 Deployment 中包含的应用实例调度到集群中的各个节点上。

创建应用实例后,Kubernetes Deployment 控制器会持续监视这些实例。 如果托管实例的节点关闭或被删除,则 Deployment 控制器会将该实例替换为集群中另一个节点上的实例。 这提供了一种自我修复机制来解决机器故障维护问题。

在没有 Kubernetes 这种编排系统之前,安装脚本通常用于启动应用,但它们不允许从机器故障中恢复。 通过创建应用实例并使它们在节点之间运行,Kubernetes Deployment 提供了一种与众不同的应用管理方法。

总结:

  • Deployment
  • kubectl

Deployment 负责创建和更新应用的实例


部署你在 Kubernetes 上的第一个应用


你可以使用 Kubernetes 命令行界面 kubectl 创建和管理 Deployment。 kubectl 使用 Kubernetes API 与集群进行交互。在本单元中,你将学习创建在 Kubernetes 集群上运行应用的 Deployment 所需的最常见的 kubectl 命令。

创建 Deployment 时,你需要指定应用的容器镜像以及要运行的副本数。 你可以稍后通过更新 Deployment 来更改该信息; 模块 56 讨论了如何扩展和更新 Deployment。

应用需要打包成一种受支持的容器格式,以便部署在 Kubernetes 上

对于你第一次部署,你将使用打包在 Docker 容器中的 hello-node 应用,该应用使用 NGINX 回显所有请求。 (如果你尚未尝试创建 hello-node 应用并使用容器进行部署,则可以首先按照 Hello Minikube 教程中的说明进行操作)。

你也需要安装好 kubectl。如果你需要安装 kubectl,参阅安装工具

现在你已经了解了部署的内容,让我们部署第一个应用!


kubectl 基础知识

kubectl 命令的常见格式是:kubectl 操作资源

这会对指定的资源(类似 nodedeployment)执行指定的操作(类似 create、describe 或 delete)。 你可以在子命令之后使用 --help 获取可能参数相关的更多信息(例如:kubectl get nodes --help)。

通过运行 kubectl version 命令,查看 kubectl 是否被配置为与你的集群通信。

查验 kubectl 是否已安装,你能同时看到客户端和服务器版本。

要查看集群中的节点,运行 kubectl get nodes 命令。

你可以看到可用的节点。稍后 Kubernetes 将根据节点可用的资源选择在哪里部署应用。

部署一个应用

让我们使用 kubectl create deployment 命令在 Kubernetes 上部署第一个应用。 我们需要提供 Deployment 命令以及应用镜像位置(包括托管在 Docker hub 之外的镜像的完整仓库地址)。

kubectl create deployment kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1

很好!你刚刚通过创建 Deployment 部署了第一个应用。这个过程中执行了以下一些操作:

  • 搜索应用实例可以运行的合适节点(我们只有一个可用的节点)
  • 调度应用在此节点上运行
  • 配置集群在需要时将实例重新调度到新的节点上

要列出你的 Deployment,使用 kubectl get deployments 命令:

kubectl get deployments

我们看到有 1 个 Deployment 运行应用的单个实例。这个实例运行在节点上的一个容器内。

查看应用

在 Kubernetes 内运行的 Pod 运行在一个私有的、隔离的网络上。 默认这些 Pod 可以从同一 Kubernetes 集群内的其他 Pod 和服务看到,但超出这个网络后则看不到。 当我们使用 kubectl 时,我们通过 API 端点交互与应用进行通信。

模块 4 中我们将讲述如何将应用暴露到 Kubernetes 集群外的其他选项。 同样作为基础教程,我们不会在这里详细解释 Pod 是什么,后面的主题会介绍它。

kubectl proxy 命令可以创建一个代理,将通信转发到集群范围的私有网络。 按下 Ctrl-C 此代理可以被终止,且在此代理运行期间不会显示任何输出。

你需要打开第二个终端窗口来运行此代理。

kubectl proxy

现在我们在主机(终端)和 Kubernetes 集群之间有一个连接。此代理能够从这些终端直接访问 API。

你可以看到通过代理端点托管的所有 API。 例如,我们可以使用以下 curl 命令直接通过 API 查询版本:

curl http://localhost:8001/version

API 服务器将基于也能通过代理访问的 Pod 名称为每个 Pod 自动创建端点。

首先我们需要获取 Pod 名称,我们将存储到环境变量 POD_NAME 中:

export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
echo Name of the Pod: $POD_NAME

你可以运行以下命令通过代理的 API 访问 Pod:

curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME/

为了不使用代理也能访问新的 Deployment,需要一个 Service,这将在下一个 模块 4 中讲述。

如果你准备好了,请访问查看 Pod 和 Node

3 - 了解你的应用

3.1 - 查看 Pod 和节点

学习如何使用 kubectl get、kubectl describe、kubectl logs 和 kubectl exec 排除 Kubernetes 应用故障。

目标

  • 了解 Kubernetes Pod。
  • 了解 Kubernetes 节点。
  • 对已部署的应用故障排除。

Kubernetes Pod

在模块 2 中创建 Deployment 时, Kubernetes 创建了一个 Pod 来托管你的应用实例。Pod 是 Kubernetes 抽象出来的, 表示一组一个或多个应用容器(如 Docker),以及这些容器的一些共享资源。这些资源包括:

  • 共享存储,当作卷
  • 网络,作为唯一的集群 IP 地址
  • 有关每个容器如何运行的信息,例如容器镜像版本或要使用的特定端口

Pod 为特定于应用的“逻辑主机”建模,并且可以包含相对紧耦合的不同应用容器。 例如,Pod 可能既包含带有 Node.js 应用的容器,也包含另一个不同的容器, 用于提供 Node.js 网络服务器要发布的数据。Pod 中的容器共享 IP 地址和端口, 始终位于同一位置并且共同调度,并在同一节点上的共享上下文中运行。

Pod 是 Kubernetes 平台上的原子单元。当我们在 Kubernetes 上创建 Deployment 时, 该 Deployment 会在其中创建包含容器的 Pod(而不是直接创建容器)。 每个 Pod 都与调度它的节点绑定,并保持在那里直到终止(根据重启策略)或删除。 如果节点发生故障,则会在集群中的其他可用节点上调度相同的 Pod。

总结:

  • Pod
  • 节点
  • Kubectl 主要命令

Pod 是一个或多个应用容器(例如 Docker)的组合,包括共享存储(卷)、IP 地址和有关如何运行它们的信息。


Pod 概览


节点

Pod 总是运行在节点上。节点是 Kubernetes 中参与计算的机器,可以是虚拟机或物理计算机,具体取决于集群。 每个节点由控制面管理。节点可以有多个 Pod,Kubernetes 控制面会自动处理在集群中的节点上调度 Pod。 控制面的自动调度考量了每个节点上的可用资源。

每个 Kubernetes 节点至少运行:

  • Kubelet,负责 Kubernetes 控制面和节点之间通信的进程;它管理机器上运行的 Pod 和容器。
  • 容器运行时(如 Docker)负责从镜像仓库中提取容器镜像、解压缩容器以及运行应用。

如果容器紧耦合并且需要共享磁盘等资源,则只应将其编排在一个 Pod 中。


节点概览


使用 kubectl 进行故障排除

在模块 2 中, 你使用了 kubectl 命令行界面。你将继续在第 3 个模块中使用 kubectl 来获取有关已部署应用及其环境的信息。 最常见的操作可以使用以下 kubectl 子命令完成:

  • kubectl get - 列出资源
  • kubectl describe - 显示有关资源的详细信息
  • kubectl logs - 打印 Pod 中容器的日志
  • kubectl exec - 在 Pod 中的容器上执行命令

你可以使用这些命令查看应用的部署时间、当前状态、运行位置以及配置。

现在我们了解了有关集群组件和命令行的更多信息,让我们来探索一下我们的应用。

节点是 Kubernetes 中负责计算的机器,可能是虚拟机或物理计算机,具体取决于集群。 多个 Pod 可以在一个节点上运行。

检查应用配置

让我们验证之前场景中部署的应用是否在运行。我们将使用 kubectl get 命令查看现存的 Pod:

kubectl get pods

如果没有 Pod 在运行,请等几秒,让 Pod 再次列出。一旦看到一个 Pod 在运行,就可以继续操作。

接下来,要查看 Pod 内有哪些容器以及使用了哪些镜像来构建这些容器,我们运行 kubectl describe pods 命令:

kubectl describe pods

我们在这里看到了 Pod 的容器相关详情:IP 地址、使用的端口以及 Pod 生命期有关的事件列表。

describe 子命令的输出宽泛,涵盖了一些我们还未讲到的概念,但不用担心, 这节课结束时你就会熟悉这些概念了。

注:describe子命令可用于获取有关大多数 Kubernetes 原语的详细信息, 包括节点、Pod 和 Deployment。describe 的输出设计为人类可读的信息,而不是脚本化的信息。

在终端中显示应用

回想一下,Pod 运行在隔离的、私有的网络中,因此我们需要代理访问它们,这样才能进行调试和交互。 为了做到这一点,我们将使用 kubectl proxy 命令在第二个终端中运行一个代理。 打开一个新的终端窗口,在这个新的终端中运行以下命令:

kubectl proxy

现在我们再次获取 Pod 命令并直接通过代理查询该 Pod。 要获取 Pod 命令并将其存到 POD_NAME 环境变量中,运行以下命令:

export POD_NAME="$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')"
echo Name of the Pod: $POD_NAME

要查看应用的输出,运行 curl 请求:

curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME:8080/proxy/

URL 是到 Pod API 的路由。

查看容器日志

应用通常发送到标准输出的所有内容都成为 Pod 内容器的日志。 我们可以使用 kubectl logs 命令检索这些日志:

kubectl logs "$POD_NAME"

注:我们不需要指定容器名称,因为在 Pod 内只有一个容器。

在容器上执行命令

一旦 Pod 启动并运行,我们就可以直接在容器上执行命令。 为此,我们使用 exec 子命令,并将 Pod 的名称作为参数。让我们列出环境变量:

kubectl exec "$POD_NAME" -- env

另外值得一提的是,由于 Pod 中只有一个容器,所以容器本身的名称可以被省略。

接下来,让我们在 Pod 的容器中启动一个 bash 会话:

kubectl exec -ti $POD_NAME -- bash

现在我们在运行 Node.js 应用的容器上有一个打开的控制台。该应用的源代码位于 server.js 文件中:

cat server.js

你可以通过运行 curl 命令查看应用是否启动:

curl http://localhost:8080

注:在这里我们使用了 localhost,因为我们在 NodeJS Pod 内执行了此命令。 如果你无法连接到 localhost:8080,请确保你已经运行了 kubectl exec 命令,并且从 Pod 内启动了该命令。

要关闭你的容器连接,键入 exit

如果你准备好了,请继续学习使用服务来暴露你的应用

3.2 - 交互式教程 - 探索你的应用

内容不可用

探索应用的交互式教程不可用。 有关更多信息,请参阅停服公告

4 - 公开地暴露你的应用

4.1 - 使用 Service 暴露你的应用

了解 Kubernetes 中的 Service。 理解标签和选择算符如何关联到 Service。 在 Kubernetes 集群外暴露应用。

目标

  • 了解 Kubernetes 中的 Service
  • 了解标签(Label)和选择算符(Selector)如何与 Service 关联
  • 在 Kubernetes 集群外用 Service 暴露应用

Kubernetes Service 总览

Kubernetes Pod 是转瞬即逝的。 Pod 拥有 生命周期。 当一个工作节点挂掉后, 在节点上运行的 Pod 也会消亡。 ReplicaSet 会自动地通过创建新的 Pod 驱动集群回到目标状态,以保证应用正常运行。 换一个例子,考虑一个具有 3 个副本的用作图像处理的后端程序。 这些副本是可替换的。前端系统不应该关心后端副本,即使某个 Pod 丢失或被重新创建。 此外,Kubernetes 集群中的每个 Pod 都有一个唯一的 IP 地址,即使是在同一个 Node 上的 Pod 也是如此, 因此需要一种方法来自动协调 Pod 之间的变化,以便应用保持运行。

Kubernetes 中的服务(Service)是一种抽象概念,它定义了 Pod 的逻辑集和访问 Pod 的协议。 Service 使从属 Pod 之间的松耦合成为可能。 和所有 Kubernetes 对象清单一样, Service 用 YAML 或者 JSON 来定义。 Service 下的一组 Pod 通常由一个 标签选择算符 来标记 (请参阅下面的说明为什么你可能想要一个 spec 中不包含 selector 的 Service)。

尽管每个 Pod 都有一个唯一的 IP 地址,但是如果没有 Service,这些 IP 不会被公开到集群外部。 Service 允许你的应用接收流量。 通过设置 Service 的 spec 中的 type,你可以用不同的方式公开 Service:

  • ClusterIP(默认)- 在集群的内部 IP 上公开 Service。这种类型使得 Service 只能从集群内访问。
  • NodePort - 使用 NAT 在集群中每个选定 Node 的相同端口上公开 Service 。使用<NodeIP>:<NodePort> 从集群外部访问 Service。是 ClusterIP 的超集。
  • LoadBalancer - 在当前云中创建一个外部负载均衡器(如果支持的话),并为 Service 分配一个固定的外部IP。是 NodePort 的超集。
  • ExternalName - 将 Service 映射到 externalName 字段的内容(例如 foo.bar.example.com),通过返回带有该名称的 CNAME 记录实现。不设置任何类型的代理。这种类型需要 kube-dns 的 v1.7 或更高版本,或者 CoreDNS 的 0.8 或更高版本。

关于不同 Service 类型的更多信息可以在使用源 IP 教程找到。 也请参阅 使用 Service 连接到应用

另外,需要注意的是有一些 Service 的用例不需要在 spec 中定义 selector。 一个创建时未设置 selector 的 Service 也不会创建相应的 Endpoint 对象。 这允许用户手动将 Service 映射到特定的端点。 没有 selector 的另一种可能是你在严格使用 type: ExternalName 服务。

总结

  • 将 Pod 暴露给外部通信
  • 跨多个 Pod 的负载均衡
  • 使用标签(Label)

Kubernetes 的 Service 是一个抽象层,它定义了一组 Pod 的逻辑集,并为这些 Pod 支持外部流量暴露、负载平衡和服务发现。


Service 和 Label

Service 为一组 Pod 提供流量路由。Service 是一种抽象,允许 Kubernetes 中的 Pod 死亡和复制,而不会影响应用。 在依赖的 Pod(如应用中的前端和后端组件)之间进行发现和路由是由 Kubernetes Service 处理的。

Service 通过标签和选择算符来匹配一组 Pod, 它们是允许对 Kubernetes 中的对象进行逻辑操作的一种分组原语。 标签是附加在对象上的键/值对,可以以多种方式使用:

  • 指定用于开发、测试和生产的对象
  • 嵌入版本标记
  • 使用标记将对象分类


标签可以在对象创建时或之后附加到对象上。它们可以随时被修改。现在使用 Service 发布我们的应用并添加一些标签。


第一步:创建新 Service

让我们来验证我们的应用正在运行。我们将使用 kubectl get 命令并查找现有的 Pod:

kubectl get pods

如果没有 Pod 正在运行,则意味着之前教程中的对象已被清理。这时, 请返回并参考 使用 kubectl 创建 Deployment 教程重新创建 Deployment。 请等待几秒钟,然后再次列举 Pod。一旦看到一个 Pod 正在运行,你就可以继续了。

接下来,让我们列举当前集群中的 Service:

kubectl get services

我们有一个名为 kubernetes 的 Service ,它在 minikube 启动集群时默认创建。 要创建一个新的 Service 然后暴露给外部流量,我们将使用 expose 命令,并将 NodePort 作为参数。

kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080

让我们再次运行 get services 子命令:

kubectl get services

我们现在有一个运行中的 Service 名为 kubernetes-bootcamp。 这里我们看到 Service 收到了一个唯一的集群内 IP(cluster-IP),一个内部端口和一个外部 IP (external-IP)(Node 的 IP)。

要得到外部打开的端口号(对于 type: NodePort 的服务),我们需要运行 describe service 子命令:

kubectl describe services/kubernetes-bootcamp

创建一个名为 NODE_PORT 的环境变量,它的值为所分配的 Node 端口:

export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')"
echo "NODE_PORT=$NODE_PORT"

现在我们可以使用 curl、Node 的 IP 地址和对外暴露的端口,来测试应用是否已经被公开到了集群外部:

curl http://"$(minikube ip):$NODE_PORT"

然后我们就会收到服务器的响应。Service 已经被暴露。

第二步:使用标签

Deployment 自动给我们的 Pod 创建了一个标签。通过 describe deployment 子命令你可以看到那个标签的名称(对应 key):

kubectl describe deployment

让我们使用这个标签来查询 Pod 列表。我们将使用 kubectl get pods 命令和 -l 参数,后面给出标签值:

kubectl get pods -l app=kubernetes-bootcamp

你可以用同样的方法列出现有的 Service:

kubectl get services -l app=kubernetes-bootcamp

获取 Pod 的名称,然后存放到 POD_NAME 环境变量:

export POD_NAME="$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')"
echo "Name of the Pod: $POD_NAME"

要应用一个新的标签,我们使用 label 子命令,接着是对象类型、对象名称和新的标签:

kubectl label pods "$POD_NAME" version=v1

这将会在我们的 Pod 上应用一个新标签(我们把应用版本锁定到 Pod 上),然后我们可以通过 describe pods 命令检查它:

kubectl describe pods "$POD_NAME"

我们可以看到现在标签已经被附加到我们的 Pod 上。我们可以通过新的标签来查询 Pod 列表:

kubectl get pods -l version=v1

我们看到了对应的 Pod。

第三步:删除一个 Service

要删除一个 Service 你可以使用 delete service 子命令。这里也可以使用标签:

kubectl delete service -l app=kubernetes-bootcamp

确认对应的 Service 已经消失:

kubectl get services

这里确认了我们的 Service 已经被删除。要确认路由已经不再被公开,你可以 curl 之前公开的 IP 和端口:

curl http://"$(minikube ip):$NODE_PORT"

这证明了集群外部已经不再可以访问应用。 你可以通过在 Pod 内部运行 curl 确认应用仍在运行:

kubectl exec -ti $POD_NAME -- curl http://localhost:8080

这里我们看到应用是运行状态。这是因为 Deployment 正在管理应用。 要关闭应用,你还需要删除 Deployment。

准备好之后,继续学习运行应用的多个实例

5 - 扩缩你的应用

5.1 - 运行多实例的应用

使用 kubectl 手动扩缩现有的应用

目标

  • 用 kubectl 扩缩应用

扩缩应用

之前我们创建了一个 Deployment, 然后通过 Service 让其可以公开访问。 Deployment 仅创建了一个 Pod 用于运行这个应用。当流量增加时,我们需要扩容应用满足用户需求。

如果你还没有学习过之前的章节, 从使用 Minikube 创建集群开始。

扩缩是通过改变 Deployment 中的副本数量来实现的。

小结:

  • 扩缩一个 Deployment

通过在使用 kubectl create deployment 命令时设置 --replicas 参数,你可以在启动 Deployment 时创建多个实例。


扩缩概述


对 Deployment 横向扩容将保证新的 Pod 被创建并调度到有可用资源的 Node 上,扩容会将 Pod 数量增加至新的预期状态。 Kubernetes 还支持 Pod 的自动扩缩容, 但这并不在本教程的讨论范围内。 将 Pods 数量收缩到 0 也是可以的,这会终止指定 Deployment 上所有的 Pod。

运行多实例的应用,需要有方法在多个实例之间分配流量。Service 有一个集成的负载均衡器, 将网络流量分配到一个可公开访问的 Deployment 的所有 Pod 上。 服务将会一直通过端点来监视 Pod 的运行,保证流量只分配到可用的 Pod 上。

扩缩是通过改变 Deployment 中的副本数量来实现的。


一旦有了多个应用实例,就可以进行滚动更新而无需停机。我们将会在教程的下一节介绍这些。 现在让我们进入终端,来扩缩我们的应用。


扩容 Deployment

要列出你的 Deployment,使用 get deployments 子命令:

kubectl get deployments

输出应该类似于:

NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   1/1     1            1           11m

我们应该有 1 个 Pod。如果没有,请再次运行该命令。结果显示:

  • NAME 列出 Deployment 在集群中的名称。
  • READY 显示当前/预期(CURRENT/DESIRED)副本数的比例。
  • UP-TO-DATE 显示为了达到预期状态,而被更新的副本的数量。
  • AVAILABLE 显示应用有多少个副本对你的用户可用。
  • AGE 显示应用的运行时间。

要查看由 Deployment 创建的 ReplicaSet,运行:

kubectl get rs

注意 ReplicaSet 名称总是遵循 [DEPLOYMENT-NAME]-[RANDOM-STRING] 的格式。 随机字符串是使用 pod-template-hash 作为种子随机生成的。

该输出有两个重要的列是:

  • DESIRED 显示了应用的预期副本数量,这是你在创建 Deployment 时定义的。这就是预期状态(desired state)。
  • CURRENT 显示了当前正在运行的副本数量。

接下来,让我们扩容 Deployment 到 4 个副本。 我们将使用 kubectl scale 命令,后面给出 Deployment 类型、名称和预期的实例数量:

kubectl scale deployments/kubernetes-bootcamp --replicas=4

要再次列举出你的 Deployment,使用 get deployments

kubectl get deployments

更改已应用,我们有 4 个应用实例可用。接下来,让我们检查 Pod 的数量是否发生变化:

kubectl get pods -o wide

现在有 4 个 Pod,各有不同的 IP 地址。这一变化会记录到 Deployment 的事件日志中。 要检查这一点,请使用 describe 子命令:

kubectl describe deployments/kubernetes-bootcamp

你还可以从该命令的输出中看到,现在有 4 个副本。

负载均衡

让我们来检查 Service 是否在进行流量负载均衡。要查找对外公开的 IP 和端口, 我们可以使用在教程之前部份学到的 describe services

kubectl describe services/kubernetes-bootcamp

export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')"

echo NODE_PORT=$NODE_PORT

接下来,我们将使用 curl 访问对外公开的 IP 和端口。多次执行以下命令:

curl http://"$(minikube ip):$NODE_PORT"

我们每个请求都命中了不同的 Pod,这证明负载均衡正在工作。

输出应该类似于:

Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-644c5687f4-wp67j | v=1
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-644c5687f4-hs9dj | v=1
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-644c5687f4-4hjvf | v=1
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-644c5687f4-wp67j | v=1
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-644c5687f4-4hjvf | v=1
                  

缩容

要将 Deployment 缩容到 2 个副本,请再次运行 scale 子命令:

kubectl scale deployments/kubernetes-bootcamp --replicas=2

要列举 Deployment 以检查是否应用了更改,使用 get deployments 子命令:

kubectl get deployments

副本数量减少到了 2 个,要列出 Pod 的数量,使用 get pods

kubectl get pods -o wide

这证实了有 2 个 Pod 被终止。

准备好之后,继续学习执行滚动更新

6 - 更新你的应用

6.1 - 执行滚动更新

使用 kubectl 执行滚动更新。

目标

  • 使用 kubectl 执行滚动更新。

更新应用程序

用户希望应用程序始终可用,而开发人员则需要每天多次部署它们的新版本。 在 Kubernetes 中,这些是通过滚动更新(Rolling Updates)完成的。 滚动更新 允许通过使用新的实例逐步更新 Pod 实例,实现零停机的 Deployment 更新。 新的 Pod 将被调度到具有可用资源的节点上。

在前面的模块中,我们将应用程序扩展为运行多个实例。这是在不影响应用程序可用性的情况下执行更新的要求。 默认情况下,更新期间不可用的 pod 的最大值和可以创建的新 pod 数都是 1。这两个选项都可以配置为(pod)数字或百分比。 在 Kubernetes 中,更新是经过版本控制的,任何 Deployment 更新都可以恢复到以前的(稳定)版本。

摘要:

  • 更新应用

滚动更新通过逐步更新 Pod 实例并替换为新的实例,从而允许在 Deployment 更新过程中实现零停机。


滚动更新概述


与应用程序扩展类似,如果 Deployment 是公开的,Service 在更新期间仅将流量负载均衡到可用的 Pod。 可用的 Pod 是指应用程序对于用户可用的实例。

滚动更新允许以下操作:

  • 将应用程序从一个环境升级到另一个环境(通过容器镜像更新)
  • 回滚到以前的版本
  • 持续集成和持续交付应用程序,无需停机

如果 Deployment 是公开的,Service 在更新期间仅将流量负载均衡到可用的 Pod。


在下面的交互式教程中,我们将应用程序更新为新版本,并执行回滚。


更新应用的版本

要列举 Deployment,请运行 get deployments 子命令:

kubectl get deployments

要列举运行中的 Pod,请运行 get pods 子命令:

kubectl get pods

要查看应用程序当前的版本,请运行 describe pods 子命令, 然后查找 Image 字段:

kubectl describe pods

要更新应用程序的镜像版本到 v2,请使用 set image 子命令,后面给出 Deployment 名称和新的镜像版本:

kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v2

此命令通知 Deployment 为应用程序使用不同的镜像,并启动滚动更新。 要检查新 Pod 的状态,并查看旧 Pod 的终止状况,请使用 get pods 子命令:

kubectl get pods

第二步:验证更新

首先,检查应用是否正在运行。要查找应用暴露的 IP 地址和端口,请运行 describe services 子命令:

kubectl describe services/kubernetes-bootcamp

创建名为 NODE_PORT 的环境变量,值为已被分配的 Node 端口:

export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')"
echo "NODE_PORT=$NODE_PORT"

接下来,针对所暴露的 IP 和端口执行 curl

curl http://"$(minikube ip):$NODE_PORT"

你每次执行 curl 命令,都会命中不同的 Pod。注意现在所有的 Pod 都运行着最新版本(v2)。

你也可以通过运行 rollout status 来确认此次更新:

kubectl rollout status deployments/kubernetes-bootcamp

要查看应用程序当前的镜像版本,请运行 describe pods 子命令:

kubectl describe pods

在输出的 Image 字段,确认你正在运行最新的版本(v2)。

回滚更新

让我们执行另一次更新,并尝试部署一个标记为 v10 的镜像:

kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=gcr.io/google-samples/kubernetes-bootcamp:v10

使用 get deployments 来查看 Deployment 的状态:

kubectl get deployments

注意,这里的输出列出的可用 Pod 数量不符合预期。 运行 get pods 子命令来列举所有的 Pod:

kubectl get pods

注意此处部分 Pod 的状态是 ImagePullBackOff

要深入了解此问题,请运行 describe pods 子命令:

kubectl describe pods

在受影响的 Pod 的 Events 部分, 可以注意到镜像的 v10 版本在仓库中不存在。

要回滚 Deployment 到上一个工作的版本,请使用 rollout undo 子命令:

kubectl rollout undo deployments/kubernetes-bootcamp

rollout undo 命令会恢复 Deployment 到先前的已知状态(v2 的镜像)。 更新是受版本控制的,你可以恢复 Deployment 到任何先前已知状态。

使用 get pods 子命令再次列举 Pod:

kubectl get pods

有四个 Pod 正在运行。要检查这些 Pod 部署的镜像, 请使用 describe pods 子命令:

kubectl describe pods

Deployment 再次使用了稳定版本的应用程序(v2)。回滚成功。

记得清理本地集群:

kubectl delete deployments/kubernetes-bootcamp services/kubernetes-bootcamp

6.2 - 交互式教程 - 更新你的应用

要与终端交互,请使用桌面/平板电脑版本