kubernetes node components – kubelet

kubelet作为k8s集群node上的重要组件,一直饱受关注。下面请随笔者一起walk through the code.

文 何思玫

1. Brief introduction of kubelet

管中窥豹,可见一斑。我们首先从k8s的官方文档中对kubelet的描述中一探究竟。

The kubelet is the primary “node agent” that runs on each node. The kubelet works in terms of a PodSpec. A PodSpec is a YAML or JSON object that describes a pod. The kubelet takes a set of PodSpecs that are provided through various echanisms (primarily through the apiserver) and ensures that the containers described in those PodSpecs are running and healthy. Other than from an PodSpec from the apiserver, there are three ways that a container manifest can be provided to the Kubelet.

File: Path passed as a flag on the command line. This file is rechecked every 20 seconds (configurable with a flag).

HTTP endpoint: HTTP endpoint passed as a parameter on the command line. This endpoint is checked every 20 seconds (also configurable with a flag).

HTTP server: The kubelet can also listen for HTTP and respond to a simple API (underspec’d currently) to submit a new manifest.

从上述描述中我们可以看到,kubelet是在集群中每个node上都必须存在的组件,负责维护管理pod。

它的工作主要基于四种source—— apiserver的PodSpec,File,HTTP endpoint及HTTP server——来更新pod。其中,File通过--file-check-frequency参数传入, HTTP通过--http-check-frequency参数。

2. Walk through the src code

文章分析的代码版本>v1.0.1, HEAD 6129d3d4。

kubelet相关代码的主入口在cmd/kublet下,调用方法的实现可能会在pkg/kubelet下。文中为了便利读者,也会就具体函数再进行标明。 下面我们就根据代码逻辑继续一次源码解读的DFS。

kubelet.go#main函数的主要流程包括如下三个步骤:

  • 创建一个KubeletServer实例
  • 根据命令行参数加载flag
  • 启动该kubeletServer。

如下图1所示。

kubelet-go-main

图1 kubelet.go#main

注意到,Run函数负责执行具体的kubelet的构建过程,在正常情况下是永远不会exit的。下面我们就来对该函数进行进一步的分析。

2.1 server.go#Run

如上图所示,KubeletServer.Run函数主要包括以下三个主要流程:

  • 配置并构建KubeletConfig实例。
  • 调用RunKubelet(&KubeletConfig,nil)函数真正地运行kubelet,该函数接受一个KubeletConfig类型的实例作为参数,包含了kubelet的配置信息。
  • 根据KubeletServer.HealthzPort的配置(即命令行参数--healthz-port),为/healthz url注册一个默认的handler(http.DefaultServeMux),启动health server。

可见,Run函数的核心步骤在于RunKubelet函数。

2.2 server.go#RunKubelet

我们首先通过略显复杂的图2来了解RunKubelet函数。它的使用场景非常明确,在node上创建并运行kubelet。 Runkubelet 图2 RunKubelet函数可以被大致划分为三大步骤。

Step1: 配置KubeletConfig信息,包括Hostname,NodeName,Recorder等。KubeletConfig这个结构包含了运行kubelet需要的所有参数,在可见的将来可能会和KubeletServer结构进行merge,不再单独存在。

  • 处理Hostname/NodeName信息
  • 创建了一个EventBroadcaster,创建一条包含kubelet及其NodeName配置的api.EventSource,将其注册到该EventBroadcaster中,用以记录kubelet产生的event并发送给apiserver。
  • 配置capabilities:系--allow-privileged--HostNetworkSources参数传入的值。
  • 配置使用docker拉取镜像时的credentialprovider的路径。
  • 配置OSInterface信息

Step2: createAndInitKubelet,顾名思义,创建并初始化kubelet。

builder在这里定义为createAndInitKubelet。

注意到这里返回了三个变量值,其中k为KubeletBootstrap(kubelet的interface),podCfg是config.PodConfig,最后一个是error变量。 podCfg变量是通过pc = makePodSourceConfig(kc)返回的,其中kc为传入的kubeletConfig变量。k则由NewMainKubelet函数返回。

Step3: 通过startKubelet启动kubelet,传入参数包括上一个函数的返回值及kcfg。

下面我们将就Step2和Step3进行更为详细的阐述。

2.2.1 server.go#createAndInitKubelet

这节内容主要包括两部分,首先来看makePodSourceConfig函数。

Section 1: makePodSourceConfig

该函数的返回值是一个config.PodConfig变量,用于将不同source的pod configuration合并到一个结构中,结构如下所示。

下面,我们具体来看makePodSourceConfig完成了什么工作。源码如下:

  • 使用NewPodConfig函数创建一个PodConfig变量cfg,用到了config.PodConfigNotificationSnapshotAndUpdateskc.RecorderPodConfigNotificationSnapshotAndUpdates的更新规则是,在增删pod的时候发送SET消息,其它变更发送UPDATE消息。其中,cfg.Updates是一个缓存大小为50的channel,收发数据类型为kubelet.PodUpdate(即对于某个pod的某种更新操作)。
  • 向podConfig变量cfg加入config source,包括 file/hhtp(url)/apiserver source。如同在开篇综述中所说,File类型和HTTP类型的pod configuration的变更,是通过定时查询对应source完成的。
  • 此处以更为常见的apiserver为例,我们使用NewSourceApiserver监听apiserver中podSpec的变更。该函数接收三个参数,第一个参数为用于向apiserver发起请求的Client,第二个参数为NodeName,第三个参数是由cfg.Channel返回的一个只读channel,类型是chan <- interface{}

也许读者会好奇,这个Channel函数具体做了哪些工作呢? 它会创建并返回一个interface{}类型的channel,并且启动go routine持续监听该Channel,并且将监听到的update进行merge。

merge是在NewPodConfig阶段决定的,即此前newPodStorage(updates, mode, recorder)返回的podStorage的Merge函数。该Merge函数定义在pkg/kubelet/config/config.go中,在该过程中会将监听的channel中更新的信息更新到cfg.updates中。限于篇幅,此处只展示PodConfigNotificationSnapshotAndUpdates对应的case,其它仅以”…”代替。

也就是说,cfg.Channel返回的是一个未知具体类型的被持续监听的channel(且该channel在merge之后会影响到原cfg),那么写channel的工作由谁完成呢?我们相信这是由config source(此处即apiserver)来完成的,也会在NewSourceApiserver函数分析中进行阐释。

  • 通过NewListWatchFromClient函数构造了一个ListWatch
  • 调用newSourceApiserverFromLW来watch并pull(拉取)apiserver的更新。

    // newSourceApiserverFromLW holds creates a config source that watches and pulls from the apiserver. func newSourceApiserverFromLW(lw cache.ListerWatcher, updates chan<- interface{}) { send := func(objs []interface{}) { var pods []api.Pod for _, o := range objs { pods = append(pods, o.(api.Pod)) } updates <- kubelet.PodUpdate{pods, kubelet.SET, kubelet.ApiserverSource} } cache.NewReflector(lw, &api.Pod{}, cache.NewUndeltaStore(send, cache.MetaNamespaceKeyFunc), 0).Run() }

可以看到,newSourceApiserverFromLW的执行核心只有一行代码,将创建出来的Reflector Run起来。

NewReflector函数创建一个Reflector对象,用于保证传入的第三个参数Store里的内容是update to date的。第三个参数以send函数为参数构建一个UndeltaStore,其PushFunc为send函数。 UndeltaStore listens to incremental updates and sends complete state on every change.也就是说,UndeltaStore不仅接受从Reflector来的update,并且还会使用UndeltaStore.PushFunc来进行change的deliver。这里就是写入到Cfg.Updates里,即完成了update的写操作。

Note:之前在集群运行过程中遇到过一个error,(可能在将来会upgrage成warning),即watcher超时,导致kubelet报错,位于reflector.go line#225。更新的内容来自listWatch,即apiserver。这里相当于是写updates。

Section 2: NewMainKubelet

我们通过pkg/kubelet/kubelet.go#NewMainKubelet函数构造了一个Kubelet。在该函数中创建各个kubelet需要的组件,部分参见如下列表

  • ContainerGC manages garbage collection of dead containers。负责进行对死掉的container进行垃圾回收。
  • ImageManager manages lifecycle of all images. 负责管理image。
  • DiskSpaceManager manages policy for diskspace management for disks holding docker images and root fs. 负责进行磁盘管理。
  • StatusManager updates pod statuses in apiserver. Writes only when new status has changed.该结构体中的podStatusChannel负责buffer podStatusSyncRequest,是一个缓冲区大小为1000的channel。 从apiserver中更新pod状态。
  • ReadinessManager maintains the readiness information(probe results) of containers over time to allow for implementation of health thresholds.负责收集container的readiness information(readiness info具体指什么并不明晰,是一个bool型,可能代表该container是否准备好?)。
  • RefManager manages the references for the containers. The references are used for reporting events such as creation, failure, etc.
  • VolumeManager manages the volumes for the pods running on the kubelet. Currently it only does book keeping, but it can be expanded to take care of the volumePlugins.
  • OOMWatcher watches cadvisor for system oom’s and records an event for every system oom encountered.
  • 初始化network plugin。这是个alpha feature。
  • ContainerRuntime 可以是DockerManager或者是rkt,默认为docker。
  • ContainerManager manages the containers running on a machine. -(周期性)配置网络参数(iptables rules)。 -(周期性)向master节点发送其它各个node的状态。synchronizes node status to master, registering the kubelet first if necessary.
  • 启动ContainerRuntime。ContainerRuntime是Runtime(interface)的一个实现,定义在pkg/kubelet/container/runtime.go中,包含了SyncPod/GetPodStatus等重要方法。以”docker”为例,它将是一个DockerManager,定义在pkg/kubelet/dockertools/manager.go中,并且实现了Runtime的所有方法。
  • PodManager stores and manages access to the pods. Kubelet discovers pod updates from 3 sources: file, http, and apiserver.三个update pod的来源,均在上例中的makePodSourceConfig 中进行了注册。 特别地,对于非apiserver来源的pod,apiserver是不知道其变更的。为了对其进行更新,我们创建了static pod。A mirror pod has the same pod full name (name and namespace) as its static counterpart (albeit different metadata such as UID, etc). By leveraging the fact that kubelet reports the pod status using the pod full name, the status of the mirror pod always reflects the actual status of the static pod. When a static pod gets deleted, the associated orphaned mirror pod will also be removed. 根据GetPodByFullName的原则,mirror pod会映射原pod的状态。
  • 为containerRuntime设置RuntimeCache。RuntimeCache caches a list of pods.该Cache中pod的状态会通过它的两个方法GetPodsForceUpdateIfOlder来更新。
  • 创建PodWorkersklet.podWorkers = newPodWorkers(runtimeCache, klet.syncPod, recorder) 第二个参数将作为podWorker.syncPodFn,即用以sync the desired stated of pod.实现为‵func (kl *Kubelet) syncPod`(定义在pkg/kubelet/kubelet.go)。
  • 在metrics中注册RuntimeCache。 创建目录,默认根目录在/var/lib/kubelet下,并在根目录下创建pods目录和plugins目录。
  • 初始化所有注册的(即可以访问kubelet的)plugin。
  • 建立记录容器的log目录(/var/log/containers)。

至此,所有相关组件或目录文件都已经被创建完毕,该函数返回一个Kubelet实例。

2.2.2 startKubelet

如果读者还记得我们在2.2节中的下段描述,“Step 3: 通过startKubelet启动kubelet,传入参数包括上一个函数的返回值及kcfg。” 那将是一个莫大的幸事,因为我们终于要从一个非常深的源码栈中跳出进入另一个更深的栈了:) 创建完毕kubelet的,下边无疑要进行的是运行操作。

根据运行类别分为两种,其一为RunOnce(只运行一次),其二为startKubelet(持续运行不退出);两种情况本质的处理逻辑是类似的,下面谨以第二种为例进行讲述。

该函数的核心——启动kubelet——由如下一行代码完成,

podCfg.Updates()返回podCfg.updates,类型为<-chan kubelet.PodUpdate,即前述提及的缓冲区为50的用以存储Pod更新信息的channel,让我们来一览其结构。

Kubelet.Run()定义在pkg/kubelet/kubelet.go中,它完成的工作包括

  • 定义kubelet.logServer
  • 如果kl.resourceContainer不为空(命令行参数--resource-container,”Absolute name of the resource-only container to create and run the Kubelet in (Default: “/kubelet.”) ),则将kubelet移入该container中。
  • 启动imageManager。运行时该imageManager负责持续list image和container,并在其Record中更新。
  • 启动cadvisor。
  • 启动containerManager。
  • 启动oomWatcher。
  • 启动周期性更新uptime。
  • 启动statusManager。
  • syncLoop(updates, kl)。

statusManager.StartsyncLoop具体做了什么工作,可能会引起读者的兴趣。下面我们就具体进行分析。为了让结构显得更为明晰,我们还是新起一个小章节:)

2.2.2.1 statusManager的启动

我们知道statusManager负责监听从apiserver对于pod的更新,更新的读写通过podStatusSyncRequest类型的channelpodStatusChannel

statusManager.Start执行核心工作的代码如下

即持续运行s.syncBatch(),这个函数负责同apiserver交互来获得pod status的更新(located @pkg/kubelet/status_manager.go),在没有更新时会block。这是因为在该函数中会等待s.podStatusChannel的返回值。从另一个角度而言,这是在读channel,写channel的操作应该由apiserver完成。

2.2.2.2 syncLoop

syncLoop这个函数使用到了传入的channel参数,即podCfg.updates,第二个参数为kubelet实例本身。它的函数体异常简单,但是却为我们执行了非常重要的sync pod的核心任务。

syncLoopIteration方法在检查各种配置之后,启动select监听updates(channel)上的数据,一旦有更新的数据,则执行podManager.UpdatePods方法,负责update the internal pods with those provided by the update,实际上就是在podManager的列表里进行相应的更新,并进行相应的标记——把每个pod(以types.UID标记)及其SyncPodType记录好(该函数执行完毕后,所有现有的pod的状态都是”sync”)。

然后,则是最为重要的sync pod

handler.SyncPods方法实际为pkg/kubelet/kubelet.go#SyncPods,进行的工作为SyncPods synchronizes the configured list of pods (desired state) with the host current state。具体包括如下步骤:

  1. 根据传入的现存pod列表将statusManager中的不存在的pod entry删除。
  2. 通过admitPods函数过滤terminated& notfitting & outofdisk pods,返回的pod列表即为desired pod。
  3. 对照desired pod列表,进行sync工作,具体是由Kubelet.podWorkers.UpdatePod来完成的。
  4. 把不存在的pod对应的podWorkers释放掉。这里就体现了维护podWorkers.podUpdates这个field的重要性。
  5. 杀死不需要的pod。
  6. 杀死孤儿volume。
  7. 删除不存在的pod对应的dir
  8. 删除孤儿mirror pod

下面我们来具体分析一下第3条Kubelet.podWorkers.UpdatePod进行的工作。

如果该pod在podWorkers.podUpdates里不存在,则需要进行创建,此时调用podWorkers.managePodLoop。 然后,根据podWorkers.isWorking[pod.UID]的值更新对应podUpdates的值或者传入podWorkers.lastUndeliveredWorkUpdate。这是对于对应pod状态的一个记录。

下面我们具体来看一下创建新pod的过程经历了什么。

从代码中可以看到,核心步骤调用了podWorkers.syncPodFn,这是在创建podWorker时构建的,具体指向了func (kl *Kubelet) syncPod(定义在pkg/kubelet/kubelet.go,完整的传参列表

这个函数在做什么呢? Let’s figure it out.

  • canRunPod:确认是否有足够的权限运行该pod。
  • 创建pod data存储的目录,包括root目录(以pod的UID命名)/volumes/plugins(默认在/var/lib/kubelet/pods下)
  • 为pod创建reference
  • mount volume,并且在volumeManager中设置相应的entry。volume是pod的manifest里边的Spec.Volumes下的信息。
  • 更新statusManager中的pod信息。根据传入参数updateType的不同,a)对于create:kl.statusManager.SetPodStatus(pod, podStatus),在statusManager里为新的pod设置StartTime,并且将新的podStatusSyncRequest传给statusManager.podStatusChannel。b)否则,通过kl.containerRuntime.GetPodStatus(pod)获得pod信息(返回值是api.PodStatus )。但是,在现在这个context中,应该为a).
  • 获得inspect pod的manifest中pod.Spec.ImagePullSecrets的信息。(这个secret是用来pull image的)
  • sync pod(在下文中再进行详细论述)
  • 根据该pod是否为static pod,在podManager中进行了相应的设置。

sync pod的过程,以DockerManager.SyncPod为例。有鉴于函数体比较长,在此就不再贴出源码。其功能非常明晰——目的在于使得running pod能够match对应的desired pod。

  • 计算running pod和desired pod之前的差距,返回的信息里包括StartInfraContainer(是否需要创建infra container),InfraContainerId(infra container ID),ContainersToStart(需要start的container),ContainersToKeep(需要keep的container)。
  • 根据返回的信息决定是否重启infra container((即gcr.io/google_containers/pause:0.8.0),配置network及其它container

至此,Kubelet.syncLoopIteration算是基本完成了。这也就意味着kubelet已经在node上运行起来,充当其pod的维护者的角色了。

3. Summary

总之,从宏观角度上而言,kubelet进行的工作就是从apiserver/file/http中获取pod更新的信息,并且定期进行sync pod。其中有大量的工作都涉及了channel的使用,也希望读者在阅读的过程中能够加以注意。

4S: Services Account, Secret, Security Context and Security in Kubernetes

Service Account, Secrets和Security Contexts作为保证kubernetes集群Security的策略被引入,相关代码一直处于快速变更与迭代中。本文谨从design和初级实践的视角对其进行概略性的分析,以飨读者。

文 何思玫

1. 集群安全(Security in Kubernetes)

众所周知,集群安全的首要关注点无疑是隔离性。进程之间的相互隔离,进程与集群基础设施的严格界限,用户与管理员之前的天然角色区分,都应该被考虑到隔离性的范畴内。 统而言之,集群安全性必须考虑如下几个目标: (1) 保证容器与其运行的宿主机的隔离。 (2) 限制容器对于基础设施及其它容器的影响权限,运行拥有特权模式的容器是不被推荐的行为。 (3) 最小权限原则——对所有组件权限的合理限制。 (4) 通过清晰地划分组件的边界来减少需要加固和加以保护的系统组件数量。 (5) 普通用户和管理员的角色区分,同时允许在必要的时候将管理员权限委派给普通用户。 (6) 允许集群上运行的应用拥有secret data。 涉及安全,authentication和authorization是不能绕过的两个话题。下面我们就先来了解一下k8s在这两个issue所提供的支持。

2. Authentication

k8s目前支持三种认证方式,包括certificates/tokens/http basic auth。 client certificate authentication是双向认证的方式,可以经由easyrsa等证书生成工具生成服务器端并客户端证书。 Token authentication:单向认证方式,为kube-apiserver提供- -token_ auth_file,格式为一个有3columns的csv file:token,user name,user id。此处为使用该认证方法的常见的elasticsearch case。 Basic authentication:传入明文用户名密码作为apiserver的启动参数,不支持在不重启apiserver的前提下进行用户名/密码修改。

更多细节详见官方相关文档

3. Authorization

--authorization-mode,apiserver的参数,用于定义对secure port设置何种authorization policy,包括三种AlwaysAllow/AlwayDeny/ABAC,第一种policy允许所有对apiserver的API request,与之相反,第二种则会block所有的API request,第三种则为Attribute-Based Access Control,即对于不同request attribute,有不同的access control。 下面我们着重讨论ABAC mode。

3.1 Request Attributes

在考虑authorization时,一个request有5种attribute需要考虑: – user – group – readOnly – resource(如只访问API endpoint,如/api/v1/namesapces/default/pods,或者其它杂项endpoint,如/version,此时的resource是空字符串) – namespace

3.2 Policy File Format

对于ABAC mode,还需要specify --authorization-policy-file参数,例子参见此处

除此之外,apiserver还可以通过调用Authorizer(interface)来决定是否允许某个API操作。

4. UserAccount

这个概念适用于所有希望与k8s集群交互的个体(通常可以认为是human),因此用户名通常是human-readable,目前并不作为一个代码中的类型单独出现,一般通过config file来读取和感知。

5. Service Account

Service Account概念的引入是基于这样的使用场景:运行在pod里的进程需要调用k8s API(如scheduler/replication controller/minitor system等)以及非k8s API的其它服务(如image repository/被mount到pod上的NFS volumes中的file等)。我们使用Service Account来为pod提供id。 Service Account和第4节中提及的User account可能会带来一定程度上的混淆,下面我们就先从概念的层面将其sort it out。

  • user account通常是为human设计的,而service account则是为跑在pod里的process。
  • user account是global的,即跨namespace使用;而service account是namespaced的,即仅在belonging的namespace下使用。
  • 创建一个新的user account通常需要较高的特权并且需要经过比较复杂的business process(即对于集群的访问权限的创建),而service account则不然。
  • 不同的auditing consideration。
5.1 Design Overview

Service Account包括如下几个元素:

  • name,用以作为id
  • principal,用以authenticated及authorized
  • security context,定义linux capabilities等与系统相关的参数。
  • secrets
5.2 Use Cases

通常我们在使用kubectlbinary来与集群交互时,我们(User Account)都会通过apiserver的认证(如果该集群设置了认证方式的话),可以被看作某个特定的User Account。类似地,当pod希望与apiserver进行交互时,也需要使用特定的认证机制,即Service Account。

当创建pod且没有经过特殊设置时,它将会被默认地分发到该namespace下default的service account,可以通过kubectl get pods/podname -o yaml的命令行查看spec.serviceAccount的field)。

5.2.1 default service account

每个namespace在创建时都会有一个default的service Account,如下所示

5.2.2 Create your own service Account

用户可以方便地通过yaml文件等形式创建自己的serviceAccount,如

通过`kubectl get < resource > -o yaml获取详细信息

可以看到,token(secret)被自动生成并ref了。如果在之后创建pod的时候ref这个自建的serviceAccount,在spec.serviceAccount中指定即可。

通过如下命令可以删除serviceAccount。

5.2.3Adding Secrets to a service account

注意到,我们可以不使用serviceAccount自建的secrets,而是选用我们自己生成的secrets,这是一种consume secret的方式。 首先创建secret,kubectl create -f secret.yaml

然后创建一个comsume该secret,kubectl create -f serviceaccount.yaml

最后在pod的manifest中指定其serviceaccount,kubectl create -f busybox4.yaml

已了解如何创建一个引用自建secret的serviceaccount,但是如果在exsiting serviceaccount中添加引用,目前官方文档mark it as TODO。笔者认为此用法应该与上例类似,但笔者采用这种方式consume secret时,serviceaccount似乎并不对该secret有维护作用。 Update:此用法确与上例类似,参见issue#12012,笔者后续会考虑对相关doc进行更新。

6. Secrets

secret是用于存放sensitive information的数据结构,可以通过manual或者automatic两种方式创建。 secret的use case主要有两种,或者作为volume mount到pod上,或者用于kubelet在为pod里的container拉取镜像时。 使用serviceAccount自建的secret是一种保证secure的推荐方式,当然可以由用户disable或者overridden,如果用户愿意承担额外的风险的话。

6.1 Secrets类型一览

secret的类型目前有三种,如下所示

Opaque类型是默认的用户自建类型,即任意string(实际上也并不是十分任意,data label的key/value必须满足特定的要求:Each key must be a valid DNS_SUBDOMAIN or leading dot followed by valid DNS_SUBDOMAIN. Each value must be a base64 encoded string as described in https://tools.ietf.org/html/rfc4648#section-4)。

第二种类型的例子如下所示

第三种类型一般用于向private registry拉取镜像,在6.3节中再做阐述。

6.2 manually specify a secret

如上述所示,使用kubectl create命令即可创建一个secret。创建完毕之后,可以使用serviceAccount来consume,也可以手动添加到pod的manifest中,如下例所示:

More example here。

6.3 Manually specifying an imagePullSecret

这个方法仅在GKE/GCE或其它cloud-provider场景下推荐使用,创建一个类型为kubernetes.io/dockercfg的secret,并且在pod manifest的imagePullSecrets label下使用。因为缺乏实验平台,在此不作赘述。

总而言之,目前k8s对于secret的support仍处于不十分完善的阶段,secret可能以多种方式暴露给外部用户甚至是attacker。

7. Security context

Security context是用以对容器进行限制,使得不同的运行容器之前能够实现较为明晰的隔离,以及降低其影响宿主机和其它容器的可能性。通俗而言,容器中的security context用于表征在创建及运行容器时,它能够使用及访问的资源参数。 该概念将会被用到如下两处:

  • kubelet用于创建及运行container。
  • 作为serviceAccount的一部分定义在pod中。

这个概念具体如何使用在k8s场景中基本上可以认为在servicAccount中的securityContext label下,目前代码只实现了capabilities和privileged,在此不展开说明。

Google Kubernetes设计文档之安全篇

摘要:Kubernetes是Google开源的容器集群管理系统,构建于Docker之上,为容器化的应用提供资源调度、部署运行、服务发现、扩容缩容等功能。本文为其设计文档系列的第一篇:安全。

1.设计目标

本文讲述了Kubernetes的容器、API和基础设施在安全方面的设计原则。

  1. 保证容器与其运行的宿主机之间有明确的隔离;
  2. 限制容器对基础设施或者其它容器造成不良影响的能力;
  3. 最小特权原则——限定每个组件只被赋予了执行操作所必需的最小特权,由此确保可能产生的损失达到最小;
  4. 通过清晰地划分组件的边界来减少需要加固和加以保护的系统组件数量。

Continue reading