本次文档将接着上次分析,介绍controller对sandbox的管理及sandbox的相关代码的分析。
(三) 管理sandbox
在controller中,有sandboxes字段存储sandbox。
controller中相关函数
controller:NewSandbox()
NewSandbox()可以创建一个新的sandbox。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 
  | func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (sBox Sandbox, err error) { 	if containerID == "" { 		return nil, types.BadRequestErrorf("invalid container ID") 	} 	var sb *sandbox 	c.Lock() 	 	for _, s := range c.sandboxes { 		if s.containerID == containerID { 			 			if !s.isStub { 				sbID := s.ID() 				c.Unlock() 				return nil, types.ForbiddenErrorf("container %s is already present in sandbox %s", containerID, sbID) 			} 			 			 			 			 			sb = s 			sb.isStub = false 			break 		} 	} 	c.Unlock() 	 	 	if sb == nil { 		sb = &sandbox{ 			id:                 stringid.GenerateRandomID(), 			containerID:        containerID, 			endpoints:          epHeap{}, 			epPriority:         map[string]int{}, 			populatedEndpoints: map[string]struct{}{}, 			config:             containerConfig{}, 			controller:         c, 		} 	} 	sBox = sb 	heap.Init(&sb.endpoints) 	sb.processOptions(options...) 	c.Lock() 	if sb.ingress && c.ingressSandbox != nil { 		c.Unlock() 		return nil, types.ForbiddenErrorf("ingress sandbox already present") 	} 	if sb.ingress { 		c.ingressSandbox = sb 		sb.id = "ingress_sbox" 	} 	c.Unlock() 	defer func() { 		if err != nil { 			c.Lock() 			if sb.ingress { 				c.ingressSandbox = nil 			} 			c.Unlock() 		} 	}() 	if err = sb.setupResolutionFiles(); err != nil { 		return nil, err 	} 	 	if sb.config.useDefaultSandBox { 		c.sboxOnce.Do(func() { 			c.defOsSbox, err = osl.NewSandbox(sb.Key(), false, false) 		}) 		if err != nil { 			c.sboxOnce = sync.Once{} 			return nil, fmt.Errorf("failed to create default sandbox: %v", err) 		} 		sb.osSbox = c.defOsSbox 	} 	 	if sb.osSbox == nil && !sb.config.useExternalKey { 		if sb.osSbox, err = osl.NewSandbox(sb.Key(), !sb.config.useDefaultSandBox, false); err != nil { 			return nil, fmt.Errorf("failed to create new osl sandbox: %v", err) 		} 	} 	c.Lock() 	 	c.sandboxes[sb.id] = sb 	c.Unlock() 	defer func() { 		if err != nil { 			c.Lock() 			delete(c.sandboxes, sb.id) 			c.Unlock() 		} 	}() 	 	err = sb.storeUpdate() 	if err != nil { 		return nil, fmt.Errorf("updating the store state of sandbox failed: %v", err) 	} 	return sb, nil } 
  | 
NewSandbox()的流程如下:
- 重名检查;
 
- 构造sandbox结构体值;
 
- 初始化sandbox的endpoints字段;
 
- 处理useDefaultSandBox情况,生成osSbox,并赋值给sb.osSobx,host模式走此分支;
 
- 处理!useExternalKey情况生成osSbox,与useDefaultSandBox不同的是,osl.NewSandbox()传入的有效参数为true;
 
- 把sandbox放入controller的sandboxes中;
 
- 调用sb.storeUpdate()存储sandbox。
 
controller::Sandboxes()
Sandboxes()可以获取controller的sandboxes字段中的sandbox。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 
  | func (c *controller) Sandboxes() []Sandbox { 	c.Lock() 	defer c.Unlock() 	list := make([]Sandbox, 0, len(c.sandboxes)) 	for _, s := range c.sandboxes { 		 		if s.isStub { 			continue 		} 		list = append(list, s) 	} 	return list } 
  | 
controller::WalkSandboxes()
WalkSandboxes()对每一个sandbox做操作,直到walker()返回true。
1 2 3 4 5 6 7 
  | func (c *controller) WalkSandboxes(walker SandboxWalker) { 	for _, sb := range c.Sandboxes() { 		if walker(sb) { 			return 		} 	} } 
  | 
controller::SandboxByID()
SandboxByID()依据id获取sandbox。
1 2 3 4 5 6 7 8 9 10 11 12 13 
  | func (c *controller) SandboxByID(id string) (Sandbox, error) { 	if id == "" { 		return nil, ErrInvalidID(id) 	} 	c.Lock() 	s, ok := c.sandboxes[id] 	c.Unlock() 	if !ok { 		return nil, types.NotFoundErrorf("sandbox %s not found", id) 	} 	return s, nil } 
  | 
controller::SandboxDestroy()
SandboxDestroy()可以依据id删除sandbox。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
  | func (c *controller) SandboxDestroy(id string) error { 	var sb *sandbox 	c.Lock() 	for _, s := range c.sandboxes { 		if s.containerID == id { 			sb = s 			break 		} 	} 	c.Unlock() 	 	if sb == nil { 		return nil 	} 	return sb.Delete() } 
  | 
controller::SandboxContainerWalker()
SandboxContainerWalker()可以返回指定containerID的walker,该walker可以找到与containerID匹配的sandbox,并把sandbox赋给out。
1 2 3 4 5 6 7 8 9 10 
  | func SandboxContainerWalker(out *Sandbox, containerID string) SandboxWalker { 	return func(sb Sandbox) bool { 		if sb.ContainerID() == containerID { 			*out = sb 			return true 		} 		return false 	} } 
  | 
controller::SandboxKeyWalker()
与SandboxContainerWalker()相同,只是比较的是存储Key。
1 2 3 4 5 6 7 8 9 10 
  | func SandboxKeyWalker(out *Sandbox, key string) SandboxWalker { 	return func(sb Sandbox) bool { 		if sb.Key() == key { 			*out = sb 			return true 		} 		return false 	} } 
  | 
Sandbox
再来看下sandbox的定义,Sandbox定义在/libnetwork/sandbox.go中,表示一个net namespace:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 
  | type sandbox struct { 	id                 string 	containerID        string 	config             containerConfig 	extDNS             []string 	osSbox             osl.Sandbox 	controller         *controller 	resolver           Resolver 	resolverOnce       sync.Once 	refCnt             int 	endpoints          epHeap 	epPriority         map[string]int 	populatedEndpoints map[string]struct{} 	joinLeaveDone      chan struct{} 	dbIndex            uint64 	dbExists           bool 	isStub             bool 	inDelete           bool 	ingress            bool 	sync.Mutex } 
  | 
主要字段含义如下:
- id: 随机生成的sandbox号;
 
- containerID: 容器ID;
 
- osSbox: 真正的net namespace;
 
- controller: sandbox所属的controller;
 
- resolver: 容器的DNS域名服务器(因为对swarm不熟悉,所以还不知道为什么不直接设置一个公共的域名服务器);
 
- endpoints: 该sandbox中绑定的endpoint,endpoints的类型是epHeap,但实际上是[]*endpoint;
 
- epPriority: endpoints的优先级;
 
sandbox::ID()
ID()可以返回sandbox的id。
1 2 3 4 
  | func (sb *sandbox) ID() string { 	return sb.id } 
  | 
sandbox::ContainerID()
ContainerID()可以返回sandbox的containerID。
1 2 3 4 
  | func (sb *sandbox) ContainerID() string { 	return sb.containerID } 
  | 
sandbox::Key()
Key()可以返回该sandbox的存储key。
1 2 3 4 5 6 
  | func (sb *sandbox) Key() string { 	if sb.config.useDefaultSandBox { 		return osl.GenerateKey("default") 	} 	return osl.GenerateKey(sb.id) } 
  | 
sandbox::Delete()
Delete()可以删除本sandbox。Delete()调用了delete(),delete()的流程如下:
- 标识inDelete,表示该sandbox在删除中;
 
- 释放绑定的endpoints;
 
- 停止resolver;
 
- 移除osSbox,即真正的net namespace;
 
- 从store中删除;
 
- 从controller中删除该sandbox。
 
其中步骤2通过调用endpoint的Leave()和Delete()完成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 
  | func (sb *sandbox) Delete() error { 	return sb.delete(false) } func (sb *sandbox) delete(force bool) error { 	sb.Lock() 	if sb.inDelete { 		sb.Unlock() 		return types.ForbiddenErrorf("another sandbox delete in progress") 	} 	 	 	 	 	 	 	 	 	sb.inDelete = true 	sb.Unlock() 	 	c := sb.controller 	 	 	retain := false 	for _, ep := range sb.getConnectedEndpoints() { 		 		if ep.endpointInGWNetwork() && !force { 			continue 		} 		 		if _, err := c.getNetworkFromStore(ep.getNetwork().ID()); err != nil { 			if c.isDistributedControl() { 				retain = true 			} 			log.Warnf("Failed getting network for ep %s during sandbox %s delete: %v", ep.ID(), sb.ID(), err) 			continue 		} 		if !force { 			if err := ep.Leave(sb); err != nil { 				log.Warnf("Failed detaching sandbox %s from endpoint %s: %v\n", sb.ID(), ep.ID(), err) 			} 		} 		if err := ep.Delete(force); err != nil { 			log.Warnf("Failed deleting endpoint %s: %v\n", ep.ID(), err) 		} 	} 	if retain { 		sb.Lock() 		sb.inDelete = false 		sb.Unlock() 		return fmt.Errorf("could not cleanup all the endpoints in container %s / sandbox %s", sb.containerID, sb.id) 	} 	 	 	etchosts.Drop(sb.config.hostsPath) 	 	if sb.resolver != nil { 		sb.resolver.Stop() 	} 	 	if sb.osSbox != nil && !sb.config.useDefaultSandBox { 		sb.osSbox.Destroy() 	} 	 	if err := sb.storeDelete(); err != nil { 		log.Warnf("Failed to delete sandbox %s from store: %v", sb.ID(), err) 	} 	c.Lock() 	if sb.ingress { 		c.ingressSandbox = nil 	} 	 	delete(c.sandboxes, sb.ID()) 	c.Unlock() 	return nil } 
  | 
sandbox::Rename()
Rename()可以更改绑定的endpoint的name,但现在还不知道为什么要更改名字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 
  | func (sb *sandbox) Rename(name string) error { 	var err error 	for _, ep := range sb.getConnectedEndpoints() { 		if ep.endpointInGWNetwork() { 			continue 		} 		oldName := ep.Name() 		lEp := ep 		if err = ep.rename(name); err != nil { 			break 		} 		defer func() { 			if err != nil { 				lEp.rename(oldName) 			} 		}() 	} 	return err } 
  | 
sandbox::Refresh()
Refresh()先解绑所有的endpoint,重新配置后再绑定之前的endpoint。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 
  | func (sb *sandbox) Refresh(options ...SandboxOption) error { 	 	epList := sb.getConnectedEndpoints() 	 	for _, ep := range epList { 		if err := ep.Leave(sb); err != nil { 			log.Warnf("Failed detaching sandbox %s from endpoint %s: %v\n", sb.ID(), ep.ID(), err) 		} 	} 	 	sb.config = containerConfig{} 	sb.processOptions(options...) 	 	if err := sb.setupResolutionFiles(); err != nil { 		return err 	} 	 	for _, ep := range epList { 		if err := ep.Join(sb); err != nil { 			log.Warnf("Failed attach sandbox %s to endpoint %s: %v\n", sb.ID(), ep.ID(), err) 		} 	} 	return nil } 
  | 
sandbox::Endpoints()
Endpoints()可以返回sandbox中所有的endpoint,返回的类型是Endpoint interface。
1 2 3 4 5 6 7 8 9 10 11 
  | func (sb *sandbox) Endpoints() []Endpoint { 	sb.Lock() 	defer sb.Unlock() 	endpoints := make([]Endpoint, len(sb.endpoints)) 	for i, ep := range sb.endpoints { 		endpoints[i] = ep 	} 	return endpoints } 
  | 
sandbox::getConnectedEndpoints()
和Endpoints()一样,只是返回的类型为endpoint。
1 2 3 4 5 6 7 8 9 10 11 12 
  | func (sb *sandbox) getConnectedEndpoints() []*endpoint { 	sb.Lock() 	defer sb.Unlock() 	eps := make([]*endpoint, len(sb.endpoints)) 	for i, ep := range sb.endpoints { 		eps[i] = ep 	} 	return eps } 
  | 
sandbox::removeEndpoint()
removeEndpoint()从sandbox中移除endpoint。
1 2 3 4 5 6 7 8 9 10 11 12 
  | func (sb *sandbox) removeEndpoint(ep *endpoint) { 	sb.Lock() 	defer sb.Unlock() 	for i, e := range sb.endpoints { 		if e == ep { 			heap.Remove(&sb.endpoints, i) 			return 		} 	} } 
  | 
sandbox::execFunc()
execFunc()可以在net namespace中执行命令。
1 2 3 
  | func (sb *sandbox) execFunc(f func()) error { 	return sb.osSbox.InvokeFunc(f) } 
  | 
其他
ResolveName(): 通过name获取ip;
ResolveIP(): 通过ip获取name;
SetKey(): 更新sandbox key,当使用外来的net namespace时使用,将在controller的监听unix socket中详细分析。