Skip to content

Files

Latest commit

3ac63cb · Dec 27, 2021

History

History
412 lines (285 loc) · 24.9 KB

File metadata and controls

412 lines (285 loc) · 24.9 KB

五、使用 Kubernetes 协调微服务

在本章中,我们将讨论 Kubernetes 背后的基本概念,Kubernetes 是一种工具,允许您管理多个容器并协调它们,从而使已经部署在每个容器上的微服务协调工作。

本章将介绍什么是容器编排器以及特定的 Kubernetes 命名法,例如 pod、服务、部署之间的区别,等等。我们还将学习如何分析正在运行的集群并执行其他常见操作,以便您可以将它们应用到我们的微服务示例中。

在本章中,我们将涵盖以下主题:

  • 定义 Kubernetes 编排器
  • 了解不同的 Kubernetes 元素
  • 使用 kubectl 执行基本操作
  • 正在运行的群集的故障排除

到本章结束时,您将了解 Kubernetes 的基本元素,并能够执行基本操作。您还将学习基本的故障排除技能,以便发现可能的问题。

技术要求

如果您使用的是 macOS 或 Windows,默认的 Docker 桌面安装可以启动本地 Kubernetes 集群。只需确保在 Kubernetes 的首选项中启用此功能:

对于 Linux,在本地安装 Kubernetes 最简单的方法是使用 k3s(https://k3s.io/)。

k3s is a nod to Kubernetes (that is, k8s) but is a simplified version of it.

k3s 是 Kubernetes 的极简安装,可以用来运行包含在单个二进制文件中的集群。如果您希望下载并运行安装页面(https://github.com/rancher/k3s/blob/master/README.md)请查看。

为了能够使用 k3s 集群内部运行的 Docker 版本,我们需要使用以下代码:

$ # Install k3s
$ curl -sfL https://get.k3s.io | sh -
$ # Restart k3s in docker mode
$ sudo systemctl edit --full k3s.service
# Replace `ExecStart=/usr/local/bin/k3s` with `ExecStart=/usr/local/bin/k3s server --docker`
$ sudo systemctl daemon-reload
$ sudo systemctl restart k3s
$ sudo systemctl enable k3s
$ # Allow access outside of root to KUBECTL config
$ sudo chmod 644 /etc/rancher/k3s/k3s.yaml
$ # Add your user to the docker group, to be able to run docker commands
$ # You may need to log out and log in again for the group to take effect
$ sudo usermod -a -G docker $USER

确保您安装了kubectl(默认情况下 k3s 会安装一个单独的版本)。安装kubectl的步骤可以在https://kubernetes.io/docs/tasks/tools/install-kubectl/找到。kubectl司令部控制 Kubernetes 斯的行动。

Check the instructions on the aforementioned page to add Bash completion, which will allow us to hit Tab to complete some commands.

如果一切都已正确安装,您应该能够使用以下命令检查运行中的吊舱:

$ kubectl get pods --all-namespaces
NAMESPACE NAME                                         READY STATUS  RESTARTS AGE
docker    compose-89fb656cf-cw7bb                      1/1   Running 0        1m
docker    compose-api-64d7d9c945-p98r2                 1/1   Running 0        1m
kube-system etcd-docker-for-desktop                    1/1   Running 0        260d
kube-system kube-apiserver-docker-for-desktop          1/1   Running 0        2m
kube-system kube-controller-manager-docker-for-desktop 1/1   Running 0        2m
kube-system kube-dns-86f4d74b45-cgpsj                  3/3   Running 1        260d
kube-system kube-proxy-rm82n                           1/1   Running 0        2m
kube-system kube-scheduler-docker-for-desktop          1/1   Running 0        2m
kube-system kubernetes-dashboard-7b9c7bc8c9-hzpkj      1/1   Running 1        260d

请注意不同的名称空间。它们都是默认的,由 Kubernetes 自己创建。

转到以下页面安装 Ingress 控制器:https://github . com/kubernetes/Ingress-nginx/blob/master/docs/deploy/index . MD。在 Docker 桌面中,您需要运行这两个命令:

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/cloud-generic.yaml

这将创建一个带有控制器盒的ingress-nginx名称空间。Kubernetes 将使用该吊舱来设置入口配置。

现在,让我们看看使用 Kubernetes 的优势。

定义 Kubernetes 编排器

Kubernetes 是一个流行的容器编排工具。它允许我们以协调的方式管理和部署多个相互交互的容器。由于每个微服务都存在于一个单独的容器中,正如我们在第 1 章行动起来——设计、计划和执行中提到的,它们可以协同工作。

For a more in-depth introduction to Kubernetes, you can check out the following comic, which was released by Scott McCloud: https://cloud.google.com/kubernetes-engine/kubernetes-comic/.

Kubernetes 的目标是生产系统。它旨在能够控制大规模部署,并抽象出基础架构的大部分细节。Kubernetes 集群中的每个元素都是以编程方式配置的,Kubernetes 本身根据可用的容量来管理在哪里部署集群。

Kubernetes 可以完全使用配置文件进行配置。这使得复制集群成为可能,例如,在导致所有物理服务器停机的完全灾难的情况下。您甚至可以使用不同的硬件来实现这一点,而传统的部署可能非常困难。

This example assumes that the data is stored and retrievable; for example, in a backup device. Obviously, this may be difficult—disaster recovery always is. However, it simplifies a lot of the steps that are required if you wish to replicate a cluster.

考虑到 Kubernetes 与容器一起工作,并且非常容易安装它们,有一个大的容器生态系统准备向 Kubernetes 本身添加功能。最好的例子可能是 kubernetes 仪表板(https://Kubernetes . io/docs/tasks/access-application-cluster/web-ui-dashboard/),这是一个显示 Kubernetes 操作概述的 UI。默认情况下不会安装,但是可以用安装服务的相同方式安装。此类用例的其他示例包括监控和日志记录。这使得 Kubernetes 非常具有可扩展性。

与 DockerSwarm 的对比

Kubernetes 不是唯一可用的编排器。正如我们在第 3 章使用 Docker 构建、运行和测试您的服务时所提到的,有docker-compose。Docker Compose 还可以编排不同的容器并协调它们,但这样做并不需要处理多个服务器。

Docker 有一个名为 Docker Swarm 的原生扩展docker-compose。这允许我们使用一组机器来运行docker-compose,同时重用相同的 YAML 文件,但是增加了一些细节来描述您希望它们如何运行。

You can learn more about Docker Swarm in the official documentation (https://docs.docker.com/engine/swarm/).

Docker Swarm 比 Kubernetes 更容易设置,假设您必须管理服务器。当您扩展 Docker Compose 的功能时,您会发现它的学习曲线很低。

另一方面,Kubernetes 的功能更强大,更可定制。它有一个更大的社区和更高的创新速度。它也更擅长处理问题。最大的问题是建立集群,但正如我们将在第 7 章中看到的,配置和保护生产系统如今,我们可以使用简单的商业部署在几分钟内创建一个集群,这降低了 Kubernetes 的进入壁垒。

当您处理从旧系统迁移和展望未来时,这使得 Kubernetes(可以说)成为更好的解决方案。对于小型部署,或者如果您需要部署和管理自己的服务器,Docker Swarm 可能是一个有趣的替代方案。

To help you move on from using a docker-compose.yaml file to using the equivalent Kubernetes YAML files, you can use kompose (https://github.com/kubernetes/kompose). It may be useful to quickly start a Kubernetes cluster and translate the services described in the docker-compose.yaml file into their equivalent Kubernetes elements, but there are always differences between both systems that may need to be tweaked.

让我们从描述 Kubernetes 的具体元素和命名开始。

了解不同的 Kubernetes 元素

Kubernetes 对不同的元素有自己的命名。我们将在本书中经常使用术语,Kubernetes 文档也使用它们。了解它们之间的差异很重要,因为有些差异可能很微妙。

节点

Kubernetes 的主要基础设施元素被称为节点。Kubernetes 集群由一个或多个节点组成,这些节点是支持其余元素抽象的物理机(或虚拟机)。

每个节点都需要能够与其他节点通信,并且它们都在一个容器运行时中运行——通常是Docker——但是它们可以使用其他系统,例如rktlet(https://github.com/kubernetes-incubator/rktlet)。

这些节点在它们之间创建了一个网络,该网络路由所有发往集群的请求,以便发送到集群中任何节点的任何请求都能得到充分响应。Kubernetes 将处理什么可部署到什么节点,甚至在节点宕机时恢复节点,或者在出现资源问题时将节点从一个节点移动到另一个节点。

节点不一定需要完全相同,在特定节点中部署特定元素时需要一定程度的控制,但是为了简单起见,它们通常是完全相同的。

虽然节点是支持集群的主干,但是 Kubernetes 通过定义期望的结果和让 Kubernetes 决定什么去哪里以及确保内部网络通道的请求被发送到适当的服务来帮助抽象出特定的节点。

立方控制平面

Kubernetes 控制平面是 Kubernetes 用来将一组服务器正确配置为 Kubernetes 集群中的节点的所有进程的地方。服务器允许节点相互连接,允许我们监控它们的当前状态,并允许我们在部署、规模等方面进行任何必要的更改。

负责注册和进行这些更改的节点称为主节点。可以有多个主节点。

所有这些控制通常在幕后顺利进行。它的网络与其他网络是分离的,这意味着这个级别的问题不会影响集群的当前运行,除了我们无法进行更改。

永恒的物体

Kubernetes 对象是表示部署在集群中的服务状态的抽象。主要是,它们处理运行的容器和这些容器的路由,以及持久存储。

让我们看看不同的元素,从最小到最大。这份清单并非详尽无遗;有关更多详细信息,请查看 Kubernetes 文档:

  • 容器:单个 Docker 容器。这些是 Kubernetes 的构件,但它们从来不会单独出现。
  • **吊舱:**可以部署在 Kubernetes 斯的基本单位。pod 是一个或多个容器的集合,它们作为一个单元工作,通常来自不同的映像。通常情况下,一个豆荚只有一个容器,但有时拥有更多可能会有用。同一 pod 中的所有容器共享相同的 IP 地址(pod IP),这意味着访问localhost中端口的容器可能正在访问不同的容器。这其实是推荐的和他们沟通的方式。

This will all be a bit strange to you at first, but normally, multi-container pods will have a main container and something else that performs auxiliary tasks, such as exporting metrics.

  • 配置图:这定义了一组可以注入 pods 的键值对,通常作为环境变量或文件。这允许我们在不同定义的容器之间共享配置,例如,让所有容器记录调试信息。请注意,面板可以有自己的配置,但是配置映射是共享相同值的一种方便方式,这样它们就可以用于不同的面板。
  • :容器中的文件是短暂的,如果容器停止执行,这些文件将会丢失。卷是一种持久存储形式,可用于在启动之间维护数据信息,并在容器之间共享信息。

As a general principle, try to have as few volumes as possible. Most of your applications should be stateless anyway, and any variable data should be stored in a database. If containers in the same pod need to communicate, it is better to do so through HTTP requests. Remember that any immutable data, such as static files, can be stored inside the container image.

  • 部署:这是一组一个或多个相同的吊舱。根据定义的策略,部署的定义将说明所需的数量,Kubernetes 将努力实现这一点。单个部署中的单元可以部署到不同的节点,通常情况下也是如此。如果其中任何一个单元被删除、完成或出现任何问题,部署将开始另一个,直到达到定义的数量。
  • 作业:一个作业创建一个或多个预计完成的荚。虽然部署会假设任何正在完成的 pod 都有问题,并将启动另一个 pod,但作业会重试,直到达到适当的成功次数。完成的豆荚不会被删除,这意味着我们可以查看它们的日志。工作是一次性的。还有 Cron Jobs ,会在特定时间运行。
  • 服务。由于 pods 被创建和重新创建,并且具有不同的 IP,为了允许服务访问它们,服务需要定义其他元素可以用来发现它的名称。换句话说,它将请求路由到合适的吊舱。通常,一个服务和一个部署是相关的,服务使得部署在所有定义的单元之间是可访问的和循环的。服务也可以用于为外部服务创建内部名称。

Services in Kubernetes solve an old problem in distributed systems, that is, service discovery. This problem occurs when nodes in a cluster need to know where a service lives, even if the nodes change; that is, when we add a node or remove it without changing the configuration settings of all the nodes.

Kubernetes will do this automatically if you create a service.

  • 入口:服务是内部的,入口是外部的。它将任何外部请求路由到适当的服务,以便它们可以被服务。您可以通过主机名定义不同的入口,这可以确保请求的目标主机将集群路由到不同的服务,或者根据路径托管单个入口。在内部,入口被实现为实现入口控制器的容器,默认情况下是nginx

Depending on your Kubernetes installation, you may need to install the default controller. To install the default controller, follow the instructions at https://github.com/kubernetes/ingress-nginx/blob/master/docs/deploy/index.md.

  • 命名空间:这是虚拟集群的定义。您可以在同一个物理 Kubernetes 集群中定义多个命名空间。在一个名称空间下定义的每个名称都需要是唯一的,但是另一个名称空间可以使用相同的定义。不同命名空间中的对象不能在内部相互通信,但它们可以在外部进行通信。

Generating different namespaces with very similar definitions can be useful if you wish to create different environments for purposes, such as testing, development, or demo concepts. The main advantage of Kubernetes is that you can replicate a whole system and take advantage of this to create similar environments with small changes in terms of details, such as a new version of an environment.

对象可以在.yaml文件中找到,可以加载到系统中。单个.yaml文件可以定义多个对象,例如,定义包含容器的容器的部署。

下图总结了可用的不同对象:

作业和卷不存在,但有两种服务可用:一种指向部署,另一种指向外部服务。外部服务是针对内部元素的,不会暴露在外部。

使用 kubectl 执行基本操作

通过使用kubectl,我们可以对所有不同的元素执行操作。我们已经对get进行了一次预检,以了解有哪些元素可用。

For more information and a quick overview of the most common operations that are available within kubectl, check out the kubectl cheat sheet at https://kubernetes.io/docs/reference/kubectl/cheatsheet/.

我们可以用kubectlcreate一个新元素。例如,要创建和列出名称空间,我们可以使用以下代码:

$ kubectl create namespace example
namespace/example created
$ kubectl get namespaces
NAME        STATUS AGE
default     Active 260d
docker      Active 260d
example     Active 9s
kube-public Active 260d
kube-system Active 260d

我们可以创造各种元素,其中一些我们会在整本书中看到。

定义元素

命名空间是一种特殊情况,因为它不需要任何配置。要创建新元素,需要创建描述该元素的 YAML 文件。例如,我们可以使用 Docker Hub 中的官方 NGINX 映像创建一个新的 pod:

---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: example
spec:
  containers:
    - name: nginx
      image: library/nginx:latest

至少,元素应包含以下内容:

  • 元素的应用编程接口版本。
  • 元素的类型。
  • 元素的名称及其命名空间。
  • 包含配置详细信息的spec部分。对于豆荚,我们需要添加必要的容器。

YAML files can be a bit temperamental sometimes, especially when it comes to indentation and syntax. You can use a tool such as Kubeval (https://kubeval.instrumenta.dev/) to check that the file is correct and that you're following Kubernetes good practices before using a file.

我们将此文件保存为example_pod.yml。我们将使用apply命令创建它,并使用以下命令监控它的运行:

$ kubectl apply -f example_pod.yml
pod/nginx created
$ kubectl get pods -n example
NAME  READY STATUS            RESTARTS AGE
nginx 0/1   ContainerCreating 0        2s
$ kubectl get pods -n example
NAME  READY STATUS  RESTARTS AGE
nginx 1/1   Running 0        51s

Note the usage of the -n parameter to determine the namespace.

我们现在可以exec进入容器,并在里面运行命令。例如,要检查 NGINX 服务器是否正在运行并提供文件,我们可以使用以下代码:

$ kubectl exec -it nginx -n example /bin/bash
root@nginx:/# apt-get update
...
root@nginx:/# apt-get install -y curl
...
root@nginx:/# curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

豆荚有两种变化。第一种方法是手动运行edit,这将打开您预定义的终端编辑器,以便您可以编辑文件:

$ kubectl edit pod nginx -n example

您将看到带有所有默认参数的 pod。这种改变 pod 的方式对小测试很有用,但是一般来说,最好改变原始的 YAML 文件,这样你就可以跟踪发生的变化。例如,我们可以更改 NGINX,使其使用以前的版本:

---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: example
spec:
  containers:
    - name: nginx
      image: library/nginx:1.16

然后,我们可以再次apply这些变化,这将重新启动吊舱:

$ kubectl apply -f example_pod.yml
pod/nginx configured
$ kubectl get pods -n example
NAME  READY STATUS  RESTARTS AGE
nginx 1/1   Running 1        36s

获取更多信息

get命令接受更多配置。您可以使用wide输出选项检索更多信息:

$ kubectl get pods -n example -o wide
NAME  READY STATUS  RESTARTS AGE IP        NODE
nginx 1/1   Running 1        30m 10.1.0.11 docker-for-desktop

如果你做了一个改变并且对这个改变感兴趣,你可以使用-w参数来观察任何改变。例如,下面的代码显示了 pod 的重启结果。由于对容器的映像进行了更改,导致重新启动:

$ kubectl get pods -n example -w
NAME  READY STATUS  RESTARTS AGE
nginx 1/1   Running 2        32m
nginx 1/1   Running 3        32m

如果您需要关于特定元素的更多信息,您可以describe它:

$ kubectl describe pod nginx -n example
Name: nginx
Namespace: example
Node: docker-for-desktop/192.168.65.3
Start Time: Sun, 23 Jun 2019 20:56:23 +0100
Labels: <none>
Annotations: ...
Status: Running
IP: 10.1.0.11
...
Events:
 Type Reason Age From Message
 ---- ------ ---- ---- -------
 Normal Scheduled 40m default-scheduler Successfully assigned nginx to docker-for-desktop
 ...
 Normal Created 4m43s (x5 over 40m) kubelet, docker-for-desktop Created container
 Normal Started 4m43s (x5 over 40m) kubelet, docker-for-desktop Started container

这返回了很多信息。最有用的信息通常是关于事件的,它将返回关于元素生命周期的信息。

移除元素

delete命令删除一个元素及其下的所有内容:

$ kubectl delete namespace example
namespace "example" deleted
$ kubectl get pods -n example
No resources found.

请注意,有时删除一个元素会导致它被重新创建。这在通过部署创建 pods 时非常常见,因为部署将使 pods 的数量达到配置的数量。

正在运行的群集的故障排除

在 Kubernetes 中,我们可以用来解决问题的主要工具是getdescribe命令。

根据我的经验,运行 Kubernetes 最常见的问题是,有时,某些豆荚无法启动。故障排除的步骤如下:

  1. 容器映像是否正确?下载映像出现问题将显示ErrImagePull。如果由于认证问题而无法从注册表下载映像,可能会导致这种情况。
  2. CrashLoopBackOff状态表示容器的处理已经中断。吊舱会一遍又一遍地尝试重启。这通常是由容器的潜在问题引起的。检查配置是否正确。您可以使用以下命令检查容器的stdout日志:
$ kubectl logs <pod> -n <namespace> -c <container>

确保容器是可运行的。尝试使用以下命令手动运行它:

$ docker run <image>
  1. 豆荚不会暴露在外面。这通常是由于暴露它们的服务和/或入口中的问题。您可以使用exec进入另一个容器,然后尝试访问服务和 pod 的内部 IP,通常使用curl来检测 pod 在集群内部是否有响应。

As we saw previously, curl is not installed in containers by default because, normally, they only install a minimal set of tools. Don't worry—you can install it using whatever package manager your operating system uses, with the advantage that, once the container is recycled (which will happen soon enough in a normal Kubernetes operation), it won't be using up any space! For the same reason, you may need to install it each time you need to debug a problem.

请记住我们讨论的入口、服务、部署和单元的链条,从内到外找出配置错误的地方。

排除故障时,请记住,可以通过exec命令访问吊舱和容器,这将允许我们检查正在运行的进程、文件等。这类似于访问物理服务器的终端。您可以使用以下代码来实现这一点:

$ kubectl exec -it <pod> -n <namespace> /bin/sh

要小心,因为 Kubernetes 集群的性质可能要求您检查一个容器中的特定容器,如果有多个容器在同一个容器中运行。

摘要

在本章中,我们研究了 Kubernetes 的基本概念,以及管理和协调包含我们的微服务的多个容器是多么有用。

首先,我们介绍了什么是 Kubernetes 以及它的一些高级优势。然后,我们描述了在 Kubernetes 命名法中定义集群的不同元素。这既包括物理方面(其中节点是主要的定义元素),也包括抽象方面(例如吊舱、部署、服务和入口),它们是我们生成工作集群所需的构建块。

我们描述了kubectl以及我们可以用来定义元素和通过 YAML 文件检索信息的常见操作。我们还描述了处理 Kubernetes 集群时可能出现的一些常见问题。

在下一章中,我们将定义可以在 YAML 文件中使用的不同选项,以便生成集群,并学习如何为我们的微服务示例生成 Kubernetes 集群。

问题

  1. 什么是容器编排器?
  2. 在 Kubernetes 中,什么是节点?
  3. 豆荚和容器有什么区别?
  4. 工作和豆荚有什么区别?
  5. 我们应该何时添加入口?
  6. 什么是命名空间?
  7. 我们如何在文件中定义一个 Kubernetes 元素?
  8. kubectlgetdescribe命令有什么区别?
  9. CrashLoopBackOff错误表示什么?

进一步阅读

您可以通过阅读Kubernetes 入门-第三版(https://www . packtpub . com/eu/虚拟化与云/入门-Kubernetes-第三版)和完整的 Kubernetes 指南(https://www . packtpub . com/eu/虚拟化与云/完整-Kubernetes-指南)了解更多关于 Kubernetes 的信息。