赞
踩
你可以认为namespaces是你kubernetes集群中的虚拟化集群。在一个Kubernetes集群中可以拥有多个命名空间,它们在逻辑上彼此隔离。 他们可以为您和您的团队提供组织,安全甚至性能方面的帮助!
“default” Namespace
大多数的Kubernetes中的集群默认会有一个叫default的namespace。实际上,应该是3个:
default:你的service和app默认被创建于此。
kube-system:kubernetes系统组件使用。
kube-public:公共资源使用。但实际上现在并不常用。
这个默认(default)的namespace并没什么特别,但你不能删除它。这很适合刚刚开始使用kubernetes和一些小的产品系统。但不建议应用于大型生产系统。因为,这种复杂系统中,团队会非常容易意外地或者无意识地重写或者中断其他服务service。相反,请创建多个命名空间来把你的服务service分割成更容易管理的块。
命名空间主要有两个方面的作用: k8s命名空间主要用于隔离集群资源、隔离容器等,为集群提供了一种虚拟隔离的策略;
- kubectl get namespaces
- kubectl get namesapce
- kubectl get ns # 三个操作等效
- kubectl get ns --show-labels # 显示namespace的label
可以使用 kubectl describe
命令来查看某个namespace的概要信息
不要害怕创建namespace。它不会降低服务的性能,反而大多情况下会提升你的工作效率。
创建namespace只需一个很简单的命令,例如,创建一个名字为:test的namespace,执行:
kubectl create namespace test
或者使用yaml文件,然后执行kubectl apply -f test.yaml
#test.yaml:
kind: Namespace
apiVersion: v1
metadata:
name: test
labels:
name: test
查看namespace:kubectl get namespace
会看到test和其他系统默认的命名空间。
如下是一个简单的 Pod YAML文件:
apiVersion: v1
kind: Pod
metadata:
name: mypod
labels:
name: mypod
spec:
containers:
- name: mypod
image: nginx
你会发现没有提到namespace。如果你通过命令kubectl apply 来创建pod,它会在当前的命名空间中创建pod。这个命名空间就是defaut,除非你更改过。
有2种方法来指定资源的namespace:
1、kubectl apply -f pod.yaml --namespace=test
2、在yaml中指定:
apiVersion: v1
kind: Pod
metadata:
name: mypod
namespace: test
labels:
name: mypod
spec:
containers:
- name: mypod
image: nginx
如果你用命令$ kubectl get pods来查看你的pod,你会得到:资源未找到的错误。
这是因为命令是在当前(default)命名空间中,如果要查看其他namespace资源,你需要指定namespace:
$ kubectl get pods --namespace=test
NAME READY STATUS RESTARTS AGE
mypod 1/1 Running 0 10s
但是,这很让人烦,每次都要指定namespace。下面让我们看看如何修正这个“烦恼”。
一开始默认的激活的命名空间是default。因此,当你在其他namespace创建了资源,那么每次使用kubectl命令都要带上namespace将会很痛苦。幸好,神器 kubens 能够解决这个问题。
当你运行kubens命令,它会高亮当前的namespace:
要更换到test空间,运行:kubens test
现在你会看到:
这是,你所有的命令会在这个namespace下执行:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
mypod 1/1 Running 0 10m
命名空间彼此是透明的。但它们并不是绝对相互隔绝但。一个namespace中service可以和另一个namespace中的service通信。这非常有用,比如你团队的一个service要和另外一个团队的service通信,而你们的service都在各自的namespace中。
我们通常会把mysql,redis,rabbitmq,mongodb这些公用组件放在一个namespace里,或者每个公用组件都有自己的namespace,而你的业务组件会统一放在自己的namespace里,这时就涉及到了跨namespace的数据通讯问题。
当你的应用app要访问Kubernetes的service,你可以使用内置的DNS服务发现并把你的app指到Service的名称。然而,你可以在多个namespace中创建同名的service。解决这个问题,就用到 DNS地址的扩展形式。
在Kubernetes中,Service通过一个DNS模式来暴露endpoint。这个模式类似:
<Service Name>.<Namespace Name>.svc.cluster.local
一般情况下,你只需要service的名称,DNS会自动解析到它的全地址。然而,如果你要访问其他namespace中的service,那么你就需要同时使用service名称和namespace名称。例如,你想访问namespace为test中的“database”服务,你可以使用下面的地址:
database.test
注意⚠️:如果你创建的namespace的名字正好映射到顶级域名,如 “com” 或者 “org”,然后,你创建的service的名称和一个网站名称一样,如 “google” 或者 “baidu”。那么 Kubernetes会拦截到 “google.com” 或者 “baidu.com”的请求并转发到你的service中。
当然,这个技术在测试或者代理功能中非常好用。但请慎重!如果你不想使namespace相互隔离,你可以使用network policy来解决。当然这是另一个话题。
Kubernetes的资源限制一般是以Namespace为单位进行限制为Namespace限额的方式有两种:ResourceQuota和LimitRange
ResourceQuota 即资源配额,用来限制 namespace 中所有的 Pod 占用的总的资源 request 和 limit 。即限定单个namespace中可使用集群资源的总量,包括两个维度:
LimitRange 用来限制 namespace 中 单个Pod 默认资源 request 和 limit。
如果在 namespace 中为计算资源 CPU 和内存设定了 ResourceQuota,用户在创建对象(Pod、Service等)时,必须指定 requests 和 limits;如果在创建或更新对象时申请的资源与 namespace 的 ResourceQuota 冲突,则 apiserver 会返回 HTTP 状态码 403,以及对应的错误提示信息。当集群中总的容量小于各个 namespace 资源配额的总和时,可能会发生资源争夺,此时 Kubernetes 将按照先到先得的方式分配资源。
声明格式为: count/<resource>.<group>
, 如下列出各类对象的声明格式
- count/persistentvolumeclaims
- count/services
- count/secrets
- count/configmaps
- count/replicationcontrollers
- count/deployments.apps
- count/replicasets.apps
- count/statefulsets.apps
- count/jobs.batch
- count/cronjobs.batch
- count/deployments.extensions
定义CPU、内存请求(requests)、限制(limits)使用的总量,包括
定义存储卷声明请求的存储总量或创建存储卷声明数量的限制,包括
<storage-class-name>.storageclass.storage.k8s.io/requests.storage
:namespace中,所有与指定存储类(StorageClass)关联的存储卷声明请求的存储总量不能超过该值<storage-class-name>.storageclass.storage.k8s.io/persistentvolumeclaims
:namespace中,所有与指定存储类关联的存储卷声明的总数不能超过该值除此之外,还可以对本地临时存储资源进行限制定义
Resource Quota 是对namespace中总体的资源使用进行限制,Resource Limit Range 则是对具体某个Pod或容器的资源使用进行限制。默认情况下,namespace中Pod或容器的资源消耗是不受限制的,这就可能导致某个容器应用内存泄露耗尽资源影响其它应用的情况。Limit Range可以用来限定namespace内Pod(或容器)可以消耗资源的数量。
使用LimitRange对象,我们可以:
如果创建或更新对象(Pod、容器、PersistentVolumeClaim)对资源的请求与LimitRange相冲突,apiserver会返回HTTP状态码403,以及相应的错误提示信息;如果namespace中定义了LimitRange 来限定CPU与内存等计算资源的使用,则用户创建Pod、容器时,必须指定CPU或内存的request与limit,否则将被系统拒绝;当namespace总的limit小于其中Pod、容器的limit之和时,将发生资源争夺,Pod或者容器将不能创建,但不影响已经创建的Pod或容器。
创建一个测试namespace test-limitrange,创建LimitRange定义文件 lr-test.yaml:
- apiVersion: v1
- kind: LimitRange
- metadata:
- name: lr-test
- spec:
- limits:
- - type: Container #资源类型
- max:
- cpu: "1" #限定最大CPU
- memory: "1Gi" #限定最大内存
- min:
- cpu: "100m" #限定最小CPU
- memory: "100Mi" #限定最小内存
- default:
- cpu: "900m" #默认CPU限定
- memory: "800Mi" #默认内存限定
- defaultRequest:
- cpu: "200m" #默认CPU请求
- memory: "200Mi" #默认内存请求
- maxLimitRequestRatio:
- cpu: 2 #限定CPU limit/request比值最大为2
- memory: 1.5 #限定内存limit/request比值最大为1.5
- - type: Pod
- max:
- cpu: "2" #限定Pod最大CPU
- memory: "2Gi" #限定Pod最大内存
- - type: PersistentVolumeClaim
- max:
- storage: 2Gi #限定PVC最大的requests.storage
- min:
- storage: 1Gi #限定PVC最小的requests.storage
该文件定义了在namespace test-limitrange
中,容器、Pod、PVC的资源限制,在该namesapce中,只有满足如下条件,对象才能创建成功
resources.limits
部分CPU必须在100m-1之间,内存必须在100Mi-1Gi之间,否则创建失败resources.limits
部分CPU与resources.requests
部分CPU的比值最大为2,memory比值最大为1.5,否则创建失败resources.limits
部分CPU总和最大为2,内存总和最大为2Gi,否则创建失败resources.requests.storage
最大为2Gi,最小为1Gi,否则创建失败如果容器定义了
resources.requests
没有定义resources.limits
,则LimitRange中的default部分将作为limit注入到容器中;如果容器定义了resources.limits
却没有定义resources.requests
,则将requests值也设置为limits的值;如果容器两者都没有定义,则使用LimitRange中default作为limits,defaultRequest作为requests值
通常大家会问:我应该创建多少个namespace?有什么用?什么是真正的可控的块?创建多了吧,碍事;创建少了吧,你还用不上namespace真正的好处。
我认为,这个答案取决于你的项目或者公司处于什么阶段----从小团队到大公司,各自都有自己的组织结构。根据不同的情况,你可以采用相对的命名空间的策略。
这种场景下,你一般运作5 - 10 个微服务,很容易做到管理这些服务。这种情况下,你将所有的服务创建在default空间中是合理的。当然你可以创建 “production” 和 “development” 两个空间,但一般情况下,你会在你本地机器上的development环境进行测试,例如使用minikube。
这种场景下,你带领一个快速增长的团队运作 10+个微服务。你将团队分成很多子团队负责各自的微服务。但可能每个人都知道整个系统是如何运行的,因此每次变更越来越难以和其他每个人进行确认,而且每个人每天会在自己本地机器运行这个复杂的全栈系统。这时,有必要针对生产环境和开发环境使用多个集群或者命名空间了。每个团队拥有各自的命名空间,这样更容易进行管理。
在大的公司中,并不是每个人都认识其他人。团队间可能并不清楚各自的机能。微服务间通过service contract(例如gRPC)来通信,并通过service mesh(如istio)来协调通信。
试图在本地运行整个堆栈是不可能的。 强烈建议使用Kubernetes-aware Continuous Delivery系统(例如,Spinnaker)。
此时,每个团队肯定需要自己的命名空间。 每个团队甚至可以选择多个名称空间来运行其开发和生产环境。 设置RBAC和ResourceQuotas也是一个好主意。 多个集群开始显得很有意义,但可能不一定是必要的。
在这种规模下,有些群体甚至不知道其他群体的存在。 某个组也可能是外部公司,服务之间通过标准文档定义的API来通信。 每个小组都有多个拥有一定数量微服务的团队。 这时使用我上面提到的所有工具是必要的。 人们不应该手工部署服务,同时应该被锁定在他们不拥有的命名空间之外。此时,拥有多个集群以减少配置不当的应用程序导致的爆炸半径,以及简化计费和资源管理可能是有意义的。
命名空间可以帮助您组织Kubernetes资源,同时可以提高团队的开发效率。 请继续关注未来的Kubernetes最佳实践剧集,我将向您展示如何锁定命名空间中的资源并为您的群集引入更多安全性和隔离性!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。