71.garbage
PR # 2022
type ByCreated []*docker.Container
func (a ByCreated) Len() int { return len(a) }
func (a ByCreated) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByCreated) Less(i, j int) bool { return a[i].Created.After(a[j].Created) }
// TODO: these removals are racy, we should make dockerclient threadsafe across List/Inspect transactions.
func (kl *Kubelet) purgeOldest(ids []string) error {
dockerData := []*docker.Container{}
for _, id := range ids {
data, err := kl.dockerClient.InspectContainer(id)
if err != nil {
return err
}
if !data.State.Running && (kl.minimumGCAge == 0 || time.Now().Sub(data.State.FinishedAt) > kl.minimumGCAge) {
dockerData = append(dockerData, data)
}
}
sort.Sort(ByCreated(dockerData))
if len(dockerData) <= kl.maxContainerCount {
return nil
}
dockerData = dockerData[kl.maxContainerCount:]
for _, data := range dockerData {
if err := kl.dockerClient.RemoveContainer(docker.RemoveContainerOptions{ID: data.ID}); err != nil {
return err
}
}
return nil
}
// TODO: Also enforce a maximum total number of containers.
func (kl *Kubelet) GarbageCollectContainers() error {
if kl.maxContainerCount == 0 {
return nil
}
containers, err := dockertools.GetKubeletDockerContainers(kl.dockerClient, true)
if err != nil {
return err
}
uuidToIDMap := map[string][]string{}
for _, container := range containers {
_, uuid, name, _ := dockertools.ParseDockerName(container.ID)
uuidName := uuid + "." + name
uuidToIDMap[uuidName] = append(uuidToIDMap[uuidName], container.ID)
}
for _, list := range uuidToIDMap {
if len(list) <= kl.maxContainerCount {
continue
}
if err := kl.purgeOldest(list); err != nil {
return err
}
}
return nil
}
首先,定义了一个名为ByCreated的类型,它是一个装有指向docker.Container的指针的切片。并且,对这个类型实现了 sort 接口,可以根据容器的创建时间进行排序。
purgeOldest函数的主要功能是清理最旧的容器。首先获取所有指定 ID 的容器的信息,并筛选出非运行状态的容器,如果这些容器结束运行的时间超过了设置的最小垃圾回收年龄,就会将这些容器的信息添加到dockerData切片中。然后,将dockerData按照创建时间排序。如果dockerData的长度小于或等于设定的最大容器数,则不需要进行清理。否则,移除排序后超出最大容器数的部分的容器。
GarbageCollectContainers函数是 Kubelet 的容器垃圾回收主要函数。首先,它获取所有由 Kubelet 创建的 Docker 容器,并将这些容器按照 UUID 和名字分类,每一类容器的容器 ID 会被放在一个切片中。然后,对每个 UUID-Name 分类的切片,如果长度大于最大容器数,就调用purgeOldest函数进行清理。
注意,这段代码中提到了两个 TODO,一个是在purgeOldest函数中,提到了对 Docker 客户端进行线程安全的改进。另一个是在GarbageCollectContainers函数中,提到了增加对总容器数量的限制。
PR # 1949
Serve API version list on /api, test with an integration test.
// APIVersionHandler returns a handler which will list the provided versions as available.
func APIVersionHandler(versions ...string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
writeRawJSON(http.StatusOK, version.APIVersions{Versions: versions}, w)
})
}
PR # 2009
Unify Accessor for ObjectMeta/TypeMeta/ListMeta
// MetadataAccessor lets you work with object metadata from any of the versioned or
// internal API objects.
type MetadataAccessor interface {
APIVersion(obj runtime.Object) (string, error)
SetAPIVersion(obj runtime.Object, version string) error
Kind(obj runtime.Object) (string, error)
SetKind(obj runtime.Object, kind string) error
Namespace(obj runtime.Object) (string, error)
SetNamespace(obj runtime.Object, namespace string) error
Name(obj runtime.Object) (string, error)
SetName(obj runtime.Object, name string) error
UID(obj runtime.Object) (string, error)
SetUID(obj runtime.Object, uid string) error
SelfLink(obj runtime.Object) (string, error)
SetSelfLink(obj runtime.Object, selfLink string) error
runtime.ResourceVersioner
}
PR # 2055
Make DataVersionAndKind public on runtime.Scheme
PR #1847
Add basic authorization
// Authorizer makes an authorization decision based on information gained by making // zero or more calls to methods of the Attributes interface. It returns nil when an action is // authorized, otherwise it returns an error. type Authorizer interface { Authorize(a Attributes) (err error) }
PR #2059
Define a mapping between REST resource name and kind/apiVersion
type DefaultRESTMapper struct {
mapping map[string]typeMeta
reverse map[typeMeta]string
versions []string
interfacesFunc VersionInterfacesFunc
例子 :
假设我们有一个资源称为"Pod",我们想要将其添加到映射中,并且我们有两个版本v1beta1
和v1beta3
。
使用旧的命名约定(v1beta1/v1beta2
),"Pod" 的资源名称是 "Pod" (驼峰命名法) 和 "pod" (小写)。而在v1beta3
以及之后的版本中,它应该是 "pods" (小写、复数)。
// 创建一个DefaultRESTMapper实例
mapper := &DefaultRESTMapper{
mapping: make(map[string]typeMeta),
reverse: make(map[typeMeta]string),
}
// 创建一个简化的Scheme实例,它知道"Pod"这种类型存在于v1beta1和v1beta3版本中
scheme := ... // 此处简化,实际上应该有一个包含这些信息的Scheme
// 使用Add方法将Pod资源添加到映射中
mapper.Add(scheme, true, "v1beta1", "v1beta3")
// 在执行完上面的代码后,我们可以预期mapper中的映射会有以下条目:
// "Pod" -> {APIVersion: "v1beta1", Kind: "Pod"}
// "pod" -> {APIVersion: "v1beta1", Kind: "Pod"}
// "pods" -> {APIVersion: "v1beta3", Kind: "Pod"}
上述的mapper
对象现在就知道如何将资源名称"Pod", "pod", 和 "pods"映射到其对应的种类(Kind)和API版本。
PR #2117
Use user-string in authentication attributes.
func (r *requestAttributeGetter) GetAttribs(req *http.Request) authorizer.Attributes {
attribs := authorizer.AttributesRecord{}
user, ok := r.userContexts.Get(req)
if ok {
attribs.User = user
}
return &attribs
}