1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

builder: add support for building from tarball

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi 2018-05-17 22:47:34 -07:00
parent 8900e3c758
commit 92395261b0
8 changed files with 123 additions and 13 deletions

View file

@ -3,7 +3,6 @@ package build // import "github.com/docker/docker/api/server/backend/build"
import ( import (
"context" "context"
"fmt" "fmt"
"strings"
"github.com/docker/distribution/reference" "github.com/docker/distribution/reference"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
@ -44,11 +43,7 @@ func NewBackend(components ImageComponent, builder Builder, fsCache *fscache.FSC
// Build builds an image from a Source // Build builds an image from a Source
func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string, error) { func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string, error) {
options := config.Options options := config.Options
useBuildKit := false useBuildKit := options.Version == types.BuilderBuildKit
if strings.HasPrefix(options.SessionID, "buildkit:") {
useBuildKit = true
options.SessionID = strings.TrimPrefix(options.SessionID, "buildkit:")
}
tagger, err := NewTagger(b.imageComponent, config.ProgressWriter.StdoutFormatter, options.Tags) tagger, err := NewTagger(b.imageComponent, config.ProgressWriter.StdoutFormatter, options.Tags)
if err != nil { if err != nil {

View file

@ -146,10 +146,25 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
} }
options.SessionID = r.FormValue("session") options.SessionID = r.FormValue("session")
options.BuildID = r.FormValue("buildid") options.BuildID = r.FormValue("buildid")
builderVersion, err := parseVersion(r.FormValue("version"))
if err != nil {
return nil, err
}
options.Version = builderVersion
return options, nil return options, nil
} }
func parseVersion(s string) (types.BuilderVersion, error) {
if s == "" || s == string(types.BuilderV1) {
return types.BuilderV1, nil
}
if s == string(types.BuilderBuildKit) {
return types.BuilderBuildKit, nil
}
return "", errors.Errorf("invalid version %s", s)
}
func (br *buildRouter) postPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { func (br *buildRouter) postPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
report, err := br.backend.PruneCache(ctx) report, err := br.backend.PruneCache(ctx)
if err != nil { if err != nil {

View file

@ -181,9 +181,18 @@ type ImageBuildOptions struct {
Target string Target string
SessionID string SessionID string
Platform string Platform string
Version BuilderVersion
BuildID string BuildID string
} }
// BuilderVersion sets the version of underlying builder to use
type BuilderVersion string
const (
BuilderV1 BuilderVersion = "1"
BuilderBuildKit = "2"
)
// ImageBuildResponse holds information // ImageBuildResponse holds information
// returned by a server after building // returned by a server after building
// an image. // an image.

View file

@ -17,6 +17,7 @@ import (
"github.com/moby/buildkit/control" "github.com/moby/buildkit/control"
"github.com/moby/buildkit/identity" "github.com/moby/buildkit/identity"
"github.com/moby/buildkit/session" "github.com/moby/buildkit/session"
"github.com/moby/buildkit/util/tracing"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
grpcmetadata "google.golang.org/grpc/metadata" grpcmetadata "google.golang.org/grpc/metadata"
@ -29,20 +30,24 @@ type Opt struct {
} }
type Builder struct { type Builder struct {
controller *control.Controller controller *control.Controller
reqBodyHandler *reqBodyHandler
mu sync.Mutex mu sync.Mutex
jobs map[string]func() jobs map[string]func()
} }
func New(opt Opt) (*Builder, error) { func New(opt Opt) (*Builder, error) {
c, err := newController(opt) reqHandler := newReqBodyHandler(tracing.DefaultTransport)
c, err := newController(reqHandler, opt)
if err != nil { if err != nil {
return nil, err return nil, err
} }
b := &Builder{ b := &Builder{
controller: c, controller: c,
jobs: map[string]func(){}, reqBodyHandler: reqHandler,
jobs: map[string]func(){},
} }
return b, nil return b, nil
} }
@ -133,7 +138,13 @@ func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder.
} }
if opt.Options.RemoteContext != "" { if opt.Options.RemoteContext != "" {
frontendAttrs["context"] = opt.Options.RemoteContext if opt.Options.RemoteContext != "client-session" {
frontendAttrs["context"] = opt.Options.RemoteContext
}
} else {
url, cancel := b.reqBodyHandler.newRequest(opt.Source)
defer cancel()
frontendAttrs["context"] = url
} }
var cacheFrom []string var cacheFrom []string

View file

@ -1,6 +1,7 @@
package buildkit package buildkit
import ( import (
"net/http"
"os" "os"
"path/filepath" "path/filepath"
@ -24,7 +25,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func newController(opt Opt) (*control.Controller, error) { func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
if err := os.MkdirAll(opt.Root, 0700); err != nil { if err := os.MkdirAll(opt.Root, 0700); err != nil {
return nil, err return nil, err
} }
@ -133,6 +134,7 @@ func newController(opt Opt) (*control.Controller, error) {
Exporters: map[string]exporter.Exporter{ Exporters: map[string]exporter.Exporter{
"moby": exp, "moby": exp,
}, },
Transport: rt,
} }
wc := &worker.Controller{} wc := &worker.Controller{}

View file

@ -0,0 +1,74 @@
package buildkit
import (
"bufio"
"io"
"net/http"
"strings"
"sync"
"github.com/moby/buildkit/identity"
"github.com/pkg/errors"
)
const urlPrefix = "build-context-"
type reqBodyHandler struct {
mu sync.Mutex
rt http.RoundTripper
requests map[string]io.ReadCloser
}
func newReqBodyHandler(rt http.RoundTripper) *reqBodyHandler {
return &reqBodyHandler{
rt: rt,
requests: map[string]io.ReadCloser{},
}
}
func (h *reqBodyHandler) newRequest(rc io.ReadCloser) (string, func()) {
// handle expect-continue vs chunked output
r := bufio.NewReader(rc)
r.Peek(1)
id := identity.NewID()
h.mu.Lock()
h.requests[id] = &readCloser{Reader: r, Closer: rc}
h.mu.Unlock()
return "http://" + urlPrefix + id, func() {
h.mu.Lock()
delete(h.requests, id)
h.mu.Unlock()
}
}
func (h *reqBodyHandler) RoundTrip(req *http.Request) (*http.Response, error) {
host := req.URL.Host
if strings.HasPrefix(host, urlPrefix) {
if req.Method != "GET" {
return nil, errors.Errorf("invalid request")
}
id := strings.TrimPrefix(host, urlPrefix)
h.mu.Lock()
rc, ok := h.requests[id]
delete(h.requests, id)
h.mu.Unlock()
if !ok {
return nil, errors.Errorf("context not found")
}
return &http.Response{
Status: "200 OK",
StatusCode: 200,
Body: rc,
ContentLength: -1,
}, nil
}
return h.rt.RoundTrip(req)
}
type readCloser struct {
io.Reader
io.Closer
}

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
nethttp "net/http"
"runtime" "runtime"
"time" "time"
@ -53,6 +54,7 @@ type WorkerOpt struct {
Exporters map[string]exporter.Exporter Exporters map[string]exporter.Exporter
DownloadManager distribution.RootFSDownloadManager DownloadManager distribution.RootFSDownloadManager
V2MetadataService distmetadata.V2MetadataService V2MetadataService distmetadata.V2MetadataService
Transport nethttp.RoundTripper
} }
// Worker is a local worker instance with dedicated snapshotter, cache, and so on. // Worker is a local worker instance with dedicated snapshotter, cache, and so on.
@ -85,6 +87,7 @@ func NewWorker(opt WorkerOpt) (*Worker, error) {
hs, err := http.NewSource(http.Opt{ hs, err := http.NewSource(http.Opt{
CacheAccessor: cm, CacheAccessor: cm,
MetadataStore: opt.MetadataStore, MetadataStore: opt.MetadataStore,
Transport: opt.Transport,
}) })
if err != nil { if err != nil {
return nil, err return nil, err
@ -125,7 +128,7 @@ func (w *Worker) ResolveOp(v solver.Vertex, s frontend.FrontendLLBBridge) (solve
case *pb.Op_Source: case *pb.Op_Source:
return ops.NewSourceOp(v, op, w.SourceManager, w) return ops.NewSourceOp(v, op, w.SourceManager, w)
case *pb.Op_Exec: case *pb.Op_Exec:
return ops.NewExecOp(v, op, w.CacheManager, w.Executor, w) return ops.NewExecOp(v, op, w.CacheManager, w.MetadataStore, w.Executor, w)
case *pb.Op_Build: case *pb.Op_Build:
return ops.NewBuildOp(v, op, s, w) return ops.NewBuildOp(v, op, s, w)
default: default:

View file

@ -136,5 +136,6 @@ func (cli *Client) imageBuildOptionsToQuery(options types.ImageBuildOptions) (ur
if options.BuildID != "" { if options.BuildID != "" {
query.Set("buildid", options.BuildID) query.Set("buildid", options.BuildID)
} }
query.Set("version", string(options.Version))
return query, nil return query, nil
} }