3.6 注解pod
除标签外,pod和其他对象还可以包含注解。注解也是键值对,所以它们本质上与标签非常相似。但与标签不同,注解并不是为了保存标识信息而存在的,它们不能像标签一样用于对对象进行分组。当我们可以通过标签选择器选择对象时,就不存在注解选择器这样的东西。
另一方面,注解可以容纳更多的信息,并且主要用于工具使用。Kubernetes也会将一些注解自动添加到对象,但其他的注解则需要由用户手动添加。
向Kubernetes引入新特性时,通常也会使用注解。一般来说,新功能的alpha和beta版本不会向API对象引入任何新字段,因此使用的是注解而不是字段,一旦所需的API更改变得清晰并得到所有相关人员的认可,就会引入新的字段并废弃相关注解。
大量使用注解可以为每个pod或其他API对象添加说明,以便每个使用该集群的人都可以快速查找有关每个单独对象的信息。例如,指定创建对象的人员姓名的注解可以使在集群中工作的人员之间的协作更加便利。
3.6.1 查找对象的注解
让我们看一个Kubernetes自动添加注解到我们在前一章中创建的pod的注解示例。为了查看注解,我们需要获取pod的完整YAML文件或使用 kubectl describe
命令。我们在下述代码清单中使用第一个方法。
Name: kubia
Namespace: default
Priority: 0
Node: minikube/172.17.0.2
Start Time: Mon, 05 Jul 2021 21:22:27 -0400
Labels: creation_method=manual
env=prod
Annotations: mycompany.com/someannotation: foo bar//注解
Status: Running
IP: 172.18.0.3
3.6.2 添加和修改注解
显然,和标签一样,注解可以在创建时就添加到pod中,也可以在之后再对现有的pod进行添加或修改。其中将注解添加到现有对象的最简单的方法是通过 kubectl annotate
命令。
我们现在可以尝试添加注解到kubia pod中:
$ kubectl annotate pod kubia mycompany.com/someannotation="foo bar"
我们已将注解 mycompany.com/someannotation
添加为值foo bar。使用这种格式的注解键来避免键冲突是一个好方法。当不同的工具或库向对象添加注解时,如果它们不像我们刚刚那样使用唯一的前缀,可能会意外地覆盖对方的注解。
使用kubectl describe命令查看刚刚添加的注解:
$ kubectl describe pod kubia
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 2d11h
kube-node-lease Active 2d11h
kube-public Active 2d11h
kube-system Active 2d11h
kubernetes-dashboard Active 2d11h
到目前为止,我们只在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
apiVersion: v1
kind: Namespace #定义的类型为命名空间
metadata:
name: custom-namespace # 命名空间的名称
现在,使用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.yaml -n custom-namespace
此时我们有两个同名的pod(kubia-manual)。一个在default命名空间中,另一个在custom-namespace中。
在列出、描述、修改或删除其他命名空间中的对象时,需要给kubectl命令传递 --namespace
(或-n)选项。如果不指定命名空间,kubectl将在当前上下文中配置的默认命名空间中执行操作。而当前上下文的命名空间和当前上下文本身都可以通过kubectl config命令进行更改。
切换命名空间
$ kubectl config set-context --current --namespace=<insert-namespace-name-here>
# Validate it
$ kubectl config view --minify | grep namespace:
3.7.5 命名空间提供的隔离
在结束命名空间这一部分之前,我们需要解释一下命名空间不提供什么—— 至少不是开箱即用的。尽管命名空间将对象分隔到不同的组,只允许你对属于特定命名空间的对象进行操作,但实际上命名空间之间并不提供对正在运行的对象的任何隔离。
例如,你可能会认为当不同的用户在不同的命名空间中部署pod时,这些pod应该彼此隔离,并且无法通信,但事实却并非如此。命名空间之间是否提供网络隔离取决于Kubernetes所使用的网络解决方案。当该解决方案不提供命名空间间的网络隔离时,如果命名空间foo中的某个pod知道命名空间 bar中pod的IP地址,那它就可以将流量(例如HTTP请求)发送到另一个pod。