官方教程,共 6 个小节。每一小节的第一部分是知识讲解,第二部分是在线测试环境的入口。
kubectl 的命令手册
原文地址
1 创建集群
1.1 使用 Minikube 创建集群
Kubernetes 集群
Kubernetes 协调一个高可用的计算机集群,这个集群连接到一起作为一个单元工作。通过 Kubernetes 中的抽象,可以将容器化应用程序部署到集群,而不必将它们绑定到单个机器上。为了使用这种新的部署模式,应用程序需要以一种将它们与单个主机分离的方式进行打包:容器化。在过去的部署模型中,应用程序作为深度集成到主机中的包直接安装到特定的机器上,相比之下,容器化应用程序更加灵活可用。Kubernetes 以更高效的方式自动化跨集群的应用程序容器的分发和调度。Kubernetes 是一个开放源代码的平台,可以在生产环境中使用。
Kubernetes 集群由两种类型的资源组成:
- 用于协调集群的 Master
- 用于作为 worker 运行应用程序的 Node
Kubernetes 是一个生产级的开源平台,负责协调计算机集群内部和跨集群应用程序容器的布局(调度)和执行。
集群图
Master 负责管理集群。Master 协调集群中的所有活动,例如调度应用程序,维护应用程序的期望状态,扩展应用程序以及滚动升级。
Node 节点是 Kubernetes 集群中的 worker 工作节点,可以是虚拟机或物理机。每个节点都安装了 Kubelet,用于管理节点并与 Kubernetes 的 Master 进行通信。每个节点还应具有处理容器操作的工具,例如 Docker 或 rkt。处理生产环境中的流量的 Kubernetes 集群至少需要有三个节点。
Master 用于管理集群,Node 节点用于托管要运行的应用程序。
在 Kubernetes 上部署应用程序时,需要告知 Master 启动应用程序容器。Master 会规划容器运行在集群的某个节点上。每个节点通过 Master 暴露的 Kubernetes API 与 Master 通信。终端用户也可以通过 Kubernetes API 直接与集群交互。
Kubernetes 集群可以部署到物理机或虚拟机上。可以使用 Minikube 来学习 Kubernetes 的部署过程。Minikube 是一个轻量级的 Kubernetes 实现,可以在你的机器上创建虚拟机并部署一个只有单个节点的简单集群。Minikube 可以在 Linux、macOS 或 Windows 上安装。Minikube CLI 命令行界面提供了用于你的集群的基本启动操作,包括 start、stop、status 以及 delete。但是对于这个教程,你会使用一个预先安装了 Minikube 的在线终端。
1.2 交互式教程
Step 1 启动并运行集群
在线终端已经安装好了 Minikube。运行下面的命令确认一下:
minikube version
确认无误后,启动集群:
minikube start
现在,在线终端上有运行中的 Kubernetes 集群了。Minikube 会启动一个虚拟机,Kubernetes 集群运行在虚拟机上。
Step 2 集群的版本
通过 kubectl
命令可以根 Kubernetes 交互。运行 kubectl version
命令查看 kubectl 是否安装成功:
kubectl version
这里会同时看到 client 和 server 两个版本号。其中,client 对应 kubectl 的版本,server 对应 Master 上安装的 Kubernetes 的版本。这里也会显示构建的详情。
Step 3 集群详情
通过 kubectl cluster-info
命令查看集群的详情:
kubectl cluster-info
我们有一个运行中的 Master 和一个 Dashboard。Kubernetes Dashboard 允许你通过 UI 用户界面查看应用程序。在本教程中,我们将专注于通过命令行部署和探索应用程序。运行 kubectl get nodes
命令查看集群中的 Node 节点:
kubectl get nodes
这会显示所有可用于应用程序的节点。现在我们只有一个节点,且其 status 状态是 ready
,表示可以用于部署应用程序。
2 部署应用程序
2.1 使用 kubectl 创建 Deployment
Kubernetes Deployments
一旦运行了 Kubernetes 集群,就可以在其上部署容器化的应用程序。为此,需要创建一个 Deployment 用于部署应用程序。Deployment 指示 Kubernetes 如何创建和更新应用程序的实例。创建 Deployment 后,Kubernetes Master 会将应用程序实例分配到集群中的独立节点上。
创建应用程序实例后,Deployment Controller 会一直监控这些实例。如果运行实例的节点出现故障或被删除,则 Deployment Controller 将替换这些节点。这提供了一种自我修复机制来应对机器故障或维护。
在编排前的世界中,安装脚本通常用于启动应用程序,但无法从机器故障中恢复。通过创建应用程序实例并保持它们跨节点运行,Kubernetes Deployment 为应用程序管理提供了一种完全不同的方法。
Deployment 负责创建和更新应用程序的实例
在 Kubernetes 上部署第一个应用程序
可以通过 Kubectl 这个命令行接口来创建并管理 Deployment。Kubectl 使用 Kubernetes API 来跟集群交互。在这一部分你会学习最常用的 Kubectl 命令,创建一个用于在 Kubernetes 集群上运行应用程序的 Deployment。
Deployment 创建完成后,需要为你的应用程序指定容器镜像及需要运行的副本(replicas)数量。可以在后面通过更新 Deployment 来改变这些设置,本教程的第 5 节和第 6 节讲述了如何伸缩及更新 Deployment。
要部署到 Kubernetes 中,应用程序必须打包为 Kubernetes 支持的容器格式。
对于第一个 Deployment,我们会使用一个打包为 Docker 容器的 Node.js 应用。源代码和 Dockerfile 可以在 Kubernetes Bootcamp 的 GitHub 仓库 中下载。
2.2 交互式教程
Step 1 kubectl 基础
类似 Minikube,Kubectl 也安装在在线终端中。输入 kubectl
可以查看命令的具体用法。Kubectl 命令的常用格式是:kubectl 动作 资源
。这会在指定的资源(例如 node、container)上执行指定的动作(例如 create、get、describe)。可以在每个可能的参数后面使用 --help
来查看额外信息(kubectl get nodes --help
)。
$ kubectl
kubectl controls the Kubernetes cluster manager.
Find more information at: https://kubernetes.io/docs/reference/kubectl/overview/
Basic Commands (Beginner):
create Create a resource from a file or from stdin.
expose Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service
run Run a particular image on the cluster
set Set specific features on objects
run-container Run a particular image on the cluster. This command is deprecated, use "run" instead
Basic Commands (Intermediate):
get Display one or many resources
explain Documentation of resources
edit Edit a resource on the server
delete Delete resources by filenames, stdin, resources and names, or by resources and label selector
Deploy Commands:
rollout Manage the rollout of a resource
rolling-update Perform a rolling update of the given ReplicationController
scale Set a new size for a Deployment, ReplicaSet, Replication Controller, or Job
autoscale Auto-scale a Deployment, ReplicaSet, or ReplicationController
Cluster Management Commands:
certificate Modify certificate resources.
cluster-info Display cluster info
top Display Resource (CPU/Memory/Storage) usage.
cordon Mark node as unschedulable
uncordon Mark node as schedulable
drain Drain node in preparation for maintenance
taint Update the taints on one or more nodes
Troubleshooting and Debugging Commands:
describe Show details of a specific resource or group of resources
logs Print the logs for a container in a pod
attach Attach to a running container
exec Execute a command in a container
port-forward Forward one or more local ports to a pod
proxy Run a proxy to the Kubernetes API server
cp Copy files and directories to and from containers.
auth Inspect authorization
Advanced Commands:
apply Apply a configuration to a resource by filename or stdin
patch Update field(s) of a resource using strategic merge patch
replace Replace a resource by filename or stdin
convert Convert config files between different API versions
Settings Commands:
label Update the labels on a resource
annotate Update the annotations on a resource
completion Output shell completion code for the specified shell (bash or zsh)
Other Commands:
api-versions Print the supported API versions on the server, in the form of "group/version"
config Modify kubeconfig files
help Help about any command
plugin Runs a command-line plugin
version Print the client and server version information
Usage:
kubectl [flags] [options]
Use "kubectl <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all
commands).
运行 kubectl version
命令来确认 kubectl 是否已经配置为与集群交互:
kubectl version
如果同时看到了 client 和 server 的版本信息,则配置无误。
通过下面命令查看集群中的节点:
kubectl get nodes
现在我们的例子中只能看到一个节点。Kubernetes 会根据 Node 的可用资源的不同来选择一个最合适的 Node 部署应用程序。
Step 2 部署应用
现在,通过 kubectl run
命令在 Kubernetes 上运行我们的第一个应用。run
命令会创建一个新的 Deployment。我们需要提供 Deployment 的名字以及应用程序的镜像位置(如果不是 Docker Hub,则需要提供完整的仓库 URL)。可以通过 --port
参数使应用运行在特定端口上。国内无法访问 gcr.io,需要替换:
kubectl run kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1 --port=8080
注意,这里因为 墙 的问题,需要替换镜像路径为 jocatalin/kubernetes-bootcamp
,完整命令如下:
kubectl run kubernetes-bootcamp --image=jocatalin/kubernetes-bootcamp:v1 --port=8080
如果需要删除所有通过 kubectl run
命令创建的 Deployment,可以运行下面命令:
kubectl delete deployments --all
现在,通过创建 Deployment 已经成功部署了第一个应用。这为你做了几件事情:
- 搜索可以运行应用程序实例的合适节点(我们只有 1 个可用节点)
- 调度应用程序在该节点上运行
- 配置集群以在需要时将实例重新规划到新节点上
通过下面命令列出所有的 Deployment:
kubectl get deployments
这里会看到一个 Deployment,其中运行着应用程序的一个实例。实例运行在节点的 Docker 容器内。
Step 3 查看应用
Kubernetes 中运行的 Pod 运行在私有的隔离网络中。默认情况下,Pod 仅对同一个 Kubernetes 集群中的 service 和其他 Pod 可见。当我们使用 kubectl 时,会通过 API 终端交互,实现与应用程序的通信。
在第 4 小节,会讲解如何使用将应用暴露到 kubernetes 集群之外的选项。
kubectl 命令可以创建代理,将通信转发到集群范围的专用网络。代理可以通过 control-C 终止,并且在运行时不会显示任何输出。
打开第二个终端窗口来运行代理(或者以后台程序 & 的方式在同一个终端中运行):
kubectl proxy
现在,在我们的主机(在线终端)和 Kubernetes 集群之间通过代理建立了连接。通过代理可以从终端直接访问 Kubernetes API。
可以在使用 proxy 开启了代理的终端上,通过 http://localhost:8001
查看所有 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
然后,向 Pod 中运行的应用发送 HTTP 请求:
curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME/proxy/
URL 就是 Pod 中对应的 API 的路由。
注意:代理需要保持开启状态。官方示例需要新开页签并执行
kubectl proxy
指令。当然,也可以在原页签中后台执行这个命令kubectl proxy &
。
3 探索你的应用
3.1 查看 Pod 和 Node
Pod
在上一节中创建了 Deployment 之后,Kubernetes 会创建 Pod 用于托管应用实例。Pod 是一个 Kubernetes 抽象,表示一个由一个或多个应用容器(Docker 或 rkt)及用于这些容器的共享资源组成的分组。这些资源包括:
- 共享存储,作为 Volume 卷
- 网络,作为唯一的集群 IP 地址
- 信息,描述如何运行每个容器,例如容器映像版本或要使用的特定端口
Pod 模拟了特定于应用程序的“逻辑主机”,并且可以包含相对紧密耦合的不同的应用程序容器。例如,Pod 可能包含一个带有 Node.js 应用程序的容器,以及另一个用于向 Node.js Web 服务器提供数据的容器。Pod 中的容器共享一个 IP 地址和端口空间,它们总是地址相同、共同调度(co-located and co-scheduled),并在同一个节点上的共享上下文中运行。
Pod 是 Kubernetes 平台上的原子单元。当在 Kubernetes 上创建一个 Deployment 时,该 Deployment 将创建带有容器的 Pod(而不是直接创建容器)。每个 Pod 在调度到某个节点后,会与该节点绑定,并保持在该位置直到终止(根据重启策略)或删除。如果发生节点故障,则会在集群中的其他可用节点上调度相同的 Pod。
Pod 概览图
Node
Pod 总是在 Node 上运行。Node 是 Kubernetes 中的工作机器,可能是虚拟机或物理机,具体取决于集群。每个 Node 由 Master 管理。一个 Node 上可以有多个 Pod,并且 Kubernetes Master 会自动在集群中的 Node 上调度 Pod。Master 的自动调度考虑了每个节点上的可用资源。
每个 Kubernetes Node 节点至少运行:
- Kubelet,负责 Kubernetes Master 与 Node 之间的通信,并管理机器上运行的 Pod 和容器。
- 一个容器运行时(如 Docker,rkt),负责从 registry 中获取容器镜像,解包容器并运行应用程序。
如果容器紧密耦合并需要共享资源(如磁盘),则只能将它们一起安排在一个 Pod 中。
Node 概览图
使用 kubectl 进行故障排除
在第 2 小节中使用了 Kubectl 命令行界面。第 3 小节中会使用 kubectl 获取有关 Deployment 的应用程序及环境的信息。最常见的操作可以通过以下 kubectl 命令完成:
kubectl get
- 列出资源kubectl describe
- 显示有关资源的详细信息kubectl logs
- 从 Pod 中的容器打印日志kubectl exec
- 在 Pod 中的容器上执行命令
可以使用这些命令查看应用程序的部署时间、当前状态、运行位置以及配置信息。
Node 是 Kubernetes 中执行具体任务的机器,可能是虚拟机或物理机,具体取决于群集。一个 Node 上可以运行多个 Pod。
3.2 交互式教程
Step 1 检查应用的配置
先确认一下前面部署的应用是否正在运行。使用 kubectl get
命令查看存在的 Pod:
kubectl get pods
如果没有运行中的 Pod,再次执行上面命令(部署需要几秒钟的时间)。
然后,查看这个 Pod 里面有哪些容器,这些容器是通过哪些镜像构建的。使用 kubectl describe pods
命令:
kubectl describe pods
这里会看到 Pod 中容器的详情:IP 地址,使用的端口号,和 Pod 生命周期相关的事件列表。
describe 命令的输出很复杂,并且包含了许多目前还没有讲解的概念。在教程最后你会熟悉这一切。
注意:describe 命令可以获取用于大部分 Kubernetes 原语的详情:node、deployments、pods。describe 命令的输出可读性好,不适合用于脚本。
Step 2 在终端中显示应用程序
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/proxy/
URL 是 Pod 的 API 对应的路由。
Step 3 查看容器日志
应用程序发送到 STDOUT 的任何内容都将成为 Pod 中容器的日志。使用 kubectl logs
命令检索这些日志:
kubectl logs $POD_NAME
注意:这里不需要指定容器名字,因为在我们的 Pod 中只有一个容器。
Step 4 在容器中执行命令
Pod 启动并运行后,可以直接在容器中执行命令。使用 exec
命令时需要指定 Pod 的名字作为参数。列出环境变量:
kubectl exec $POD_NAME env
这里容器的名称可以省略,因为我们在 Pod 中只有一个容器。
下面,让我们在 Pod 的容器中开始一个 bash 会话:
kubectl exec -ti $POD_NAME bash
现在,在我们运行 NodeJS 应用程序的容器中开启了会话。应用程序的源代码是 server.js 文件:
cat server.js
可以通过 curl 命令确认应用程序是否启动并在运行中:
curl localhost:8080
注意:这里是在 NodeJS 容器内执行命令,所以才可以使用 localhost。
通过 exit
命令关闭到容器的连接。
4 暴露应用到外网环境
4.1 通过 Service 暴露应用程序
Kubernetes Service 概述
Kubernetes Pod 是有 生命周期 的。当工作节点宕机时,节点上运行的 Pod 也会丢失。然后,ReplicationController 会创建新的 Pod 来动态地使集群回到所需的状态,以保持应用程序的运行。另一个例子,考虑具有 3 个副本的图像处理后端。副本是可以替代的,前端系统不应该关心后端的副本,哪怕 Pod 丢失并重新创建。也就是说,Kubernetes 集群中的每个 Pod 都具有唯一的 IP 地址,即使是同一个节点上的 Pod 也是如此,因此需要一种自动协调 Pod 切换的方式,以便应用程序持续运行。
Kubernetes 中的 Service 是一个抽象,定义了一个 Pod 的逻辑分组和一个访问这些 Pod 的策略。服务使得相关 Pod 之间建立松散耦合。就像其他 Kubernetes 对象一样,通过 YAML(首选)或 JSON 来定义 Service。Service 所针对的一组 Pod 集合通常由 LabelSelector 标签选择器来确定(请参阅下面的内容以了解为什么您可能需要规范中不包含选择器的 Service。a Service without including selector in the spec)。
虽然每个 Pod 具有唯一的 IP 地址,但是如果没有 Service,这些 IP 不会暴露到集群外部。Service 允许应用程序接收流量。通过在 ServiceSpec 中指定类型,可以以不同的方式暴露 Service:
- ClusterIP(默认) - 将 Service 公开在集群的内部 IP 上。这种类型使服务只能从集群内访问。
- NodePort - 使用 NAT 在集群中每个选定节点的同一端口上暴露 Service。使用
<NodeIP>:<NodePort>
使集群外部的服务可访问。ClusterIP 的超集。 - LoadBalancer - 在当前云中创建外部负载平衡器(如果支持)并为服务分配固定的外部 IP。NodePort 的超集。
- ExternalName - 使用任意名称(由规范中的externalName指定)通过返回具有名称的 CNAME 记录来暴露 Service。没有使用代理。需要 v1.7 或更高版本的 kube-dns。
有关不同类型 Service 的更多信息可以在 Using Source IP 教程中找到。另请参阅 用服务连接应用程序。
此外,注意,有些 Service 的用例未在 spec 规范中定义 selector。创建的 Service 如果没有 selector,就不会创建相应的 Endpoint 对象。这允许用户手动将 Service 映射到特定的端点。不使用 selector 的另一个可能性是你严格使用 type: ExternalName
。
Kubernetes Service 是一个抽象层,定义了 Pod 的逻辑分组,并为这一组 Pod 实现外部流量暴露,负载均衡和服务发现。
Service 和 Label
Service 通过一组 Pod 来路由流量。Service 是一个抽象层,允许 Pod 在 Kubernetes 中死亡和复制而不影响应用程序。在相关 Pod 中的发现和路由(例如应用程序中的前端和后端组件)由 Kubernetes Services 处理。
Services 使用 标签和选择器 匹配一组 Pod,这是一个允许对 Kubernetes 中的对象进行逻辑操作的分组原语(Services match a set of Pods using labels and selectors, a grouping primitive that allows logical operation on objects in Kubernetes)。标签是附加到对象的键/值对,可以以多种方式使用:
- 指定用于开发,测试和生产的对象
- 嵌入版本标签
- 使用标签分类对象
可以在创建 Deployment 的同时在 kubectl 中使用
--expose
创建 Service。
标签可以在创建时或之后添加到对象,并且可以随时修改。现在让我们使用服务公开我们的应用程序并应用一些标签。
4.2 交互式教程
Step 1 创建 Service
首先确认应用是否正在运行。使用 kubectl get
命令查看存在的 Pod 及状态:
kubectl get pods
然后,列出集群当前运行的 Service:
kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3m
有一个名为 Kubernetes 的 Service,在 Minikube 启动集群时会默认创建这个服务。通过 expose
命令,使用 NodePort 参数(Minikube 暂时不支持 LoadBalancer),创建新 Service 并将其暴露到外网:
kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080
再次列出集群当前运行的 Service:
kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3m
kubernetes-bootcamp NodePort 10.105.185.171 <none> 8080:32327/TCP 9s
kubernetes-bootcamp 这个 Service 已经运行了。可以看到,这个 Service 有一个唯一的 CLUSTER-IP,一个内部端口号以及一个 EXTERNAL-IP(Node 节点的 IP)。
要找出开放到外部的端口(通过 NodePort 选项)是哪个,需要运行 kubectl describe service
命令:
kubectl describe services/kubernetes-bootcamp
创建名为 NODE_PORT 的环境变量,保存分配的节点端口号:
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 $(minikube ip):$NODE_PORT
如果成功获取服务器的响应,则 Service 暴露成功。
Step 2: 使用标签
Deployment 自动为 Pod 创建了一个标签。使用 kubectl describe deployment
命令,可以看到标签的名称:
# kubectl describe deployment
Name: kubernetes-bootcamp
Namespace: default
CreationTimestamp: Mon, 09 Apr 2018 07:26:15 +0000
Labels: run=kubernetes-bootcamp
Annotations: deployment.kubernetes.io/revision=1
Selector: run=kubernetes-bootcamp
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
Pod Template:
Labels: run=kubernetes-bootcamp
Containers:
kubernetes-bootcamp:
Image: gcr.io/google-samples/kubernetes-bootcamp:v1
Port: 8080/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
OldReplicaSets: <none>
NewReplicaSet: kubernetes-bootcamp-5dbf48f7d4 (1/1 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 32m deployment-controller Scaled up replica set kubernetes-bootcamp-5dbf48f7d4 to 1
可以通过这个标签查询 Pod。使用 kubectl get pods
命令时,通过 -l
参数指定标签值:
# kubectl get pods -l run=kubernetes-bootcamp
NAME READY STATUS RESTARTS AGE
kubernetes-bootcamp-5dbf48f7d4-c8jwv 1/1 Running 0 35m
查看 Service 时,也可以使用这个参数:
# kubectl get services -l run=kubernetes-bootcamp
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes-bootcamp NodePort 10.105.185.171 <none> 8080:32327/TCP 32m
获取 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
可以通过 kubectl label 对象类型 对象名字 新标签
命令创建新标签:
kubectl label pod $POD_NAME app=v1
这会为我们的 Pod 应用一个新标签(这里将应用程序的版本固定到 Pod),可以使用 kubectl describe pod
命令检查:
kubectl describe pods $POD_NAME
这里会看到标签附加到了 Pod 上。现在可以使用这个新标签来查询 Pod 列表了:
kubectl get pods -l app=v1
Step 3 删除 Service
通过 kubectl delete service -l your-label
命令删除 Service。这里也可以使用标签:
kubectl delete service -l run=kubernetes-bootcamp
确认 Service 删除是否成功:
kubectl get services
这里会发现 Service 删除成功。可以通过 curl 和之前暴露的 IP 地址和端口号确认路由不再暴露到外网:
curl $(minikube ip):$NODE_PORT
这证明集群外部无法继续访问我们的应用程序了。可以通过在 Pod 内部执行 curl 来验证应用程序仍然在运行中:
kubectl exec -ti $POD_NAME curl localhost:8080
可以看到应用仍在运行。
5 伸缩应用
5.1 运行应用的多个实例
伸缩一个应用
在之前的讲解中,我们创建了一个 Deployment,然后通过一个 Service 将其暴露到外网。Deployment 只创建一个 Pod 来运行我们的应用程序。当流量增加时,我们需要扩展应用以满足用户需求。
应用的伸缩是通过改变 Deployment 中副本的数量来完成的。
可以使用 kubectl run
命令的 --replicas
参数从头开始创建具有多个实例的Deployment。
Scaling 概览图
应用的伸缩是通过改变 Deployment 中副本的数量来完成的。
扩展 Deployment 将确保创建新 Pod 并将其调度到具有可用资源的节点。收缩 Deployment 将减少 Pod 到新的期望数量。Kubernetes 还支持 Pod 的 自动缩放,但它不在本教程的范围之内。伸缩到零也是可能的,这会终止指定 Deployment 的所有 Pod。
运行应用程序的多个实例将需要一种方法将流量分配给所有这些实例。Service 具有集成的负载均衡器,可将网络流量分配给 Deployment 的所有 Pod。Service 将使用 endpoint 持续监视正在运行的 Pod,以确保流量仅发送到可用的 Pod。
应用伸缩是通过更改 Deployment 中副本的数量来完成的。
一旦运行了多个应用程序实例,就可以在不停机的情况下执行滚动更新。在下一小节中介绍会介绍。现在,转到在线终端并扩展我们的应用程序。
5.2 交互式教程
Step 1: 伸缩 Deployment
列出 Pod:
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kubernetes-bootcamp-5c69669756-56z44 1/1 Running 0 11s 172.18.0.2 minikube
列出 Deployment:
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
kubernetes-bootcamp 1 1 1 1 2m
我们应该有 1 个 Pod。如果不是,请再次运行该命令。各字段的解释如下:
- DESIRED 字段显示配置的副本数量
- CURRENT 字段显示现在有多少副本正在运行
- UP-TO-DATE 是已更新的副本数量,在滚动更新时,这个数字会从 0 增大到 DESIRED 字段值
- AVAILABLE 字段显示用户实际可用的副本数量
然后,将 Deployment 扩展到 4 个副本。使用 kubectl scale
命令时,指定 Deployment 类型、名称以及所需实例的数量:
$ kubectl scale deployments/kubernetes-bootcamp --replicas=4
deployment.extensions "kubernetes-bootcamp" scaled
再次列出可用的 Deployment:
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
kubernetes-bootcamp 4 4 4 4 4m
更改已生效,现在应用程序有 4 个可用实例。接下来,看一下 Pod 的数量是否发生了变化:
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kubernetes-bootcamp-5c69669756-4xrp6 1/1 Running 0 57s 172.18.0.6 minikube
kubernetes-bootcamp-5c69669756-56z44 1/1 Running 0 5m 172.18.0.2 minikube
kubernetes-bootcamp-5c69669756-8lccx 1/1 Running 0 57s 172.18.0.7 minikube
kubernetes-bootcamp-5c69669756-z97gr 1/1 Running 0 57s 172.18.0.5 minikube
现在有 4 个具有不同 IP 地址的 Pod。更改已在 Deployment 事件日志中注册。使用 describe
命令查看:
$ kubectl describe deployments/kubernetes-bootcamp
Name: kubernetes-bootcamp
Namespace: default
CreationTimestamp: Thu, 03 May 2018 13:21:05 +0000
Labels: run=kubernetes-bootcamp
Annotations: deployment.kubernetes.io/revision=1
Selector: run=kubernetes-bootcamp
Replicas: 4 desired | 4 updated | 4 total | 4 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
Pod Template:
Labels: run=kubernetes-bootcamp
Containers:
kubernetes-bootcamp:
Image: gcr.io/google-samples/kubernetes-bootcamp:v1
Port: 8080/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Progressing True NewReplicaSetAvailable
Available True MinimumReplicasAvailable
OldReplicaSets: <none>
NewReplicaSet: kubernetes-bootcamp-5c69669756 (4/4 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 6m deployment-controller Scaled up replica set kubernetes-bootcamp-5c69669756 to 1
Normal ScalingReplicaSet 2m deployment-controller Scaled up replica set kubernetes-bootcamp-5c69669756 to 4
从这个命令的输出中也可以看到现在有 4 个副本。
Step 2: 负载均衡
检查 Service 是否对流量做了负载均衡。可以通过 describe
命令找出暴露的 IP 地址和端口:
kubectl describe services/kubernetes-bootcamp
创建名为 NODE_PORT 的环境变量保存节点的端口号:
$ export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')
$ echo NODE_PORT=$NODE_PORT
NODE_PORT=30999
然后,通过 curl 访问暴露的 IP 地址和端口号。多次执行这个命令:
$ curl $(minikube ip):$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5c69669756-j58hc | v=1
每个请求会命中不同的 Pod。这证明负载均衡生效了。
Step 3: 缩减应用
再次运行 kubectl scale
命令将 Service 缩减为 2 个副本:
$ kubectl scale deployment/kubernetes-bootcamp --replicas=2
deployment.extensions "kubernetes-bootcamp" scaled
列出 Deployment 来验证变更是否生效:
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
kubernetes-bootcamp 2 2 2 2 2m
期望的副本数是 2。列出 Pod 的数量:
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGEIP NODE
kubernetes-bootcamp-5c69669756-dmbj8 1/1 Terminating 0 2m172.18.0.5 minikube
kubernetes-bootcamp-5c69669756-j58hc 1/1 Terminating 0 2m172.18.0.2 minikube
kubernetes-bootcamp-5c69669756-mvj7v 1/1 Running 0 2m172.18.0.3 minikube
kubernetes-bootcamp-5c69669756-n47zs 1/1 Running 0 2m172.18.0.4 minikube
只剩 2 个运行中的 Pod 了。
6 更新应用
6.1 执行滚动更新
更新应用
用户希望应用程序随时都可以访问,而开发者希望每天能部署几个新版本。在 Kubernetes 中通过滚动更新实现这两个目的。滚动更新使用新的实例逐个更新 Pod(而不是一次全部更新),从而实现不停机对 Deployment 的更新。新 Pod 将分配到具有可用资源的节点上。
在之前的讲解中,我们伸缩了应用程序以运行多个实例。这是执行更新而不影响应用程序可用性的要求。默认情况下,更新过程中允许不可用的 Pod 的最大数量以及可以创建的新 Pod 的最大数量为 1。这两个选项都可以配置为数字或百分比(相对于 Pods)。在 Kubernetes 中,更新是版本化的,任何 Deployment 的更新都可以恢复到以前的(稳定)版本。
滚动更新使用新的实例逐个更新 Pod(而不是一次全部更新),从而实现不停机对 Deployment 的更新。
滚动升级概览
与应用程序伸缩类似,如果 Deployment 暴露到外网,在更新期间 Service 会将流量负载平衡到可用的 Pod。可用的 Pod 是可以响应用户请求的应用程序的可用实例。
滚动更新允许执行以下操作:
- 将应用程序从一个环境推到另一个环境(通过容器镜像更新)
- 回退到以前的版本
- 以零停机时间持续集成和持续交付应用程序
如果 Deployment 暴露到外网,在更新期间 Service 会将流量负载平衡到可用的 Pod。
在下面的交互式教程中,会将我们的应用程序更新为新版本,并执行回滚。
6.2 交互式教程
Step 1: 更新应用程序的版本
列出所有 Deployment:
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
kubernetes-bootcamp 4 4 4 4 16s
列出运行中的 Pod:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kubernetes-bootcamp-5c69669756-2qclp 1/1 Running 0 35s
kubernetes-bootcamp-5c69669756-btznb 1/1 Running 0 35s
kubernetes-bootcamp-5c69669756-dfjzr 1/1 Running 0 35s
kubernetes-bootcamp-5c69669756-kl225 1/1 Running 0 35s
通过对 Pod 执行 describe
命令(查看 Image 字段)查看当前应用程序的版本。
$ kubectl describe pods
Name: kubernetes-bootcamp-5c69669756-2qclp
Namespace: default
Node: minikube/172.17.0.33
Start Time: Thu, 03 May 2018 14:39:49 +0000
Labels: pod-template-hash=1725225312
run=kubernetes-bootcamp
Annotations: <none>
Status: Running
IP: 172.18.0.2
Controlled By: ReplicaSet/kubernetes-bootcamp-5c69669756
Containers:
kubernetes-bootcamp:
Container ID: docker://bd2acdb49f2d9a2e9f796065372425562818156e8f121c69b11c29c260f2f106
Image: gcr.io/google-samples/kubernetes-bootcamp:v1
Image ID: docker-pullable://gcr.io/google-samples/kubernetes-bootcamp@sha256:0d6b8ee63bb57c5f5b6156f446b3bc3b3c143d233037f3a2f00e279c8fcc64af
Port: 8080/TCP
Host Port: 0/TCP
State: Running
Started: Thu, 03 May 2018 14:39:51 +0000
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-86srb (ro)
Conditions:
Type Status
Initialized True
Ready True
PodScheduled True
Volumes:
default-token-86srb:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-86srb
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 1m (x2 over 1m) default-scheduler 0/1 nodes areavailable: 1 node(s) were not ready.
Normal Scheduled 1m default-scheduler Successfully assigned kubernetes-bootcamp-5c69669756-2qclp to minikube
Normal SuccessfulMountVolume 1m kubelet, minikube MountVolume.SetUp succeeded for volume "default-token-86srb"
Normal Pulled 1m kubelet, minikube Container image "gcr.io/google-samples/kubernetes-bootcamp:v1" already present on machine
Normal Created 1m kubelet, minikube Created container
Normal Started 1m kubelet, minikube Started container
Name: kubernetes-bootcamp-5c69669756-btznb
Namespace: default
Node: minikube/172.17.0.33
Start Time: Thu, 03 May 2018 14:39:49 +0000
Labels: pod-template-hash=1725225312
run=kubernetes-bootcamp
Annotations: <none>
Status: Running
IP: 172.18.0.3
Controlled By: ReplicaSet/kubernetes-bootcamp-5c69669756
Containers:
kubernetes-bootcamp:
Container ID: docker://40dfdafb48176b77efaa6eaf3c8ed256feffd15e60743d4da51419eb3d5c9a33
Image: gcr.io/google-samples/kubernetes-bootcamp:v1
Image ID: docker-pullable://gcr.io/google-samples/kubernetes-bootcamp@sha256:0d6b8ee63bb57c5f5b6156f446b3bc3b3c143d233037f3a2f00e279c8fcc64af
Port: 8080/TCP
Host Port: 0/TCP
State: Running
Started: Thu, 03 May 2018 14:39:52 +0000
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-86srb (ro)
Conditions:
Type Status
Initialized True
Ready True
PodScheduled True
Volumes:
default-token-86srb:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-86srb
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 1m (x3 over 1m) default-scheduler 0/1 nodes areavailable: 1 node(s) were not ready.
Normal Scheduled 1m default-scheduler Successfully assigned kubernetes-bootcamp-5c69669756-btznb to minikube
Normal SuccessfulMountVolume 1m kubelet, minikube MountVolume.SetUp succeeded for volume "default-token-86srb"
Normal Pulled 1m kubelet, minikube Container image "gcr.io/google-samples/kubernetes-bootcamp:v1" already present on machine
Normal Created 1m kubelet, minikube Created container
Normal Started 1m kubelet, minikube Started container
Name: kubernetes-bootcamp-5c69669756-dfjzr
Namespace: default
Node: minikube/172.17.0.33
Start Time: Thu, 03 May 2018 14:39:50 +0000
Labels: pod-template-hash=1725225312
run=kubernetes-bootcamp
Annotations: <none>
Status: Running
IP: 172.18.0.5
Controlled By: ReplicaSet/kubernetes-bootcamp-5c69669756
Containers:
kubernetes-bootcamp:
Container ID: docker://822193c72cdd69142f355c1e514b9a63246c9b29b34e8c3424d74e422dbc2461
Image: gcr.io/google-samples/kubernetes-bootcamp:v1
Image ID: docker-pullable://gcr.io/google-samples/kubernetes-bootcamp@sha256:0d6b8ee63bb57c5f5b6156f446b3bc3b3c143d233037f3a2f00e279c8fcc64af
Port: 8080/TCP
Host Port: 0/TCP
State: Running
Started: Thu, 03 May 2018 14:39:52 +0000
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-86srb (ro)
Conditions:
Type Status
Initialized True
Ready True
PodScheduled True
Volumes:
default-token-86srb:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-86srb
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 1m (x3 over 1m) default-scheduler 0/1 nodes areavailable: 1 node(s) were not ready.
Normal Scheduled 1m default-scheduler Successfully assigned kubernetes-bootcamp-5c69669756-dfjzr to minikube
Normal SuccessfulMountVolume 1m kubelet, minikube MountVolume.SetUp succeeded for volume "default-token-86srb"
Normal Pulled 1m kubelet, minikube Container image "gcr.io/google-samples/kubernetes-bootcamp:v1" already present on machine
Normal Created 1m kubelet, minikube Created container
Normal Started 1m kubelet, minikube Started container
Name: kubernetes-bootcamp-5c69669756-kl225
Namespace: default
Node: minikube/172.17.0.33
Start Time: Thu, 03 May 2018 14:39:50 +0000
Labels: pod-template-hash=1725225312
run=kubernetes-bootcamp
Annotations: <none>
Status: Running
IP: 172.18.0.4
Controlled By: ReplicaSet/kubernetes-bootcamp-5c69669756
Containers:
kubernetes-bootcamp:
Container ID: docker://60f8bd1b989b701a5a51371db665886aba700839e9cf21651bc8385781f13b34
Image: gcr.io/google-samples/kubernetes-bootcamp:v1
Image ID: docker-pullable://gcr.io/google-samples/kubernetes-bootcamp@sha256:0d6b8ee63bb57c5f5b6156f446b3bc3b3c143d233037f3a2f00e279c8fcc64af
Port: 8080/TCP
Host Port: 0/TCP
State: Running
Started: Thu, 03 May 2018 14:39:52 +0000
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-86srb (ro)
Conditions:
Type Status
Initialized True
Ready True
PodScheduled True
Volumes:
default-token-86srb:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-86srb
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 1m (x3 over 1m) default-scheduler 0/1 nodes areavailable: 1 node(s) were not ready.
Normal Scheduled 1m default-scheduler Successfully assigned kubernetes-bootcamp-5c69669756-kl225 to minikube
Normal SuccessfulMountVolume 1m kubelet, minikube MountVolume.SetUp succeeded for volume "default-token-86srb"
Normal Pulled 1m kubelet, minikube Container image "gcr.io/google-samples/kubernetes-bootcamp:v1" already present on machine
Normal Created 1m kubelet, minikube Created container
Normal Started 1m kubelet, minikube Started container
执行 set image
命令,并指定 Deployment 名称及新镜像,升级应用程序的镜像到版本 2。
$ kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v2
deployment.apps "kubernetes-bootcamp" image updated
命令通知 Deployment 为应用程序使用不同的镜像,并初始化滚动更新。检查新 Pod 的状态:
kubectl get pods
Step 2: 验证升级
首先,检查应用程序是否在运行。通过 describe service
命令找出暴露的 IP 地址和端口号:
kubectl describe services/kubernetes-bootcamp
创建名为 NODE_PORT 的环境变量,保存分配到的节点端口号:
export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')
echo NODE_PORT=$NODE_PORT
然后,通过 curl 访问暴露的 IP 地址和端口号:
curl $(minikube ip):$NODE_PORT
每次请求命中不同的 Pod,且所有 Pod 都运行最新版本(v2)。
更新也可以通过 rollout status
命令来确认:
kubectl rollout status deployments/kubernetes-bootcamp
通过在 Pod 上执行 describe
命令来查看应用程序当前运行的镜像的版本号:
kubectl describe pods
查看 Image 字段,现在运行的是应用程序的版本 2。
Step 3: 回滚更新
现在执行另外一个更新,部署标记为 v10 的镜像:
kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=gcr.io/google-samples/kubernetes-bootcamp:v10
查看 Deployment 的状态:
kubectl get deployments
出错了。。。没有可用的 Pod 数量。查看所有的 Pod:
kubectl get pods
针对 Pod 的 describe
命令可以提供更多信息:
kubectl describe pods
仓库中没有名为 v10 的镜像。现在要回到之前的可以正常工作的版本。使用 rollout undo
命令:
kubectl rollout undo deployments/kubernetes-bootcamp
rollout 命令将 Deployment 恢复到之前已知的状态(v2 版本的镜像)。更新是版本化的,你可以恢复到任何之前知道的 Deployment 状态。再次列出 Pods:
kubectl get pods
4 个 Pod 正在运行。再次检查部署到这些 Pod 上的镜像:
kubectl describe pods
可以看到 Deployment 使用的是稳定版本的应用程序(v2)。回滚成功了。
所有评论(0)