3

部署你的第一个应用程序

本章涵盖

             在你的笔记本上运行单节点的Kubernetes集群

             在Google Kubernetes引擎上建立Kubernetes集群

             使用kubectl命令行工具设置和使用

       •      在Kubernetes部署应用,让它全球可用

       •      水平扩张应用程序

这一章的目标是向你展示如何运行开发本地单节点Kubernetes集群或在云上适当设置,管理多节点集群。一旦你运行集群,你将可用使用集群运行你在前一章创建的容器。

3.1 部署Kubernetes集群

建立成熟,多节点的Kubernetes集群并不是简单的任务,特别当你不熟悉Linux与网络管理。正确的安装跨多个物理或虚拟机的Kubernetes,要求正确的网络配置,以允许集群中的所有容器能相互通信。

       你可以在你的笔记本上、你组织的基础设施上,或云供应商(Google Compute Engine,Amazon EC2,Microsoft Azure,等等)提供的虚拟机上安装Kubernetes。作为选择,大部分云提供商现在提供管理Kubernetes服务,为你省去安装和管理的麻烦。以下是最大云提供商们提供的K8S服务概览:

  • Google提供GKE-Google Kubernetes引擎,
  • Amazon 有EKS-Amazon弹性Kubernetes服务,
  • Microsoft有AKS-Azure Kuberntes服务,
  • IBM有IBM云Kubernetes服务,
  • Alibaba 提供Alibaba云容器服务,

安装和管理Kubernetes比仅仅使用它要困难得多,特别是在你非常熟悉它的架构和操作之前。因此,我们将从最简单的方式获得一个工作的Kubernetes集群开始。你将学习几种方式在你的本地运行单节点Kubernetes集群,以及如何使用运行在GKE上的集群。

       第三中选择,牵涉使用kubeadm工具安装集群,这在附录B解释。该教程将向您展示如何使用虚拟机设置一个三节点的Kubernetes集群。但是你可能想在你熟悉Kubernetes之后再尝试。还有许多其他选择,但是其他选择超出了本书的范围。引用kuberntes.io网址了解更多。

       如果你有权访问其他人已经部署的集群,你可以跳过本节直接跳到3.2节,在那里你将学习如何与Kubernetes集群交互。

3.1.1 使用Docker Desktop中内置的Kubernetes集群

如果你使用macOS或Windows操作系统,为了运行前一章的例子,你大概率已经安装了Docker桌面。它包含一个你可以通过设置会话框开启的单节点的Kubernetes集群。这可能是最容易的方式开启你的kubernetes之旅,但请记住,Kubernetes的版本可能没有使用下一节中描述的替代选项时那么新。

注意 虽然从技术上讲不是集群,Docker Desktop提供的单节点Kubernetes系统应该足够探索这本书讨论的大部分主题。当练习需要多节点集群的时候,我会指出来。

在Docker Desktop中启用Kubernetes

假设你的电脑已经安装了Docker Desktop,你可以通过打开设置会话框,点击系统托盘的鲸鱼图标启动Kubernetets集群。点击Kubernetes选项卡,确保Kubernetes复选框已经勾上。组成控制平面的组件作为Docker容器运行,但是,当您调用docker ps命令时,它们不会显示在正在运行的容器列表中。要显示它们,请选中“显示系统容器”复选框。

              注意 第一次安装集群要几分钟,因为Kubernetes组件的所有容器镜像要下载

图3.1 Windows操作系统Docker Desktop设置对话框

如果你想重置集群,删除你已经部署的所有对象,记住点至重置Kubernetes集群按钮。

可视化系统

为了理解运行在Docker Desktop中的Kubernetes有哪些组件,看下图.

图3.2 运行在Docker Desktop中的Kubernetes

Docker Desktop在Docker Daemon驻留的机器上创建一个Linux虚拟机并且在虚拟机上创建所有的容器。虚拟机也运行了Kubelet-Kubernetes代理管理的节点。控制平面的组件都运行在容器中,就像你部署的应用一张。

       列出运行的容器,你不需要登录VM,因为你操作系统上由docker CLI工具展示容器。

从内部探索虚拟机

在撰写本文时,如果您想从内部探索虚拟机,Docker Desktop没有提供登录虚拟机的命令。然而,你可以运行特殊的容器配置使用VM的命名空间运行远程shell,几乎等同于通过SSH访问远程服务器。为了运行容器,执行如下命令:

$ docker run --net=host --ipc=host --uts=host --pid=host --privileged \
--security-opt=seccomp=unconfined -it --rm -v /:/host alpine chroot /host

这个长命令要求解释:

  • 容器是从alpine镜像创建的。
  • --net, --ipc, --uts 与—pid使得容器使用主机的命名空间而不是使用沙盒,--privileged和—security-opt标志给容器无限制的访问系统调用的权力。
  • --it标志以交互模式运行容器,--rm标志确保容器在它们终止的时候被删除。
  • -v标志挂载主机的根目录到容器的/host目录。然后使用chroot /host命令将该目录设置为容器中的根目录。

运行该命令后,您将处于一个shell中,它实际上与你SSH进入虚拟机使用的shell是一样的。使用shell探索VM-试着通过执行ps aux命令列出所有执行的进程或通过运行ip addr命令列出所有运行的网卡。

3.1.2 使用Minikube运行本地集群

另外一种创建Kubernetes集群的方式是使用Minikube,一个由Kubernetes社区维护的工具。Minikube部署的Kubernetes版本一般比Docker Desktop部署的版本更新。集群由一个单节点组成,其适合测试Kubernetes和本地部署应用。它正常在Linux VM中运行Kubernetes,但是如果你的计算机是基于Linux操作系统,Kubernetes也可以通过Docker直接部署在你的主机上。

注意 如果你使用VM配置Minikube,你不需要Docker,但是你需要一个类似于VirtualBox的管理程序。在其他情况你需要Docker,而部署管理程序.

安装Minikube

Minikube支持MacOS,LinuxWindows. 它有单个可执行二进制文件,你可以在MinikubeGitHub上的仓库找到它(http://github.com/kubernetes/minikube).

最好按照那里发布的当前安装说明进行安装,但粗略地说,您可以按照以下方式安装它。

       macOS你可以用Brew包管理器安装Minikube,在Windows上你可以下载一个安装器,在Linux上你可以下载一个.deb或者.rpm包,或者简单下载二进制文件并且用以下指令执行它:

$ curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linuxamd64 && sudo install minikube-linux-amd64 /usr/local/bin/minikube

对于你的特殊操作系统,请引用在线安装引导。

Minikube启动Kubernetes集群

在安装Minikube之后,使用下面列表中所示启动kubernetes集群.

这个过程可能要几分钟,因为VM镜像和Kubernetes组件的容器镜像需要下载。

建议 如果你使用Linux,你可以不通过虚拟机创建集群以减少Minikube要求的资源。使用命令: minikube start –vm-driver none

查看Minikube的状态

当minikube启动命令完成的适合,你可以通过运行minikube status查看状态,如下类比所示.

命令的输出展示Kubernetes主机(Kubernetes驻留的虚拟机)正在运行,Kubelet也做运行-复杂管理节点的代理-Kubernetes API服务器也在运行.最后一行展示使用Minikube提供的Kubernetes集群的kubectl命令行工具(CLI)已配置。Minikube没有安装CLI工具,同时也创建了它的配置文件.如何安装CLI工具已经在3.2解释过。

可视化系统

下图展示了系统架构,基本和Docker Desktop一样.

图3.3 使用Minikube运行单节点的Kubernetes集群

控制平面组件在虚拟机的容器中运行,如果使用——VM -driver none选项创建集群,则直接在主机操作系统中运行。控件中直接运行Kubelet虚拟机或主机的操作系统。它通过Docker守护进程运行部署在集群中的应用程序。

您可以运行minikube ssh登录到minikube VM,并从内部探索它。例如,您可以通过运行ps aux来列出正在运行的进程,或者运行docker ps来列出正在运行的容器,从而查看虚拟机中正在运行的内容。

建议   如果您希望在本地的docker CLI实例中列出容器,例如在docker Desktop中,请执行以下命令:eval $(minikube docker-env)

3.1.3 使用kind运行本地集群(在Docker中的Kubernetes)

Minikube的一个替代是kind,虽然不是很成熟。不是在虚拟机上或直接在主机上运行Kubernetes,kind一个容器中运行一个kubernetes集群,这运行它通过启动多个容器创建多节点的集群。你部署到Kubernetes的应用容器在节点容器中运行.系统如下图所示.

图3.4 使用kind运行多节点的kubernetes

在前一章我提到容器实际上是运行在主机上的进程。这意味着当你用kind运行Kubernetes时,所有的Kubernetes组件都运行在你的主机上。你部署到Kubernetes集群的应用也部署在你的主机操作系统上。

    这使得kind成为完美的开发测试工具,因为一切都运行本地,你可以调试运行进程就像在容器外运行它们一样容易。当我在Kubernetes上开发应用时我宁愿使用这种方案,因为它允许我做神奇的事情,像运行网络流量风险工具比如Wireshark,甚至在我运行我应用的容器中运行浏览器。我使用工具nsenter运行我在容器的网络或其他命名空间中运行那些工具。

    如果你是一个Kubernetes信息,最安全的选择是从Minikube开始,但是如果你感觉冒险,如下是如何从kind开始。

安装KIND

就像Minikube,kind由单个二进制可执行文件组成。安装KIND,应用安装指令https://kind.sigs.k8s.io/docs/user/quick-start/. 在macOS与Linux上,安装命令如下:

$ curl -Lo ./kind https://github.com/kubernetessigs/kind/releases/download/v0.7.0/kind-$(uname)-amd64 && \chmod +x ./kind && \mv
./kind /some-dir-in-your-PATH/kind

查看文档以了解最新版本,并在上面的示例中使用它而不是v0.7.0。另外,将/some-dir-in-your-PATH/替换为路径中的实际目录.

    说明要使用kind,必须在您的系统上安装Docker。

使用KIND启动Kubernetes集群

使用Kind启动Kubernetes集群就像Minikube一样容器。执行如下命令

        $ kind create cluster

像Minikube,kind配置kubectl使用它创建的集群.

使用kind启动多节点集群

Kind默认运行单节点集群。如果要运行具有多个工作节点的集群,必须首先创建一个名为kind-multi-node的配置文件。(你可以在本书的代码存档目录Chapter03/中找到该文件):

文件就绪后,使用以下命令创建集群:

    $ kind create cluster --config kind-multi-node.yaml

列出工作节点

在撰写本文时,kind没有提供检查集群状态的命令,但是您可以使用kind get节点列出集群节点,如下一个清单所示。

注意 由于宽度的限制,本书中使用了control-plane、worker1和worker2节点名,而不是实际的节点名。

由于每个节点都作为容器运行,因此您还可以通过使用docker ps列出正在运行的容器来查看节点,如下面的清单所示。

登录到kind提供的集群节点

与Minikube不同的是,如果您想要查看节点内运行的进程,您可以使用Minikube ssh登录到节点,而Minikube则使用docker exec。例如,要进入名为kind-control-plane的节点,执行命令:

    $ docker exec -it kind-control-plane bash

不是使用Docker来运行容器,由kind创建的节点使用CRI-O容器运行时,我在前一章中提到过,作为Docker的轻量级替代品。crictl命令行工具用于与CRI-O交互。它的用法与docker工具非常相似。登录到节点后,通过运行crictl ps而不是docker ps来列出其中运行的容器。下面的清单显示了该命令的输出示例:

3.1.4 使用GKE创建管理集群

3.1.5 使用Amazon EKS创建集群

3.2 与kubernetes交互

你已经了解了几种部署Kubernetes集群的方法。现在是适合学习如何使用集群。与Kubernetes交互,你必须使用命令行工具kubectl,发音kube-control,kube-C-T-L或kube-cuddle。

    如下图所示,工具通过Kubernetes API服务器通信, 其是kubernetes控制平面的一部分。然后控制平面触发其他组件完成你通过API做的改变。

图3.6 如何与Kubernetes集群交互

3.2.1 设置kubectl-Kubernetes命令行客户端

Kubectl是一个可执行文件,你必须下载到你的计算机,把它放进你的路径。它从一个叫kubeconfig的文件加载它的配置。为了使用kubectl,你必须安装它并且准备kubeconfig文件让kubectl知道它在跟哪个集群交互。

下载安装KUBECTL

可以使用以下命令下载并安装Linux的最新稳定版本:

$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s
https://storage.googleapis.com/kubernetesrelease/release/stable.txt)/bin/linux/amd64/kubectl && chmod +x kubectl && sudo mv
kubectl /usr/local/bin/

在macOS上安装kubectl,你也可以使用同样的命令,但要用darwin替代linux,或者通过Homebrew运行brew install kubectl。

    在Windows上,从https://storage.googleapis.com/kubernetesrelease/release/v1.18.2/bin/windows/amd64/kubectl.exe下载kubectl.exe。下载最新的版本,首先查看https://storage.googleapis.com/kubernetes-release/release/stable.txt最新的稳定版,然后用稳定版替换上面URL的版本。检查是否正确安装,运行kubectl –help。注意kubectl可能配置也可能没有配置要通信的Kubernetes集群,这意味着大部分命令还不能用。

建议 你可以在任意的kubectl命令后面追加—help获取更多命令做了什么以及如何使用它的更多信息。

建立Kubectl的缩写

你将经常使用kubectl。没有必要每一次都耗时输入整个命令,你可以通过缩写然后使用tab键补全加快输入。

    大部分kubernetes用户使用k作为kubectl的缩写。如果你还没有设置缩写,以下是如何在Linux和macOS上设置它。把以下行添加到你的~/.bashrc或类似文件:

        Alias k=kubectl

在Windows上,如果你用命令提示,通过执行doskey k=kubectl $.*定义缩写。如果你使用PowerShell,执行set-alias -name k -value kubectl.

注意 如果你使用gcloud建立集群,你可能不需要缩写。它处理安装kubectl之外还安装了K。

配置TAB不全KUBECTL

即使用与K类似的缩写,你也必须输入许多。幸运的是,幸运的是,kubectl命令还可以输出bash和zsh shell的shell完成代码。它不仅允许tab补全命名名,同时也补全对象名,比如,之后你将学习如何通过执行如下的命令查看指定集群节点的细节:

    $ kubectl describe node gke-kubia-default-pool-9bba9b18-4glf

这有许多你要一直重复的输入。用tab补全,输入变得更简单。你输入每个符号的前几个字符,然后按TAB键即可:

    $ kubectl desc<TAB> no<TAB> gke-ku<TAB>

在bash中启用tab补全,首先,你必须要安装bash-completion包然后允许以下命令(你也可以添加它到~/.bashrc或其他类似的文件)

    $ source <(kubectl completion bash)

但有一点需要注意。仅当您使用完整的kubectl命令名时,它才补全命令。当你使用k缩写的适合它不会起作用。为了让它对缩写也生效。你必须使用sed工具转换kubectl completion命令的输出:

    $ source <(kubectl completion bash | sed s/kubectl/k/g)

3.2.2 使用指定的Kubernetes集群配置kubectl

Kubeconfig配置文件在~/.kube/config.如果你使用Docker Desktop,minikube或GKE部署集群,它们已经为你创建了该文件。如果你访问现有的集群,你已经已经收到了这个文件。其他工具,比如kind,可能把配置文件写在不同的位置。不是移动文件到默认文件,你也可以通过如下命令,设置环境变量KUBECONFIG,让它指向配置文件:

    $ export KUBECONFIG=/path/to/custom/kubeconfig

学习更多如何管理kubectl的配置并且从头开始创建配置文件,引用附录A。

注意 如果你使用几个Kubernetes集群(比如,Minikube和GKE),看附录A,关于在不同kubectl上下文的切换的信息。

3.2.3 使用kubectl

假设你已经安装配置了kubectl,现在你可以使用它与你的集群通信。

验证集群是否启动以及kubectl能集群通信

要验证您的集群是否正在工作,请使用kubectl cluster-info命令,如下面的清单所示。

这表明API服务器已激活并且响应了请求。输出列出在集群中运行的各种Kubernetes集群服务的url。上述的例子除了显示API Server外,还显示了kubeDNS服务,它在整个集群内部提供域名服务,它是运行在集群中的另一个服务。

列出集群节点

现在使用kubectl命令列出集群中的所有节点。下面的清单显示了对具有三个节点的GKE集群执行kubectl时生成的输出

Kubernetes中的一切都用对象表示,可用通过RESTful API检索与操作。Kubectl get命令检索使用API指定类型的对象列表。你将一直使用这个命令,但是它仅仅展示列出对象的概要信息。

检索对象的额外细节

查看对象的详细信息,要使用kubectl describe命令,它的输出展示更多信息:

    $ kubectl describe node gke-kubia-85f6-node-0rrx  

我忽略describe命令的实际输出,因为它非常多,在本书中完全无法阅读。如果你自己运行这个命令,你将看到它显示状态码,关于CPU和内存的使用,系统信息,运行在节点上的容器,以及其他信息。

    如果你运行kubectl describe命令时没有指定资源名,节点的所有信息都会打印处理。

    建议 不指定对象名执行describe命令很有用,当仅存在确定的对象类型。你不用输入或拷贝/粘贴对象名。

通过本书你将学习到更多其他的kubectl命令。

3.2.4 通过web仪表板与Kubernetes交互

如果你更喜欢图形化web用户接口,你将乐意听到Kubernetes也有一个很好的web仪表板。然而,注意,仪表板功能可能远远落后于kubectl,kubectl是与kubernetes交互的主要工具。

    尽管如此,仪表板在上下文中显示了不同的资源,这是一个很好的开始,可以让你了解Kubernetes中的主要资源类型是什么,以及它们之间是如何相互关联的。仪表板还提供了修改已部署对象的可能性,并为每个操作显示等效的kubectl命令——大多数初学者都会喜欢这个特性。

    图3.7展示部署在集群中有两个工作负载的仪表板。

图3.7 基于web仪表板的kubernetes截屏

虽然你不会在本书中使用仪表板,但您可以随时打开它,以便在通过kubectl创建对象后快速查看部署在集群中的对象的图形视图。

访问在Docker Desktop中的仪表板

不幸的是,Docker Desktop默认没有安装Kubernetes仪表板。访问它也不轻松,但这里是怎么做。第一,你需要使用如下命令安装它:

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-
rc5/aio/deploy/recommended.yaml

引用github.com/kubernetes/dashboard找到最新的版本号。在安装一般表后,接下来运行命令:

    $ kubectl proxy

该命令运行API服务器的本地代理,允许你通过代理访问服务。让代理进程允许,使用浏览器通过如下的URL,打开仪表板:

http://localhost:8001/api/v1/namespaces/kubernetesdashboard/services/https:kubernetes-dashboard:/proxy/

你将看到一个授权页面。然后你必须啊运行接下来的命令去获取授权码。

$ kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard
get secret | sls admin-user | ForEach-Object { $_ -Split '\s+' } | Select -First 1)

找到在kubernetes-dashboard-token-xyz下面的token,然后把token粘贴到浏览器的授权页面。当你做完之后,你应该能使用仪表板。当你使用完后,使用Control-C终止kubectl proxy进程.

访问在Minikube中的仪表板

如果你使用的是Minikube,访问仪表板更容器。运行如下的命令,仪表板将在你的默认浏览器中打开:

    $ minikube dashboard

访问允许在其他地方的Kubernetes的仪表板

Google Kubernetes引擎不在提供开源Kubernetes仪表板访问,但是它提供代替的基于web的控制台。其他云供应商也一行。更多如何访问仪表板的信息,请引用云供应商的文档。

    如果你的集群运行在你自己得基础设施上,你可以通过跟随引导kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard.

部署仪表板。

3.3 在Kubernetes上运行你的第一个应用程序

现在是时候在你得集群中部署以西东西了。通常,要部署应用程序,需要准备一个JSON或YAML文件,描述应用程序所包含的所有组件,并将该文件应用到集群。这就是声明式方法。

    因为可能是你第一次部署应用到kubernetes,让我们选择更容易的方式。我们使用简单,一行重要的命令去部署你的应用程序。

3.3.1 部署你的应用

命令式的方式使用kubectl create deployment命令部署应用。正如命令本身所暗示,它创建一个部署对象,该对象代表部署到集群中的应用程序。通过使用命令式命令,你不必像编写YAML或JSON清单时那样需要知道Deployment对象的结构。

创建一个部署

在前一章,你以及创建了一个Node.js应用程序,然后打包成容器镜像,为了容易发布到任意计算机把它推送到了Docker Hub。让我们把那个应用部署到你的Kubernetes集群。下面是你要执行的命令:

    $ kubectl create deployment kubia --image=luksa/kubia:1.0

你在这里指定了三件事情:

  • 创建一个deployment对象。
  • 对象名是kubia
  • 使用容器镜像luksa/kubia:1.0部署。

默认情况下,从Docker Hub拉取镜像,但是你也可以在镜像名字指定镜像注册中心(比如,quay/io/luksa/kubia:1.0).

注意 确保镜像存储在公共注册中心并且可以无授权拉取。在第八章,你将学习如何为拉取私有镜像提供身份证明。

部署对象现在存储在Kubernetes API中。这个对象告诉Kubernetes,luksa/kubia:1.0容器必须允许在你的集群中。你已经陈述了你想要的对象。现在Kubernetes必须确保实际状况反应你的愿望。

列出所有的部署

与Kubernetes交互主要包括通过API创建和操作对象。Kubernetes存储那些对象,然后执行操作将对象生效。比如,当你创建一个Deployment对象,Kubernetes运行一个应用程序。然后,Kubernetes通过将应用程序的状态写入相同的Deployment对象,让你了解应用程序的当前状态。你可以通过回读对象查看状态。一种获取状态的方式是如下列出所有Deloyment对象:

Kubectl get deployments命令列出集群中当前存在的所有Deployment对象。在你的集群中仅有一个Deployment。它运行你应用程序的一个实例,如UP-TO-DATE所示,但是AVAILABLE列表明应用还不可用。那是因为容器没有就绪,如READY列所示。你可以看见总共0个容器就绪。

    你可能奇怪,你是否可以通过运行kubectl get containers请求Kubernetes列出所有运行的容器。让我们试试。

命令失败由于Kubernetes没有Container对象类型。这可能看起来很奇怪,因为Kubernetes完全是关于运行容器的,但这里有一个转折。容器并不是Kubernetes中最小的部署单元。那最小部署单元是什么?

介绍PODS

在Kubernetes中,不是部署单个容器,你部署一组叫Pods的协同容器。你知道,就像一群鲸鱼,或者一个豌豆荚。

    一个pod是一组或多个紧密相关的容器,它们运行在同样的工作节点同时需要共享确定的linux命名空间,所有它们可以比其他pods进行更紧密的交互。

    在前一章,我展示了一个使用相同命名空间的两个进程。通过共享网络命名空间。两个进程使用同样的网卡。共享同一的IP和端口空间。通过共享UTS命名空间,它们看到同一的系统主机名。这就是在通用的pod中运行容器实际上发生的事情。它们使用同样的网络和UTS命名空间,以及其他命名空间,依赖pods的说明。

图3.8 容器,pods,工作节点之间的关系

如图3.8所示,你可以把pod想象成一个包含单个应用程序的隔离逻辑计算机。应用程序可以由运行一个容器的单进程组成,或者主应用程序在加上支持进程,每个在隔离的容器中运行。Pods分布在集群的所有工作节点上。

    每个pod由它自己的IP,主界面,进程,网卡和其他资源。同一pod上的容器认为它们是运行在计算机上的唯一容器。它们看不到任何其他pod的进程,即使它们在同一节点上。

列出PODS

因为容器部署Kubernetes的顶级对象,所有你不能列出它们,但是你可以列出pods。如下所示,通过创建Deployment对象,你已经部署了一个pod。

这个pod容纳了运行应用程序的容器。确切的讲,由于状态仍然是Pending,应用程序,或者更确切地说,容器还没有运行。如READY列中表示,这表明pod有一个未就绪的容器。

    Pod挂起的原因是因为赋给pod的工作节点在运行容器镜像之前必须先下载它。下载完成后,pod的容器被创建并且pod进入Running状态。

    如果Kubernetes不能从注册中心拉取镜像,kubectl get pods命令输出的STATUS列表明这一点。如果你使用你自己的镜像,确保它在Docker Hub标记为公共。尝试在另一台计算机上使用docker pull命令手动拉取映像。

    如果另一个问题导致pod不能运行,或者你只是想查看有关pod的更多信息,那么你还可以使用kubectl describe pod命令,就像你之前所做的那样,查看工作节点的详细信息。如果你的pod有任何问题,它们应该展示在该命令的输出中。查看底部输出的事件。对于一个正在运行的pod,它们应该有如下列表类似的输出。

理解幕后发生的事情

帮助你可视化创建部署时发生的情况,看图3.9

图3.9创建部署对象如何导致运行应用程序容器

当你运行kubectl create命令时,它通过向Kubernetes API服务器发送一个HTTP请求在集群中创建一个新的Deployment对象。然后Kubernetes创建一个新的Pod对象,随后pod对象被赋给或者调度到一个工作节点。在工作节点(Kubelet)上的Kubernetes代理意识到新创建的Pod对象,被调度到它所在的节点,并指示Docker从注册表中提取指定的镜像,从镜像创建容器,并执行它。

定义 术语调度指的是将pod分配给一个节点。Pod立刻运行,而不是在将来某个时间点运行。就像操作系统中的CPU调度器如何选择那个cpu运行进程一样,kubernetes的调度器决定每个容器应该执行在那个工作节点上。不像操作系统进程,一旦一个pod被赋给一个节点,它仅运行在那个节点上。即使它失败了,这个pod实例也不会像CPU进程那样移动到其他节点,但是可能会创建一个新的pod实例来替换它。

取决于你在Kubernetes集群中运行的是什么,你集群中的工作节点个数可能不同。上图仅展示被调度到的工作节点。在多节点集群中,该过程不涉及任何其他工作节点。

3.3.2 向世界公布你的应用程序

你的应用程序正在运行,接下来的问题是如何访问它。我提过每个pod有自己的IP地址,但是这个地址是外部不可访问的集群内部的地址。为了使pod从外部可以访问,你将通过创建Service对象公布它。

    有几种类型的Service对象。你决定需要哪个类型。一些仅在集群内暴露pods,其他的向外部暴露pods。一个有LoadBalancer类型的服务提供一个外部负载均衡器,其使得服务可以通过公网IP访问。这是我们现在要创建的服务类型。

创建服务

创建服务最容易的方式是使用如下的命令式命令:

$ kubectl expose deployment kubia --type=LoadBalancer --port 8080
service/kubia exposed

你之前运行create deployment命令创建了一个Deployment对象,而expose deployment命令创建一个Service对象。上述运行的命令告诉Kubernetes:

  • 你希望将属于kubia Deployment的所有pod作为新服务公开。
  • 你希望通过负载均衡器在集群外访问所有的pod
  • 应用侦听8080端口,你希望通过该端口访问应用。

你没有指定Service对象名称,因此它继承Deployment的名称

列出服务

Service是API对象,就像Pods,Deployments,Nodes和Kubernetes中的所有对象一样,因此你可以通过执行kubectl get services列出它们,如下列表所示.

注意 注意用svc缩写代替services。大部分资源类型都有代替对象全名的缩写名(比如, po是pods的缩写,no是nodes的缩写,deploy是deployments的缩写)。

列表显示现在有两种服务类型,分别是公开的IP和端口。现在忽视kubernetes服务,仔细看kubia服务。它还没有外部IP地址。能否获取IP地址取决于你如何在集群中部署它。

使用kubectl api资源列出可用的对象类型

你已经使用kubectl get命令列出集群中的各种东西:Nodes, Deployment, Pods与现在的服务。它们都是Kubernetes对象类型。你可以运行kubectl api资源展示所有支持的列表。同时列表显示每种类型的缩写名和你需要在JSON/YAML文件中定义的对象,你将在接下来的章节学习到。

-------------------------------------------------------------------------------

理解服务的负载均衡

虽然Kubernetes允许你创建LoadBalancer服务,但它本身没有提供负载均衡器。如果你的集群部署在云端,Kubernetes可以请求云基础设施提供与一个负载均衡器并且配置它将流量转发至你的机器。基础设施告诉Kubernetes负载均衡器的IP地址,这个IP地址变成你服务的外部地址。

    创建Service对象的过程,预置负载均衡器的过程,如何将连接转发至集群的过程如下图所示。

图3.10 如何用LoadBalancer类型创建一个Service对象

有时负载均衡器要消耗一些时间,所有让我们等待然后再次检查是否已经分配了IP地址。

这一次,不是列出所有的服务,你仅通过名称展示kubia服务,如下列表所示。

现在显示了waibuIP。这意味着负载均衡器已经准备好为全世界的客户端转发你的请求至你的应用。

    注意 如果你使用Docker Desktop部署你的集群,负载均衡器的IP地址显示的是localhost,引用Windows或macOS机器的地址,而不是Kubernetes和应用程序运行的虚拟机的IP地址。如果你使用Minikube创建集群,没有负载均衡器被创建,但是你可以通过另外一种方式访问服务。随后你将了解更多。

通过负载平衡器访问应用程序

现在你可以通过服务的外部IP和端口向你的应用程序发送请求:

注意 如果你使用Docker Desktop,这个服务在你主机操作系统过的local host:8080可用。

祝贺你!如果你使用Google Kubernetes引擎,你已经成功向全球用户发布了你的应用程序。任何知道IP和端口的人都可用访问它,如果你没有算上部署集群本身所需要的步骤,部署你的应用只需要2个简单的命令:

  • Kubectl create deployment和
  • Kubectl expose deployment.

当负载均衡器不可用的时候访问你的应用

并不是所有的Kubernetes集群都有提供负载均衡器的机制。Minikube是其中之一。如果你创建LoadBalancer类型的服务,服务本身生效,但是没有负载均衡器。Kubectl一直显示外部IP为<pending>,你必须用不同的方法访问服务。

    有几种访问服务的方法。你甚至可用绕过服务直接访问单个pods,但是这最常用于排错。你将在第五章学到怎么做。现在,让我们探索在没有负载平衡器可用的情况下访问服务的下一种更简单的方法。

    如下类比所示,Minikube可用告诉你去那里访问服务:

该命令打印服务的URL。现在你可用使用curl或你的浏览器通过URL访问你的应用程序:

建议 运行minikube service命令的适合,如果你省略—url选项,你的浏览器将打开加载服务URL

你可用好奇IP地址和端口从哪来的。这是运行Minikube虚拟机的IP地址。你可用通过执行minikube ip命令验证它。Minikube虚拟机也是你的工作节点。端口30838被称作节点端口号。它是将流量从工作节点转发到你的服务的端口。当你运行kubectl get svc命令时,你可能已经注意到在服务端口列表中的端口:


通过这个端口号可用访问你所有工作节点商的服务,忽略你使用的是Minikube或任意其他的Kubernetes集群。

注意 如果你使用Docker Desktop。运行Kubernetes的虚拟机无法从你的主机操作系统通过虚拟机的IP到达。只能在虚拟机内通过节点端口访问该服务,需要使用3.1.1节中介绍的专用容器登录虚拟机。

如果你至少知道一个工作节点的IP,你应该能通过IP:port组合访问服务,防火墙规则不会阻止你访问该端口。

    下图展示外部客户端如何通过节点端口访问应用程序。

图3.11 通过服务节点端口路由连接

将此与我之前提到的负载均衡器将连接转发到节点,然后节点将连接转发到容器的内容联系起来:节点端口正是负载均衡器发送传入请求的位置。然后Kubernetes确保转发请求至运行在容器中的应用程序。当我们在第10章深入研究服务时,您将了解它是如何做到这一点的。在那之前不要浪费太多时间思考它。相反,让我们对我们的集群进行更多的操作,看看Kubernetes还能做些什么。

3.3.3 水平扩展应用程序

现在你有一个用Deployment代表的正在运行的应用程序,并且已经通过Service把它发布给了全世界。现在让我们创建一些额外的魔法。

    在容器中运行应用的主要好处之一是你可用很容易的扩展你的应用部署。当前你运行应用程序的单个实例。想象你突然看到许多用户使用你的应用。单个实例再也无法处理负载。你需要运行额外的实例来分配负载并且向你的用户提供服务。这就叫扩展。使用Kubernetes很容易做到。

增加应用运行的实例个数

为了部署你的应用,你已经创建了一个Deployment对象。默认情况下,它运行应用程序的单个实例。运行其他的实例,你仅需要使用如下命令扩展Deployment对象:

    $kubectl scale deployment kubia –replicas=3

    Deployment.apps/kubia scaled

现在你告诉Kubernetes你希望运行pod的3个实际拷贝或副本。注意你没有告诉Kubernetes做什么。你也没有告诉它多增加两个pods。你仅设置期望的新的副本数,让Kubernetes决定它要做什么才能达到新的期望状态。

    这是Kubernetes最基本的原则之一。不是告诉Kubernetes做什么,你简单给系统设置一个新的期望状态,然后让Kubernetes去实现它。为了达到木朵,它检查当前状态,与期望状态做比较,识别不同然后决定该怎么做才能让它们达到一致状态。

查看扩展的结构

虽然kubectl scale deployment命令看起来的却是命令式的,因为它显式的告诉Kubernetes扩展你的应用程序,但该命令实际做的是修改了指定的Deployment对象。在后续章节你将看到,你可用简单编辑对象而不是给出命令式命令,让我们再次查看Deployment对象,看scale命令是如何影响它的:

现在生效了3个可用实例,3个容器已就绪。命令的输出并不是台清晰,因为三个容器不是同一pod实例的一部分。三个pods,每个有一个容器。你可用通过列出pods做验证:

你可用看到,现在又三个pods。如READY列所示,每个有一个容器,并且所有的容器已就绪。所有的pods在运行状态。

在列出PODs时显示pods的主机节点

如果你用单节点集群,所有的pods运行在同一节点上。但是在多节点集群,三个节点应该分布在集群中。查看pod被调度到那些节点,你可用使用-o wide选项展示pod列表的更多细节:

    注意 当列出其他对象类型的适合,你也可用使用-o wide输出选项看额外的信息。

宽输出显示一个pod被调度到一个节点,而另外两个pod都被调度到不同的节点。调度器一般分布pods偶数,但是这也依赖于它的配置。你将在第21章学习更多的调度器知识.

理解为什么一个pod被调度到指定工作节点的原因并不重要

忽略pod运行的节点,你应用程序的所有实例都有同样的操作系统环境,因为它们运行有同一个容器镜像创建来的容器。你可能记得前一章,仅有的不同可能是操作系统内核的不同,但仅当不同的节点用不同的内核版本或加载不同的内核模块才发生。

此外,每个pod获得自己的IP,可以用同一种方式于其他pod通信-不管其他节点是不是在同样的工作节点,另外一个节点是不是在同一个服务器机架上,或甚至在完全不同的数据中心。

迄今为止,你还没有设置pods的资源需求,但是如果你设置了,每个pod将被分配请求的计算机资源数。只要满足pod的资源需求,是哪个节点为pod提供的资源不应该是问题。

因此,你不应该关心哪个pod被调度到。这也是为什么默认的kubectl get pods命令为pods列表展示关于工作节点的信息。在Kubernetes的世界,这不重要。

-------------------------------------------------------------------------------

如你所见,扩展应用程序相当容易。一旦你的应用在生产环境,应用需要扩展,你可以用一条命令添加额外的实例,不用看安装,配置与运行额外的拷贝手册。

注意 app本身必须支持水平扩展。Kubernetes没有魔法使你的app变得可扩展;它只是让复制它变得微不足道。

当使用服务的时候观测3个节点的请求命中率

现在应用程序的多个实例正在运行,让我们看看当你再次点击服务URL发生了什么。是否每次的响应来自于同一个节点?如下列表显示发生了什么。

如果你仔细看响应,你将看到相应于pods的名称。每个请求以随机的顺序到达不同的pod。这就是当服务背后有不止一个pod实例,kubernetes中服务所做的事情。

图3.12相同服务后面跨多个pod之间的负载均衡

    如图所示,你不应该混淆负载均衡机制,它有Kubernetes服务本身提供,当使用GKE或其他云供应商运行集群时,额外的负载均衡器由基础设施提供。即使你使用Minikube,没有额外的负载均衡器,你的请求还是通过服务本身分布在三个pod上。如果你使用GKE,实际上有两份负载均衡器在起作用。图中显示基础设施提供的负载平衡器跨节点分发请求,然后服务跨pod分发请求。

    我知道现在你可能非常混乱,但是在第十章所有的都应该变清晰。

3.3.4 理解已部署的应用程序

结束本章,让我们回顾你的系统由什么组成。由两种视角看你的系统-逻辑视角和物理视角。在3.12机仅仅看了物理视角。在三个工作节点上运行着三个容器(当使用Minikube是单个)。如果你在云上运行Kubernetes,云基础设施也为你创建了一个负载均衡器。Docker Desktop也创建本地类型的负载均衡器。Minikube没有创建负载均衡器,但是你可以通过节点端口直接访问服务。

    在不同的集群中,系统的物理视图存在差异,逻辑视角一直是一样的,无论你使用一个小的开发集群或一个有几千个节点的大的生产环境的集群。如果你不是管理集群的人,你甚至都不需要操心集群的物理视图。如果一切如期望般工作,逻辑视图是你仅需关心的事情。让我们仔细看逻辑视图。

理解代表你应用的API对象

逻辑视图由你通过Kubernetes API创建的对象组成-直接创建或间接创建。下图展示了对象之间的关系。

图3.13 部署的应用由Deployment,几个pods,一个服务组成.

对象如下:

  • 你创建的Deployment对象,
  • 基于Deployment自动创建的pod对象,
  • 你手动创建的Service对象

除了刚才提到的三个对象,还有其他对象,但是你根本不需要知道它们。你将在后续章节学到它们。

    还记不记得我第一章解释的Kubernetes抽象了基础设施?你应用程序的逻辑视图是一个很好的例子。这里没有节点,没有复杂的网络拓扑,没有物理负载均衡器。仅有一个包含你的应用程序与支持对象的简单视图。让我们看看这些对象是如何组合在一起的,以及它们在您的小型设置中扮演什么角色。

    Deployment对象代表一个应用程序的部署。它指定你的应用包含哪个镜像容器,Kubernetes应该运行多少个副本。Service对象代表那些副本的单个通信进入点。

理解PODS

你的系统本质和最重要的部分是pods。每个pod定义包含一个或多个组成pod的容器。当Kubernetes使一个pod生效,它运行所有的在定义中指定的容器。只要Pod对象存在,Kubernetes将尽最大努力确保容器保持运行。Kubernetes仅当Pod对象被删除的时候关闭容器。

理解Deleployment的角色

当你第一次创建Deployment对象时,仅有单个Pod对象被创建。但是当你在Deployment上增加期望的副本数时,Kubernetes创建额外的副本。Kubernetes确保pods的数量一致匹配期望的数量。

    如果你一个或多个pods消失,或状态未知,Kubernetes用新的pod替代它们,从而使pod数量回到期望的数量。当有人或其他东西删除pod时,pod消失,因为pod的状态不可知,当pod运行的节点由于网络或节点失败不再报告pod的状态。

    严格的讲,一个Deployment的结果仅仅是创建指定数量的pod对象。你可能好奇你是否可以跳过创建Deployment对象而直接创建pods。当然可以这样做,但是如果你向运行多个副本,你必须手动创建每一个pod并且确保你给每个pod取了唯一的名字。然后你也必须一致看着pods,当pods突然消失或它们的运行的节点失败时替换pods。这就是为什么你从来不直接创建pod而是使用Deployment。

理解为什么需要服务

系统的第三个组件是Service对象。通过创建Service对象,你告诉Kubernetes你需要为你的pods指定单个通信进入点。这个服务给你单个IP地址与你的pods通信。忽略当前部署了多少个副本。如果服务后面有多个pods,服务半夜负载均衡器的角色。即使只有一个节点,你也系统通过服务公开它。理解为什么,你需要学习pods的更多重要的斜街。

    Pod是短暂的。一个pod可能在任何时间消失。这可能发生在,主机节点失败,有人不经意上次pod,或pod从一个要为更重要的pod挪出空间的健康的节点中驱逐。如上一节解释的那样,当通过Deployment创建pods,消失的pod立马被一个新的pod替代。这个新pod与它要替代的pod不一样。它是一个有新IP的,完全新的pod。

    如果你没有使用service,已配置你的客户端直连原始pod的IP,你需要重新配置所有的客户端连接到新的pod。当使用服务时就不需要这样做。不像pods,服务部署短暂的。当你创建一个服务,它被赋予一个静态IP,这个IP在它的生命周期内都不会改变。

    不是直接连接到pod,客户端应该连接服务的IP。这确保客户端的连接一直路由到健康的pod,即使服务后面的pod一直改变。如果您决定横向扩展部署,它还可以确保负载均匀地分布在所有pod上。

3.4 总结

在动手实践的一章中,你学到了:

  • 几乎所有的云供应商都提供了Kubernetes管理选择。当你使用kubernetes API部署你的应用的时候,它们从你肩上接过你自己维护Kubernetes的负担。
  • 你也可以在你自己的云上安装Kubernetes,但是这被证明在你精通管理Kubernetes的各个方面之前,不是一个好注意。
  • 你可以在本地安装Kubernetes,甚至在你的笔记本上,使用如Docker Desktop或者Minikube之类的工具,这些工具在Linux虚拟机中运行Kubernetes,它们运行主节点和工作节点作为Docker容器同时在这些容器内部运行应用程序容器。
  • 命令行工具kubectl,是与Kubernetes交互的常用方式。也有一个基于web的仪表板,但不像CLI工具那样稳定和实时。
  • 为了更快的使用kubectl,为了更快地使用kubectl,为它定义一个短别名并启用shell完成是很有用的。
  • 应用程序可以使用kubectl create deployment部署。然后通过kubectl expose deployment向客户端公开应用程序。水平扩展应用程序是微不足道的:kubectl scale deployment命令kubernetes增加新副本或删除已存在的副本,使副本达到你指定的副本数。
  • 部署的基本单元部署容器,而是pod,它可以包含一个或许多个相关的容器。
  • 部署,服务,pods和节点是Kubernetes的对象或资源。你可以用kubectl get命令列出它们,也可以使用kubectl describe命令观察它们。
  • Deployment对象部署相应的pods数量,而Service对象使得它们可以通过单个稳定的ip访问。
  • 在集群中的每个服务提供内部的负载均衡器,但是如果你设置LoadBalance类型的服务,Kubernetes将请求云基础设施为它提供一个额外的负载均衡器,使你的应用在公共地址可用。

现在你已经完成了你的第一次海湾导游之旅。现在是时候开始学习诀窍了,这样你就能独立航行了。书的下一部分聚焦Kubernetes对象的区别以及如何/什么时候使用它们。你将从最重要的Pod开始。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐