push container support

Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
This commit is contained in:
Andrea Luzzardi 2021-03-11 16:41:19 -08:00
parent 78236470f7
commit c35eca99e1
6 changed files with 99 additions and 8 deletions

View File

@ -127,8 +127,8 @@ func (c *Client) buildfn(ctx context.Context, env *Env, ch chan *bk.SolveStatus,
Interface("attrs", opts.FrontendAttrs). Interface("attrs", opts.FrontendAttrs).
Msg("spawning buildkit job") Msg("spawning buildkit job")
resp, err := c.c.Build(ctx, opts, "", func(ctx context.Context, c bkgw.Client) (*bkgw.Result, error) { resp, err := c.c.Build(ctx, opts, "", func(ctx context.Context, gw bkgw.Client) (*bkgw.Result, error) {
s := NewSolver(c) s := NewSolver(c.c, gw, ch)
lg.Debug().Msg("loading configuration") lg.Debug().Msg("loading configuration")
if err := env.Update(ctx, s); err != nil { if err := env.Update(ctx, s); err != nil {

View File

@ -7,6 +7,7 @@ import (
"path" "path"
"strings" "strings"
bk "github.com/moby/buildkit/client"
"github.com/moby/buildkit/client/llb" "github.com/moby/buildkit/client/llb"
bkgw "github.com/moby/buildkit/frontend/gateway/client" bkgw "github.com/moby/buildkit/frontend/gateway/client"
bkpb "github.com/moby/buildkit/solver/pb" bkpb "github.com/moby/buildkit/solver/pb"
@ -190,6 +191,25 @@ func (fs FS) Result(ctx context.Context) (*bkgw.Result, error) {
return res, nil return res, nil
} }
func (fs FS) Export(ctx context.Context, output bk.ExportEntry) (*bk.SolveResponse, error) {
// Lazy solve
if err := (&fs).solve(ctx); err != nil {
return nil, err
}
// NOTE: llb.Scratch is represented by a `nil` reference. If solve result is
// Scratch, then `fs.output` is `nil`.
if fs.output == nil {
return nil, os.ErrNotExist
}
st, err := fs.output.ToState()
if err != nil {
return nil, err
}
return fs.s.Export(ctx, st, output)
}
// A helper to remove noise from buildkit error messages. // A helper to remove noise from buildkit error messages.
// FIXME: Obviously a cleaner solution would be nice. // FIXME: Obviously a cleaner solution would be nice.
func bkCleanError(err error) error { func bkCleanError(err error) error {

View File

@ -9,6 +9,7 @@ import (
"strings" "strings"
"github.com/docker/distribution/reference" "github.com/docker/distribution/reference"
bk "github.com/moby/buildkit/client"
"github.com/moby/buildkit/client/llb" "github.com/moby/buildkit/client/llb"
dockerfilebuilder "github.com/moby/buildkit/frontend/dockerfile/builder" dockerfilebuilder "github.com/moby/buildkit/frontend/dockerfile/builder"
bkgw "github.com/moby/buildkit/frontend/gateway/client" bkgw "github.com/moby/buildkit/frontend/gateway/client"
@ -158,6 +159,8 @@ func (p *Pipeline) doOp(ctx context.Context, op *compiler.Value) error {
return p.Export(ctx, op) return p.Export(ctx, op)
case "fetch-container": case "fetch-container":
return p.FetchContainer(ctx, op) return p.FetchContainer(ctx, op)
case "push-container":
return p.PushContainer(ctx, op)
case "fetch-git": case "fetch-git":
return p.FetchGit(ctx, op) return p.FetchGit(ctx, op)
case "local": case "local":
@ -541,6 +544,29 @@ func parseKeyValue(env string) (string, string) {
return parts[0], v return parts[0], v
} }
func (p *Pipeline) PushContainer(ctx context.Context, op *compiler.Value) error {
rawRef, err := op.Get("ref").String()
if err != nil {
return err
}
ref, err := reference.ParseNormalizedNamed(rawRef)
if err != nil {
return fmt.Errorf("failed to parse ref %s: %w", rawRef, err)
}
// Add the default tag "latest" to a reference if it only has a repo name.
ref = reference.TagNameOnly(ref)
_, err = p.fs.Export(ctx, bk.ExportEntry{
Type: bk.ExporterImage,
Attrs: map[string]string{
"name": ref.String(),
"push": "true",
},
})
return err
}
func (p *Pipeline) FetchGit(ctx context.Context, op *compiler.Value) error { func (p *Pipeline) FetchGit(ctx context.Context, op *compiler.Value) error {
remote, err := op.Get("remote").String() remote, err := op.Get("remote").String()
if err != nil { if err != nil {

View File

@ -5,9 +5,12 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
bk "github.com/moby/buildkit/client"
"github.com/moby/buildkit/client/llb" "github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb" "github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb"
bkgw "github.com/moby/buildkit/frontend/gateway/client" bkgw "github.com/moby/buildkit/frontend/gateway/client"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/auth/authprovider"
bkpb "github.com/moby/buildkit/solver/pb" bkpb "github.com/moby/buildkit/solver/pb"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
@ -16,12 +19,16 @@ import (
// Polyfill for buildkit gateway client // Polyfill for buildkit gateway client
// Use instead of bkgw.Client // Use instead of bkgw.Client
type Solver struct { type Solver struct {
c bkgw.Client events chan *bk.SolveStatus
control *bk.Client
gw bkgw.Client
} }
func NewSolver(c bkgw.Client) Solver { func NewSolver(control *bk.Client, gw bkgw.Client, events chan *bk.SolveStatus) Solver {
return Solver{ return Solver{
c: c, events: events,
control: control,
gw: gw,
} }
} }
@ -37,7 +44,7 @@ func (s Solver) Scratch() FS {
} }
func (s Solver) SessionID() string { func (s Solver) SessionID() string {
return s.c.BuildOpts().SessionID return s.gw.BuildOpts().SessionID
} }
func (s Solver) ResolveImageConfig(ctx context.Context, ref string, opts llb.ResolveImageConfigOpt) (dockerfile2llb.Image, error) { func (s Solver) ResolveImageConfig(ctx context.Context, ref string, opts llb.ResolveImageConfigOpt) (dockerfile2llb.Image, error) {
@ -46,7 +53,7 @@ func (s Solver) ResolveImageConfig(ctx context.Context, ref string, opts llb.Res
// Load image metadata and convert to to LLB. // Load image metadata and convert to to LLB.
// Inspired by https://github.com/moby/buildkit/blob/master/frontend/dockerfile/dockerfile2llb/convert.go // Inspired by https://github.com/moby/buildkit/blob/master/frontend/dockerfile/dockerfile2llb/convert.go
// FIXME: this needs to handle platform // FIXME: this needs to handle platform
_, meta, err := s.c.ResolveImageConfig(ctx, ref, opts) _, meta, err := s.gw.ResolveImageConfig(ctx, ref, opts)
if err != nil { if err != nil {
return image, err return image, err
} }
@ -60,7 +67,7 @@ func (s Solver) ResolveImageConfig(ctx context.Context, ref string, opts llb.Res
// Solve will block until the state is solved and returns a Reference. // Solve will block until the state is solved and returns a Reference.
func (s Solver) SolveRequest(ctx context.Context, req bkgw.SolveRequest) (bkgw.Reference, error) { func (s Solver) SolveRequest(ctx context.Context, req bkgw.SolveRequest) (bkgw.Reference, error) {
// call solve // call solve
res, err := s.c.Solve(ctx, req) res, err := s.gw.Solve(ctx, req)
if err != nil { if err != nil {
return nil, bkCleanError(err) return nil, bkCleanError(err)
} }
@ -98,6 +105,38 @@ func (s Solver) Solve(ctx context.Context, st llb.State) (bkgw.Reference, error)
}) })
} }
// Export will export `st` to `output`
// FIXME: this is currently impleneted as a hack, starting a new Build session
// within buildkit from the Control API. Ideally the Gateway API should allow to
// Export directly.
func (s Solver) Export(ctx context.Context, st llb.State, output bk.ExportEntry) (*bk.SolveResponse, error) {
def, err := st.Marshal(ctx, llb.LinuxAmd64)
if err != nil {
return nil, err
}
opts := bk.SolveOpt{
Exports: []bk.ExportEntry{output},
Session: []session.Attachable{
authprovider.NewDockerAuthProvider(log.Ctx(ctx)),
},
}
ch := make(chan *bk.SolveStatus)
go func() {
for event := range ch {
s.events <- event
}
}()
return s.control.Build(ctx, opts, "", func(ctx context.Context, c bkgw.Client) (*bkgw.Result, error) {
return c.Solve(ctx, bkgw.SolveRequest{
Definition: def.ToPB(),
})
}, ch)
}
type llbOp struct { type llbOp struct {
Op bkpb.Op Op bkpb.Op
Digest digest.Digest Digest digest.Digest

1
go.sum
View File

@ -268,6 +268,7 @@ github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r
github.com/docker/docker v17.12.0-ce-rc1.0.20200730172259-9f28837c1d93+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v17.12.0-ce-rc1.0.20200730172259-9f28837c1d93+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.0-beta1.0.20201110211921-af34b94a78a1+incompatible h1:J2OhsbfqoBRRT048iD/tqXBvEQWQATQ8vew6LqQmDSU= github.com/docker/docker v20.10.0-beta1.0.20201110211921-af34b94a78a1+incompatible h1:J2OhsbfqoBRRT048iD/tqXBvEQWQATQ8vew6LqQmDSU=
github.com/docker/docker v20.10.0-beta1.0.20201110211921-af34b94a78a1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.0-beta1.0.20201110211921-af34b94a78a1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=

View File

@ -52,6 +52,11 @@ package dagger
ref: string ref: string
} }
#PushContainer: {
do: "push-container"
ref: string
}
#FetchGit: { #FetchGit: {
do: "fetch-git" do: "fetch-git"
remote: string remote: string