【Kubernetes in Action读书笔记】4.3 使用ReplicaSet

167 阅读3分钟

【Kubernetes in Action读书笔记】4.3 使用ReplicaSet

据说ReplicationController最终将被弃用,所以跳过4.2节。

ReplicaSet能够保障所管理的Pod的数量总是与预期的数量一致

相较于ReplicationController,ReplicaSet的Pod选择器的表达能力更强。

ReplicaSet的yaml的示例

apiVersion: apps/v1beta2
kind: ReplicaSet
metadata:
    name: kubia
spec:
    replicas: 3
    selector:
        matchLabels:
            app: kubia
        matchExpressions:
            - key: env, 
              operator: In, 
              values:
                - prod
                - qa
...

选择器selector相关代码

相关文件

  • staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/types.go
  • staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/helpers.go
  • staging/src/k8s.io/apimachinery/pkg/labels/selector.go

yaml文件中的配置项spec.selector.matchLabelsspec.selector.matchExpressions对应的类型

// staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/types.go

// A label selector is a label query over a set of resources.
type LabelSelector struct {
	// matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
	// map is equivalent to an element of matchExpressions, whose key field is "key", the
	// operator is "In", and the values array contains only "value". The requirements are ANDed.
	MatchLabels      map[string]string
  
	// matchExpressions is a list of label selector requirements. The requirements are ANDed.
	MatchExpressions []LabelSelectorRequirement
}


// A label selector requirement is a selector that contains values, a key, and an operator that
// relates the key and values.
type LabelSelectorRequirement struct {
	Key 			string
  
	// operator represents a key's relationship to a set of values.
	// Valid operators are In, NotIn, Exists and DoesNotExist.
	Operator 	LabelSelectorOperator

	Values 		[]string
}

// A label selector operator is the set of operators that can be used in a selector requirement.
type LabelSelectorOperator string

每一个选择器(selector中的元素)都对应一个Requirement类型的值

// staging/src/k8s.io/apimachinery/pkg/labels/selector.go
// Requirements is AND of all requirements.
type Requirements []Requirement

// Selector represents a label selector.
type Selector interface {
  ...

LabelSelectorAsSelector()LabelSelector类型转换为实现了接口labels.Selector的类型——type internalSelector []Requirement——一组Requirement

// staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/helpers.go

// LabelSelectorAsSelector converts the LabelSelector api type into a struct that implements
// labels.Selector
// ...
func LabelSelectorAsSelector(ps *LabelSelector) (labels.Selector, error) {
  // ...
  for k, v := range ps.MatchLabels {
		r, err := labels.NewRequirement(k, selection.Equals, []string{v})	// ①
		// ...
		requirements = append(requirements, *r)
	}
	for _, expr := range ps.MatchExpressions {
		// ...
		r, err := labels.NewRequirement(expr.Key, op, append([]string(nil), expr.Values...))//②
		// ...
		requirements = append(requirements, *r)
	}
	selector := labels.NewSelector() // ③
	selector = selector.Add(requirements...)
	return selector, nil
}

// ...

// Add adds requirements to the selector. It copies the current selector returning a new one
func (s internalSelector) Add(reqs ...Requirement) Selector {
	ret := make(internalSelector, 0, len(s)+len(reqs))
	ret = append(ret, s...)
	ret = append(ret, reqs...)
	sort.Sort(ByKey(ret))
	return ret
}
  • ① 将spec.selector.matchLabels配置项中的元素一一转换成*labels.Requirement

  • ② 将spec.selector.matchExpressions配置项中的元素也一一转换成*labels.Requirement

  • ③ 创建实现了接口labels.Selector的类型internalSelector的变量selector。该类型实际上是[]Requirement的别名

检测Requirement是否匹配给定的标签lable

// staging/src/k8s.io/apimachinery/pkg/labels/selector.go
func (s internalSelector) Matches(l Labels) bool {
	for ix := range s {
		if matches := s[ix].Matches(l); !matches {
			return false
		}
	}
	return true
}

func (r *Requirement) Matches(ls Labels) bool {
	switch r.operator {
	case selection.In, selection.Equals, selection.DoubleEquals:
		// ...
	case selection.NotIn, selection.NotEquals:
		// ...
	case selection.Exists:
    // ...

直接通过switch case处理,不是用Requirement的“子类”,用多态的Matches()方法。

待确认:这里Labels是复数,但从注释里看Labels似乎又代表1个标签

// Labels allows you to present labels independently from their storage.
type Labels interface {
	// Has returns whether the provided label exists.
	Has(label string) (exists bool)

	// Get returns the value for the provided label.
	Get(label string) (value string)
}

会不会名词复数是一种接口命名风格

nothingSelector与Rust中的基元型结构体

另外,nothingSelector类似Rust中的基元型结构体(Unit-like structs)

// staging/src/k8s.io/apimachinery/pkg/labels/selector.go
type nothingSelector struct{}

func (n nothingSelector) Matches(_ Labels) bool              { return false }
func (n nothingSelector) Empty() bool                        { return false }
func (n nothingSelector) String() string                     { return "" }
func (n nothingSelector) Add(_ ...Requirement) Selector      { return n }
func (n nothingSelector) Requirements() (Requirements, bool) { return nil, false }
// ...

// Sharing this saves 1 alloc per use; this is safe because it's immutable.
var sharedNothingSelector Selector = nothingSelector{}

似乎即使每次使用时都在堆上(无论用new还是&)创建了“新的”nothingSelector的值,Go也只会在内存中存储一份该类型的值。

type nothingSelector struct{}

func main() {
	fmt.Printf("%p\n", new(nothingSelector))	// 0x54e3a0
	fmt.Printf("%p\n", new(nothingSelector))	// 0x54e3a0
	fmt.Printf("%p\n", &nothingSelector{})		// 0x54e3a0
}

4.3节翻译错误的地方

P104 4.3节 第1段

最初,ReplicationController是用于复制和在异常时重新调度节点的唯一Kubernetes组件,……

Initially, ReplicationControllers were the only Kubernetes component for replicating pods and rescheduling them when nodes failed.

“复制”和“重新调度”的对象都是Pod