Kubernetes in Action 笔记 —— Kubernetes 介绍

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kubernetes in Action 笔记 —— Kubernetes 介绍相关的知识,希望对你有一定的参考价值。

参考技术A

Kubernetes 这个名字来自于希腊语,意思是舵手。还是很符合这个平台的作用的。Kubernetes 负责管理部署的应用并报告它们的情况,而用户就像是船长,只需要决定想要整个系统达到怎样的状态。

Kubernetes 是一个负责自动化部署和管理应用的软件系统,主要针对由容器构成的复杂的大型应用系统

抽象化基础设施

Kubernetes 为用户和应用在底层的硬件之上提供了一个抽象层,底层的基础设施如计算机、网络及其他组件等对应用都是不可见的。用户通过这个抽象层部署和管理应用,不需要再面对每一台特定的机器。因此配置起来更加方便。

标准化部署
由于底层基础设施的具体细节不会再影响到应用的部署,本地数据中心和云环境都可以使用同样的部署方式。任何底层基础设施的差异都交给 Kubernetes 去处理,用户可以只关注产品及其内部逻辑。

声明式部署
Kubernetes 使用声明式的模型来定义具体的应用。用户只需要完成对应用中各组件的描述,Kubernetes 就会将这些描述转化成运行的应用。并在之后保证该应用的健康运行,在必要的时候重启或重新创建某个组件。

当用户修改了某些描述,Kubernetes 会根据改动自动采取必要的步骤重新配置应用,令应用满足最新的描述。

接管应用的日常管理
一旦用户通过 Kubernetes 部署了某个应用,该应用的日常管理就会被 Kubernetes 接管。假如服务停止运行,Kubernetes 会自动重启该应用;或者由于硬件失效、基础设施架构调整导致该应用需要移动到其他机器上,Kubernetes 也会自行处理。

就像之前提到的,用户类似于船长负责更高层级的决策,而 Kubernetes 则类似于舵手负责执行具体的底层任务。

之前的年头,绝大多数应用都是单体应用。应用里的各个组件是强耦合的,全部运行在同一个进程里。
当应用的容量需要提升时,水平扩展单体应用是非常困难的。只能不断升级服务器的硬件,即垂直扩展。

微服务范式是后来才出现的。单体应用被分割成数十甚至数百个独立的进程(微服务)。每一个微服务都拥有自己所独有的开发和部署周期,不同微服务的依赖会随着时间的推移差距越来越大。这使得在同一个操作系统内部运行两个微服务应用变得非常困难。
容器正好方便解决这个问题。但每个微服务都是一个独立的应用,需要单独进行管理。随着应用数量的上升这将会越来越困难。
整个应用系统的各个部分不需要部署到同一台机器上,这使得扩展起来更加方便。但同时也意味着各组件之间需要配置成能够相互通信的状态。同样增加了维护成本。
因此当微服务的规模变得很大时,自动化管理就显得尤为必要。Kubernetes 则正好提供了这种自动化功能。

Kubernetes 可以看作是一个面向服务器集群的操作系统。
操作系统用来支撑计算机的基本功能比如 CPU 调度,作为应用和计算机硬件之间沟通的接口。类似的,Kubernetes 负责在服务器集群的各台机器上调度安排分布式应用的各个组件,作为应用和集群之间的接口。

一个 Kubernetes 集群包含两组节点:

Control Plane 负责控制整个集群。它运行在一台主节点上,或者以副本的方式运行在多个主节点上。包含 Scheduler、Controllers、Kubernetes API Server、etcd 等几个组件。

工作节点就是实际上运行应用的节点,它们构成了 Workload Plane。负责运行、监控各个应用,并在各应用之间提供连通性。

其中各组件的功能如下:

Kubernetes 中的所有元素都由对象表示,可以通过 API 创建和获取这些对象。用户需要几种不同的对象来定义自己的应用,通常在 YAML 或 JSON 格式的清单文件中定义。

向 Kubernetes 部署应用的具体步骤为:

Kubernetes in Action, Second Edition

Kubernetes in Action 3 pod:运行于Kubernetes中的容器

目录

(1)Kubernetes In Action 1:Kubernetes介绍

(2)Kubernetes In Action 2:开始使用Kubernetes和Docker

(3)Kubernetes in Action 3 pod:运行于Kubernetes中的容器(1)

3 pod:运行于Kubernetes中的容器(2)

3.6 注解pod

除标签外,pod和其他对象还可以包含注解。注解也是键值对,所以它们本质上与标签非常相似。但与标签不同,注解并不是为了保存标识信息而存在的,它们不能像标签一样用于对对象进行分组。当我们可以通过标签选择器选择对象时,就不存在注解选择器这样的东西。

另一方面,注解可以容纳更多的信息,并且主要用于工具使用。Kubernetes也会将一些注解自动添加到对象,但其他的注解则需要由用户手动添加。

向Kubernetes引入新特性时,通常也会使用注解。一般来说,新功能的alpha和beta版本不会向API对象引入任何新字段,因此使用的是注解而不是字段,一旦所需的API更改变得清晰并得到所有相关人员的认可,就会引入新的字段并废弃相关注解。

大量使用注解可以为每个pod或其他API对象添加说明,以便每个使用该集群的人都可以快速查找有关每个单独对象的信息。例如,指定创建对象的人员姓名的注解可以使在集群中工作的人员之间的协作更加便利。

3.6.1 查找对象的注解

让我们看一个Kubernetes自动添加注解到我们在前一章中创建的pod的注解示例。为了查看注解,我们需要获取pod的完整YAML文件或使用 kubectl describe 命令。我们在下述代码清单中使用第一个方法。

代码清单3.5 pod的注解

$ kubectl get po kubia -o yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2021-02-12T23:33:12Z"
  labels:
    run: kubia
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:status:
......

正如你所见,kubernetes.io/created-by 注解保存了创建该pod的对象的一些JSON数据,而没有涉及太多细节,因此注解并不会是我们想要放入标签的东西。相对而言,标签应该简短一些,而注解则可以包含相对更多的数据(总共不超过256KB)。

注意  kubernetes.io/created-by 注解在版本1.8中已经废弃,将会在版本1.9中删除,所以在YAML文件中不会再看到该注解。

3.6.2 添加和修改注解

显然,和标签一样,注解可以在创建时就添加到pod中,也可以在之后再对现有的pod进行添加或修改。其中将注解添加到现有对象的最简单的方法是通过 kubectl annotate 命令。

我们现在可以尝试添加注解到kubia-manual pod中:

$ kubectl annotate pod kubia-manual mycompany.com/someannotation="foo bar"

我们已将注解 mycompany.com/someannotation 添加为值foo bar。使用这种格式的注解键来避免键冲突是一个好方法。当不同的工具或库向对象添加注解时,如果它们不像我们刚刚那样使用唯一的前缀,可能会意外地覆盖对方的注解。

使用kubectl describe命令查看刚刚添加的注解:

$ kubectl describe pod kubia-manual

3.7 使用命名空间对资源进行分组

首先回到标签的概念,我们已经看到标签是如何将pod和其他对象组织成组的。由于每个对象都可以有多个标签,因此这些对象组可以重叠。另外,当在集群中工作(例如通过kubectl)时,如果没有明确指定标签选择器,我们总能看到所有对象。

但是,当你想将对象分割成完全独立且不重叠的组时,又该如何呢?可能你每次只想在一个小组内进行操作,因此Kubernetes也能将对象分组到命名空间中。这和我们在第2章中讨论的用于相互隔离进程的Linux命名空间不一样,Kubernetes命名空间简单地为对象名称提供了一个作用域。此时我们并不会将所有资源都放在同一个命名空间中,而是将它们组织到多个命名空间中,这样可以允许我们多次使用相同的资源名称(跨不同的命名空间)。

3.7.1 了解对命名空间的需求

在使用多个namespace的前提下,我们可以将包含大量组件的复杂系统拆分为更小的不同组,这些不同组也可以用于在多租户环境中分配资源,将资源分配为生产、开发和QA环境,或者以其他任何你需要的方式分配资源。资源名称只需在命名空间内保持唯一即可,因此两个不同的命名空间可以包含同名的资源。虽然大多数类型的资源都与命名空间相关,但仍有一些与它无关,其中之一便是全局且未被约束于单一命名空间的节点资源。在后续章节我们还将接触到其他一些集群级别的资源。

现在让我们看看如何使用命名空间。

3.7.2 发现其他命名空间及其pod

首先,让我们列出集群中的所有命名空间:

$ kubectl get ns
NAME              STATUS   AGE
default           Active   17h
kube-node-lease   Active   17h
kube-public       Active   17h
kube-system       Active   17h

 到目前为止,我们只在default命名空间中进行操作。当使用 kubectl get 命令列出资源时,我们从未明确指定命名空间,因此kubectl总是默认为default命名空间,只显示该命名空间下的对象。但从列表中我们可以看到还存在kube-public和kube-system命名空间。接下来可以使用kubectl命令指定命名空间来列出只属于该命名空间的pod,如下所示为属于 kube-system 命名空间的pod:

$ kubectl get po --namespace kube-system
NAME                                 READY   STATUS              RESTARTS   AGE
coredns-74ff55c5b-mglbs              0/1     Pending             0          17h
coredns-74ff55c5b-vw4g8              0/1     Pending             0          17h
etcd-k8s-master                      1/1     Running             3          17h
kube-apiserver-k8s-master            1/1     Running             3          17h
kube-controller-manager-k8s-master   1/1     Running             3          17h
kube-proxy-bsjx2                     0/1     ContainerCreating   0          16h
kube-proxy-g2mlv                     0/1     ContainerCreating   0          16h
kube-proxy-mskzh                     1/1     Running             3          17h
kube-scheduler-k8s-master            1/1     Running             3          17h

提示 也可以使用-n来代替--namespace 

我们将在本书后面继续了解这些pod(如果此处显示的pod与你系统上的pod不匹配,请不用担心)。从命名空间的名称可以清楚地看到,这些资源与Kubernetes系统本身是密切相关的。通过将它们放在单独的命名空间中,可以保持一切组织良好。如果它们都在默认的命名空间中,同时与我们自己创建的资源混合在一起,那么我们很难区分这些资源属于哪里,并且也可能会无意中删除一些系统资源。

namespace使我们能够将不属于一组的资源分到不重叠的组中。如果有多个用户或用户组正在使用同一个Kubernetes集群,并且它们都各自管理自己独特的资源集合,那么它们就应该分别使用各自的命名空间。这样一来,它们就不用特别担心无意中修改或删除其他用户的资源,也无须关心名称冲突。如前所述,命名空间为资源名称提供了一个作用域。

除了隔离资源,命名空间还可用于仅允许某些用户访问某些特定资源,甚至限制单个用户可用的计算资源数量。关于这些内容我们将在第12~14章进行具体介绍。

3.7.3 创建一个命名空间

命名空间是一种和其他资源一样的Kubernetes资源,因此可以通过将YAML文件提交到Kubernetes API服务器来创建该资源。现在就让我们具体实践操作一下吧。

从YAML文件创建命名空间

首先,创建一个包含以下代码清单内容的custom-namespace.yaml文件(可以在本书的代码归档中找到它)。

代码清单3.6 namespace的YAML定义:custom-namespace.yaml

 现在,使用kubectl将文件提交到Kubernetes API服务器:

$  kubectl create -f custom-namespace.yaml

使用kubectl create namespace命令创建命名空间

虽然写出上面这样的文件并不困难,但这仍然是一件麻烦事。幸运的是,我们还可以使用专用的kubectl create namespace命令创建命名空间,这比编写YAML文件快得多。而我们之所以选择使用YAML文件,只是为了强化Kubernetes中的所有内容都是一个API对象这一概念。可以通过向API服务器提交YAML manifest来实现创建、读取、更新和删除。

可以像这样创建命名空间:

$ kubectl create namespace custom-namespace

注意 尽管大多数对象的名称必须符合RFC 1035(域名)中规定的命名规范,这意味着它们可能只包含字母、数字、横杠(-)和点号,但命名空间(和另外几个)不允许包含点号。

3.7.4 管理其他命名空间中的对象

如果想要在刚创建的命名空间中创建资源,可以选择在metadata字段中添加一个 namespace: custom-namespace 属性,也可以在使用 kubectl create 命令创建资源时指定命名空间:

$ kubectl create -f kubia-manual.yaml -n custom-namespace

此时我们有两个同名的pod(kubia-manual)。一个在default命名空间中,另一个在custom-namespace中。

在列出、描述、修改或删除其他命名空间中的对象时,需要给kubectl命令传递 --namespace(或-n)选项。如果不指定命名空间,kubectl将在当前上下文中配置的默认命名空间中执行操作。而当前上下文的命名空间和当前上下文本身都可以通过kubectl config命令进行更改。

提示 要想快速切换到不同的命名空间,可以设置以下别名:alias kcd='kubectl config set-context $(kubectl config currentcontext)--namespace'。然后,可以使用 kcd some-namespace 在命名空间之间进行切换。

3.7.5 命名空间提供的隔离

在结束命名空间这一部分之前,我们需要解释一下命名空间不提供什么—— 至少不是开箱即用的。尽管命名空间将对象分隔到不同的组,只允许你对属于特定命名空间的对象进行操作,但实际上命名空间之间并不提供对正在运行的对象的任何隔离。

例如,你可能会认为当不同的用户在不同的命名空间中部署pod时,这些pod应该彼此隔离,并且无法通信,但事实却并非如此。命名空间之间是否提供网络隔离取决于Kubernetes所使用的网络解决方案。当该解决方案不提供命名空间间的网络隔离时,如果命名空间foo中的某个pod知道命名空间 bar中pod的IP地址,那它就可以将流量(例如HTTP请求)发送到另一个pod。

 

3.8 停止和移除pod

到目前为止,我们已经创建了一些应该仍在运行的pod。其中有四个pod在default命名空间中运行,一个pod在custom-namespace中运行。由于我们已经不需要这些pod了,所以此时考虑停止它们。

3.8.1 按名称删除pod

首先,我们将按名称删除kubia-gpu pod:

$ kubectl delete po kubia-gpu

在删除pod的过程中,实际上我们在指示Kubernetes终止该pod中的所有容器。Kubernetes向进程发送一个SIGTERM信号并等待一定的秒数(默认为30),使其正常关闭。如果它没有及时关闭,则通过SIGKILL终止该进程。因此,为了确保你的进程总是正常关闭,进程需要正确处理SIGTERM信号。

提示 还可以通过指定多个空格分隔的名称来删除多个pod(例如:kubectl delete po pod1 pod2)。

3.8.2 使用标签选择器删除pod

与根据名称指定pod进行删除不同,此时将使用我们了解的关于标签选择器的知识来停止 kubia-manual 和 kubia-manual-v2 pod 。这两个pod都包含标签 creation_method=manual ,因此可以通过使用一个标签选择器来删除它们:

$ kubectl delete po -l creation_method=manual

在之前的微服务示例中,我们有几十个(或可能有几百个)pod。例如,通过指定 rel=canary 标签选择器(如图3.10所示),可以一次删除所有金丝雀pod:

$ kubectl delete po -l rel=canary
图3.10 通过rel=canary标签选择器选择并删除所有金丝雀pod

3.8.3 通过删除整个命名空间来删除pod

再回过头看看custom-namespace中的pod。此时不再需要该命名空间中的pod,也不需要命名空间本身。这意味着,可以简单地删除整个命名空间(pod将会伴随命名空间自动删除)。现在使用以下命令删除custom-namespace:

$ kubectl delete ns custom-namespace

3.8.4 删除命名空间中的所有pod,但保留命名空间

此时我们已经清理了几乎所有的东西,但在第2章中用kubectl run命令创建的pod怎么样了呢?该pod目前仍然在运行:

$ kubectl get pods

这一次我们不再删除一个特定pod,而是通过使用--all选项告诉Kubernetes删除当前命名空间中的所有pod:

$ kubectl delete po --all

现在,让我们再次检查有没有遗留依然在运行的pod:

$ kubectl get pods

什么?!我们看到,在kubia-zxzij pod 正在终止时,却出现一个之前并没有出现过的叫作kubia-09as0的新pod。无论我们进行了多少遍的全部删除pod,都会冒出一个名为kubia-something的新pod。

你可能还记得我们使用kubectl run命令创建了第一个pod。在第2章中提过这不会直接创建pod,而是创建一个ReplicationCcontroller,然后再由ReplicationCcontroller创建pod。因此只要删除由该ReplicationCcontroller创建的pod,它便会立即创建一个新的pod。如果想要删除该pod,我们还需要删除这个ReplicationCcontroller。

 

3.8.5 删除命名空间中的(几乎)所有资源

通过使用单个命令删除当前命名空间中的所有资源,可以删除ReplicationCcontroller和pod,以及我们创建的所有service:

$ kubectl delete all --all

命令中的第一个all指定正在删除所有资源类型,而--all选项指定将删除所有资源实例,而不是按名称指定它们(我们在运行前一个删除命令时已经使用过此选项)。

注意 使用all关键字删除所有内容并不是真的完全删除所有内容。一些资源(比如我们将在第7章中介绍的Secret)会被保留下来,并且需要被明确指定删除。

删除资源时,kubectl将打印它删除的每个资源的名称。在列表中,可以看到在第2章中创建的名为kubia的ReplicationController和名为kubia-http的Service。

注意 kubectl delete all --all 命令也会删除名为kubernetes的Service,但它应该会在几分钟后自动重新创建。

3.9 本章小结

阅读本章之后,你应该对Kubernetes的核心模块有了系统的了解。在接下来的几章中学到的概念也都与pod有着直接关联。

在本章中,你应该已经掌握:

  • 如何决定是否应将某些容器组合在一个pod中。
  • pod可以运行多个进程,这和非容器世界中的物理主机类似。
  • 可以编写YAML或JSON描述文件用于创建pod,然后查看pod的规格及其当前状态。
  • 使用标签来组织pod,并且一次在多个pod上执行操作。
  • 可以使用节点标签将pod只调度到提供某些指定特性的节点上。
  • 注解允许人们、工具或库将更大的数据块附加到pod。
  • 命名空间可用于允许不同团队使用同一集群,就像它们使用单独的Kubernetes集群一样。
  • 使用 kubectl explain 命令快速查看任何Kubernetes资源的信息。

在下一章,你将会了解到ReplicationController和其他管理pod的资源。

以上是关于Kubernetes in Action 笔记 —— Kubernetes 介绍的主要内容,如果未能解决你的问题,请参考以下文章

Kubernetes in Action 笔记 —— 部署第一个应用

Kubernetes In Action :2开始使用Kubernetes和Docker

Kubernetes In Action :2开始使用Kubernetes和Docker

Kubernetes In Action :2开始使用Kubernetes和Docker

Kubernetes In Action :1Kubernetes介绍

Kubernetes In Action :1Kubernetes介绍