这是我参加11月更文挑战的第21天,活动概况查看:2021最后一次更文挑战

为了加强自己的了解,袁小白像以往相同,梳理了下流程图

深入理解Moby Buildkit系列 #21 - 是时候开始Build了

  1. solver接受到恳求后,在Solve办法中调用Bridge的Solve办法,开端解析
  2. 在bridge中调用Frontend进行解析,这儿的Frontend便是dockerfile
  3. 在dockerfile Frontend中,又调用了bridge的Solve办法,这一次和第一步不相同的当地在于传入的参数,这一次是传入了现已解析好的Definition
  4. 创立署理成果,由于这个时候并没有得到真实的构建成果,只是把中间所需求的对象都安排好,比方这儿预备的实践上是frontend.Result.Ref
  5. 预备好newResultProxy,回来第一步Solve的成果res
  6. 得到Frontend Solve的成果res后,加载署理成果的Result
  7. 实践调用的是创立代码成果的回调函数pr.cb – proxyResult.callBack
  8. 署理成果中实践恳求的是llbBridge.loadResult
  9. loadResult中先调用的是Load,注意,这儿的Load和咱们之前见到的相同,是将Definition转换为Edge。这儿Edge第一次呈现了
  10. 真实的Build开端了,而且呈现了一个新的文件 – jobs.go

源码是:

res, bi, err := b.builder.Build(ctx, edge)

b便是llbBridge实例,那b.builder是什么呢? 从上面流程图中可以知道,在第一步时,solver的Solve办法中,调用了Bridge的Solve:

res, err = s.Bridge(j).Solve(ctx, req, sessionID)

这儿是bridge实例化的当地:

func (s *Solver) Bridge(b solver.Builder) frontend.FrontendLLBBridge {
   return &llbBridge{
      builder:                   b,
      frontends:                 s.frontends,
      resolveWorker:             s.resolveWorker,
      eachWorker:                s.eachWorker,
      resolveCacheImporterFuncs: s.resolveCacheImporterFuncs,
      cms:                       map[string]solver.CacheManager{},
      sm:                        s.sm,
   }
}

传入的参数便是便是builder,再看这个j

j, err := s.solver.NewJob(id)

再继续打开:

func (jl *Solver) NewJob(id string) (*Job, error) {
   jl.mu.Lock()
   defer jl.mu.Unlock()
   if _, ok := jl.jobs[id]; ok {
      return nil, errors.Errorf("job ID %s exists", id)
   }
   pr, ctx, progressCloser := progress.NewContext(context.Background())
   pw, _, _ := progress.NewFromContext(ctx) // TODO: expose progress.Pipe()
   _, span := trace.NewNoopTracerProvider().Tracer("").Start(ctx, "")
   j := &Job{
      list:           jl,
      pr:             progress.NewMultiReader(pr),
      pw:             pw,
      progressCloser: progressCloser,
      span:           span,
      id:             id,
   }
   jl.jobs[id] = j
   jl.updateCond.Broadcast()
   return j, nil
}

可以看到,这儿有一个list,用来存储新创立的job,回来的j中有对应的list引证。 在回来前咱们还看到了jl.updateCond.Broadcast(),应该是向组内其它job进行广播,有新成员加入了。

绕了一圈回来,咱们找到了真实Build开端的当地 – jobs.Build:

func (j *Job) Build(ctx context.Context, e Edge) (CachedResult, BuildInfo, error) {
   if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() {
      j.span = span
   }
   v, err := j.list.load(e.Vertex, nil, j)
   if err != nil {
      return nil, nil, err
   }
   e.Vertex = v
   res, err := j.list.s.build(ctx, e)
   if err != nil {
      return nil, nil, err
   }
   j.list.mu.Lock()
   defer j.list.mu.Unlock()
   return res, j.walkBuildInfo(ctx, e, make(BuildInfo)), nil
}

其中有两句招引了袁小白的注意:

  • j.list.load
  • j.list.s.build

不知道要用什么样的姿态,才干正确打开jobs的load和s.build

下一篇:深化了解Moby Buildkit系列 #22 – jobs的国际