This is the 19th day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021

It has been nearly a month since the State – Definition – Edge was combed. Yuan Xiaobai feels the realization of pure handmade, 24K container operation ecology, is more and more confident!

But then again. What do we see? Why are you looking at these three data structures? What’s next? Yuan Xiaobai suddenly felt facing three final problems in life.

We’re looking at Frontend and we see dockerfile. build, because it’s a long function, it’s about 500 lines long, and we see llb.State in the key place, and to figure out what llb.State does, So it’s time to look at data structures. Now that we’re done, let’s go back to where we were before:

func Build(ctx context.Context, c client.Client) (*client.Result, error){... res := client.NewResult() ...for i, tp := range targetPlatforms {
       func(i int, tp *ocispecs.Platform){... st, img, err := dockerfile2llb.Dockerfile2LLB(...) . }... def, err := st.Marshal(ctx) ... r, err := c.Solve(ctx, client.SolveRequest{ Definition: def.ToPB(), CacheImports: cacheImports, }) ... ref, err := r.SingleRef() ... res.SetRef(ref) ... }...return res, nil
}
Copy the code

Look back at this code, Yuan Xiaobai feel at a glance, refreshed, this feeling is like being through the ren Du two pulse.

  • Through dockerfile2llb dockerfile2llb method, convert dockerfile into the State
  • The returned state-St. Marshal is then converted to def-definition
  • Parse c. solo again, where the c-client is the llbBridge passed in; And the incoming def. ToPB ()
  • Finally, the parsed result is returned

The data structure is not too much of a problem, it helps us understand the 500 lines of code, become a lot easier. Why call llbBridge again this morning? The first parsed parameter is not the same as the first parsed parameter, so the result is not the same.

func (b *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest, sid string) (res *frontend.Result, err error) {
   ifreq.Definition ! =nil&& req.Definition.Def ! =nil&& req.Frontend ! ="" {
      return nil, errors.New("cannot solve with both Definition and Frontend specified")}ifreq.Definition ! =nil&& req.Definition.Def ! =nil {
      res = &frontend.Result{Ref: newResultProxy(b, req)}
      if req.Evaluate {
         _, err := res.Ref.Result(ctx)
         return res, err
      }
   } else ifreq.Frontend ! ="" {
      f, ok := b.frontends[req.Frontend]
      if! ok {return nil, errors.Errorf("invalid frontend: %s", req.Frontend)
      }
      res, err = f.Solve(ctx, b, req.FrontendOpt, req.FrontendInputs, sid, b.sm)
      iferr ! =nil {
         return nil, err
      }
   } else {
      return &frontend.Result{}, nil
   }

   return
}
Copy the code

Req.Definitoin is not null, and req.Frontend is not null. The first time is because req.Frontend is passed in dockerfile.v0. Read from the buildctl build command line argument. This time, the call is made by the Frontend Dockerfile. Build method, and the req.Definition passed in is not empty.

Res = &frontend.Result{Ref: newResultProxy(b, req)} That is, after going all the way around, the Result in bridge.go is returned.

You really screwed yourself up…

Look at the sequence of dragon Fei, I really have to admire, next to see the real Build.

Next: In-depth Understanding of the Moby Buildkit series #21 – It’s time to start building