本次文档将接着上次分析,介绍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中详细分析。