@dujun
        
        2015-02-27T08:32:16.000000Z
        字数 6460
        阅读 7616
    Kubernetes写书
什么是namespace
namespace是一个将Kubernetes的资源对象进行细分的一个类似于DNS子域名的概念。namespace能够帮助不同的租户共享一个Kubernetes集群。Kubernetes引入namespace的目的包括:
与namespace相关的kubectl命令如下所示。
| 命令 | 含义 | 
|---|---|
| kubectl namespace | 查看当前所处的namespace | 
| kubectl namespace yourspace | 设置当前的namespace为yourspace | 
| kubectl get namespaces | 罗列系统当前可用的namespace列表 | 
表x kubectl与namespace相关的命令及含义
相关参数有以下这些。
| 参数 | 含义 | 
|---|---|
| --namespace | 将kubectl命令行请求所能操作的kubernetes对象限定在特定namespace中 | 
| --ns-path | 记录当前namespace内容的文件路径 | 
表x kubectl与namespace相关的参数及含义
Kubernetes系统默认namespace是default,ns-path默认是user_home_path/.kubernetes_ns,该文件内容形如。
{"Namespace":"default"}
事实上,通过命令kubectl namespace space设置当前namespace为space就是通过将文件.kubernetes_ns的内容被改为以下内容来实现的。如果新切换的前namespace不存在,则调用系统API创建该namespace?还是返回一个错误信息。关于创建namespace的一些细节,请参考下文的实践案例。
{"Namespace":"space"}
这样,所有的API操作都被限定在namespace space中,与其他namespace完全隔离开来。而kubectl namespace命令查看当前namespace则是通过读取文件.kubernetes_ns的内容来实现的。
多namespace使用案例
假设有一个资源文件:redis-controller.json,该json文件定义了一个replication controller,该replication controller又管理着一个pod。首先,在default namespace中创建一个名为redisController的replication controller。
kubectl create -f redis-controller.json --namespace=default
接着,用同样方法在myspace namespace中创建一个名为redisController2的replication controller。
kubectl create -f redis-controller2.json --namespace=myspace(如果myspace不存在呢?创建一个新的?必需确定下来!)
创建完毕后,查看系统中的replication controller信息。
$ kubectl get replicationController
CONTROLLER          CONTAINER(S)        IMAGE(S)                   SELECTOR            REPLICAS
redisController     redis               10.10.103.215:5000/redis   name=redis          1
你会惊奇地发现:replication controller只有一个,即redisController。那为什么看不到redisController2呢?原来我们现在处于default namespace,要看到另外一个则需要切换到我们刚刚自定义的myspace namespace。
$ kubectl get replicationController --namespace=myspace
CONTROLLER          CONTAINER(S)        IMAGE(S)                   SELECTOR            REPLICAS
redisController2     redis               10.10.103.215:5000/redis   name=redis          1
这样,redisController2就对用户可见。而redisController则只在default namespace对用户可见。
$ kubectl get replicationController --namespace=default
CONTROLLER          CONTAINER(S)        IMAGE(S)                   SELECTOR            REPLICAS
redisController     redis               10.10.103.215:5000/redis   name=redis          1
这样通过在kubectl命令行添加--namespace参数,我们就初步实现了客户端对kubernetes资源对象的隔离访问。
事实上,Kubernetes支持namespace隔离的资源对象类型至少包括这几种:pod、service、replicationController、event、endpoints。这一点可以通过查看etcd上/registry目录便可一目了然,在etcd上进行内容持久化的Kubernetes资源的存储路径如下所示。
/registry/{resourceType}/{resource.Namespace}/{resource.Name}
这样,Kubernetes就可以通过etcd的watch机制监测/registry/{resourceType}目录下数据的变化来及时发现不同namespace的{resourceType}的更新。
当将一个pod调度到一个特定的主机上时,该pod在etcd上的存储路径形如:/host/{host}/pod/{pod.Namespace}/{pod.Name}。
以pod为例。
$ etcdctl ls /registry --recursive
...省略部分输出
/registry/pods
/registry/pods/default
/registry/pods/default/f54759d0-a51f-11e4-91b1-005056b43972
/registry/pods/myspace
/registry/pods/myspace/ac8e6983-a51f-11e4-91b1-005056b43972
以上输出表明,pod分别存在于两个namespace:default和myspace,其uid分别为f54759d0-a51f-11e4-91b1-005056b43972和ac8e6983-a51f-11e4-91b1-005056b43972,分别对应于redisController和redisController2控制的pod。是的,pod与控制该pod的replication Controller处于同一个namespace中,Kubernetes的controller-manager保证了这一点。另外,不同的namespace中允许存在同名的kubernetes资源对象,这与C++等支持namespace的编程语言类似。
我们再回头看上面提到的与namespace相关的kubctl命令:kubectl get namespaces,然后与我们熟悉的kubectl get pods命令相比较,聪明的读者可能已经猜到了,namespace也是kubernetes内置的对象类型之一。用户可以通过资源文件来描述一个namespace对象,譬如下面的这个namespace-dev.json文件,定义了一个名为development的namespace。
{
  "kind": "Namespace",
  "apiVersion":"v1beta1",
  "id": "development",
  "spec": {},
  "status": {},
  "labels": {
    "name": "development"
  },
}
与Kubernetes的其他对象一样,我们可以使用kubectl create来创建该namespace对象。
$ kubectl create -f namespace-dev.json
同理,我们可以用同样的方法创建一个名为production的namespace。
$ kubectl create -f namespace-prod.json
为了检验上述namespace是否成功创建,罗列系统当前可用的namespace列表。
$ kubectl get namespaces
NAME                LABELS
default             <none>
development         name=development
production          name=production
上文提到过,kubectl命令后面加--namespace参数会将kubectl客户端限定在特定namespace中,如果读者觉得每条命令后面都加这么一条尾巴觉得累赘,可以使用下面的步骤来设置kubectl命令的上下文。
定义kubectl客户端上下文:dev和prod。
$ kubectl config set-context dev --namespace=development
$ kubectl config set-context prod --namespace=production
切换到你希望进行操作的namespace。
$ kubectl config use-context dev
这样,接下来的所有kubectl客户端操作都被限定在development namespace中。如果需要查看当前所处的上下文,可以这么做。
$ kubectl config view
clusters: {}
contexts:
  dev:
    cluster: ""
    namespace: development
    user: ""
  prod:
    cluster: ""
    namespace: production
    user: ""
current-context: dev
preferences: {}
users: {}
是的,我们处于dev上下文中,同时也被限定在development namespace中。上面的输出也告诉我们,namespace可以与用户的认证授权机制结合在一起使用。随着Kubernetes认证授权机制开发的深入,可以为不同的namespace提供不同的授权规则。下面我们将简单介绍下Kubernetes namespace与Kubernetes认证授权机制结合使用的原理。
namespace与认证授权机制结合
首先,我们来了解一下Kubernetes集群中的各种用户所扮演的角色。
| 用户 | 角色 | 
|---|---|
| kubernetes admin | kubernetes集群管理员 | 
| kubernetes service | kubernetes守护进程(如:controller-manager) | 
| policy manager | kubernetes集群访问控制规则的制定者 | 
| kubernetes user | kubernetes集群普通用户 | 
表x Kubernetes集群用户及其角色
为了支持namespace的资源隔离,Kubernetes APIServer按如下方式描述资源的地址(URL)。即在URL路径中,资源类型(resourceType)位于namespace(ns)之后。
发起以下资源请求的典型用户是kubernetes user或kubernetes service。
| 请求类型 | HTTP动作 | 资源路径 | 描述 | 
|---|---|---|---|
| CREATE | POST | /api/{version}/ns/{ns}/{resourceType}/ | 在 nsnamespace中创建资源resourceType的实例 | 
| GET | GET | /api/{version}/ns/{ns}/{resourceType}/{name} | 在 nsnamespace中获取名为name的资源resourceType的实例 | 
| UPDATE | PUT | /api/{version}/ns/{ns}/{resourceType}/{name} | 在 nsnamespace中更新名为name的资源resourceType的实例 | 
| DELETE | DELETE | /api/{version}/ns/{ns}/{resourceType}/{name} | 在 nsnamespace中删除名为name的资源resourceType的实例 | 
| LIST | GET | /api/{version}/ns/{ns}/{resourceType} | 罗列 nsnamespace中资源resourceType的实例列表 | 
| WATCH | GET | /api/{version}/watch/ns/{ns}/{resourceType} | 监测 nsnamespace中资源resourceType的变化 | 
发起以下资源请求的典型用户是由访问控制规则限定的kubernetes admin或kubernetes service。
| 请求类型 | HTTP动作 | 资源路径 | 描述 | 
|---|---|---|---|
| WATCH | GET | /api/{version}/watch/{resourceType} | 监测集群所有namespace中资源 resourceType的变化 | 
| LIST | GET | /api/{version}/list/{resourceType} | 罗列集群所有namespace中资源 resourceType的实例列表 | 
下面这些API模式是对default namespace进行操作的别名(alias)。
| 请求类型 | HTTP动作 | 资源路径 | 描述 | 
|---|---|---|---|
| CREATE | POST | /api/{version}/{resourceType}/ | 在 defaultnamespace中创建资源resourceType的实例 | 
| GET | GET | /api/{version}/{resourceType}/{name} | 在 defaultnamespace中获取名为name的资源resourceType的实例 | 
| UPDATE | PUT | /api/{version}/{resourceType}/{name} | 在 defaultnamespace中更新名为name的资源resourceType的实例 | 
| DELETE | DELETE | /api/{version}/{resourceType}/{name} | 在 defaultnamespace中删除名为name的资源resourceType的实例 | 
以上资源路径/api/{version}/{resourceType}/等价于/api/{version}/ns/default/{resourceType}/。
由上可以看出,任意一个Kubernetes资源对象在创建之初便与一个namespace绑定,如果API请求上下文中没有明确指定namespace,则APIServer会为之绑定一个默认namespace(default)。因此,当要创建或更新Kubernetes资源对象时,Kubernetes APIServer的认证授权插件会验证发起API请求的客户端所处的namespace是否与请求url路径中的{ns}相匹配。如果不匹配,Kubernetes APIServer则会拒绝该API请求。并且,Kubernetes APIServer也支持将访问控制规则与HTTP资源路径和动作绑定。这种将namespace编码到HTTP资源路径中的设计方案使得外部认证授权插件仅凭资源路径就能够执行相应动作。如果API请求认证授权失败,则该请求到此为止;否则将被转发给APIServer。