Skip to content

Commit

Permalink
Merge pull request #44079 from thaJeztah/c8d_build
Browse files Browse the repository at this point in the history
containerd integration: Make build work
  • Loading branch information
thaJeztah committed Mar 7, 2023
2 parents f61142c + f8b468f commit b3428bc
Show file tree
Hide file tree
Showing 122 changed files with 17,370 additions and 63 deletions.
46 changes: 31 additions & 15 deletions builder/builder-next/builder.go
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/builder"
mobyexporter "github.com/docker/docker/builder/builder-next/exporter"
"github.com/docker/docker/builder/builder-next/exporter/overrides"
"github.com/docker/docker/daemon/config"
"github.com/docker/docker/daemon/images"
"github.com/docker/docker/libnetwork"
Expand Down Expand Up @@ -77,6 +79,10 @@ type Opt struct {
IdentityMapping idtools.IdentityMapping
DNSConfig config.DNSConfig
ApparmorProfile string
UseSnapshotter bool
Snapshotter string
ContainerdAddress string
ContainerdNamespace string
}

// Builder can build using BuildKit backend
Expand All @@ -85,15 +91,16 @@ type Builder struct {
dnsconfig config.DNSConfig
reqBodyHandler *reqBodyHandler

mu sync.Mutex
jobs map[string]*buildJob
mu sync.Mutex
jobs map[string]*buildJob
useSnapshotter bool
}

// New creates a new builder
func New(opt Opt) (*Builder, error) {
func New(ctx context.Context, opt Opt) (*Builder, error) {
reqHandler := newReqBodyHandler(tracing.DefaultTransport)

c, err := newController(reqHandler, opt)
c, err := newController(ctx, reqHandler, opt)
if err != nil {
return nil, err
}
Expand All @@ -102,6 +109,7 @@ func New(opt Opt) (*Builder, error) {
dnsconfig: opt.DNSConfig,
reqBodyHandler: reqHandler,
jobs: map[string]*buildJob{},
useSnapshotter: opt.UseSnapshotter,
}
return b, nil
}
Expand Down Expand Up @@ -202,8 +210,11 @@ func (b *Builder) Prune(ctx context.Context, opts types.BuildCachePruneOptions)

// Build executes a build request
func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder.Result, error) {
var rc = opt.Source
if len(opt.Options.Outputs) > 1 {
return nil, errors.Errorf("multiple outputs not supported")
}

var rc = opt.Source
if buildID := opt.Options.BuildID; buildID != "" {
b.mu.Lock()

Expand Down Expand Up @@ -333,11 +344,12 @@ func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder.

exporterName := ""
exporterAttrs := map[string]string{}

if len(opt.Options.Outputs) > 1 {
return nil, errors.Errorf("multiple outputs not supported")
} else if len(opt.Options.Outputs) == 0 {
exporterName = "moby"
if len(opt.Options.Outputs) == 0 {
if b.useSnapshotter {
exporterName = client.ExporterImage
} else {
exporterName = mobyexporter.Moby
}
} else {
// cacheonly is a special type for triggering skipping all exporters
if opt.Options.Outputs[0].Type != "cacheonly" {
Expand All @@ -346,14 +358,18 @@ func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder.
}
}

if exporterName == "moby" {
if len(opt.Options.Tags) > 0 {
exporterAttrs["name"] = strings.Join(opt.Options.Tags, ",")
if (exporterName == client.ExporterImage || exporterName == mobyexporter.Moby) && len(opt.Options.Tags) > 0 {
nameAttr, err := overrides.SanitizeRepoAndTags(opt.Options.Tags)
if err != nil {
return nil, err
}
if exporterAttrs == nil {
exporterAttrs = make(map[string]string)
}
exporterAttrs["name"] = strings.Join(nameAttr, ",")
}

cache := controlapi.CacheOptions{}

if inlineCache := opt.Options.BuildArgs["BUILDKIT_INLINE_CACHE"]; inlineCache != nil {
if b, err := strconv.ParseBool(*inlineCache); err == nil && b {
cache.Exports = append(cache.Exports, &controlapi.CacheOptionsEntry{
Expand Down Expand Up @@ -385,7 +401,7 @@ func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder.
if err != nil {
return err
}
if exporterName != "moby" {
if exporterName != mobyexporter.Moby && exporterName != client.ExporterImage {
return nil
}
id, ok := resp.ExporterResponse["containerimage.digest"]
Expand Down
140 changes: 123 additions & 17 deletions builder/builder-next/controller.go
Expand Up @@ -5,7 +5,9 @@ import (
"net/http"
"os"
"path/filepath"
"time"

ctd "github.com/containerd/containerd"
"github.com/containerd/containerd/content/local"
ctdmetadata "github.com/containerd/containerd/metadata"
"github.com/containerd/containerd/snapshots"
Expand All @@ -14,7 +16,8 @@ import (
"github.com/docker/docker/builder/builder-next/adapters/containerimage"
"github.com/docker/docker/builder/builder-next/adapters/localinlinecache"
"github.com/docker/docker/builder/builder-next/adapters/snapshot"
containerimageexp "github.com/docker/docker/builder/builder-next/exporter"
"github.com/docker/docker/builder/builder-next/exporter"
"github.com/docker/docker/builder/builder-next/exporter/mobyexporter"
"github.com/docker/docker/builder/builder-next/imagerefchecker"
mobyworker "github.com/docker/docker/builder/builder-next/worker"
"github.com/docker/docker/daemon/config"
Expand All @@ -23,8 +26,10 @@ import (
"github.com/moby/buildkit/cache"
"github.com/moby/buildkit/cache/metadata"
"github.com/moby/buildkit/cache/remotecache"
"github.com/moby/buildkit/cache/remotecache/gha"
inlineremotecache "github.com/moby/buildkit/cache/remotecache/inline"
localremotecache "github.com/moby/buildkit/cache/remotecache/local"
registryremotecache "github.com/moby/buildkit/cache/remotecache/registry"
"github.com/moby/buildkit/client"
bkconfig "github.com/moby/buildkit/cmd/buildkitd/config"
"github.com/moby/buildkit/control"
Expand All @@ -37,13 +42,122 @@ import (
"github.com/moby/buildkit/util/archutil"
"github.com/moby/buildkit/util/entitlements"
"github.com/moby/buildkit/util/leaseutil"
"github.com/moby/buildkit/util/network/netproviders"
"github.com/moby/buildkit/worker"
"github.com/moby/buildkit/worker/containerd"
"github.com/moby/buildkit/worker/label"
"github.com/pkg/errors"
"go.etcd.io/bbolt"
bolt "go.etcd.io/bbolt"
)

func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
func newController(ctx context.Context, rt http.RoundTripper, opt Opt) (*control.Controller, error) {
if opt.UseSnapshotter {
return newSnapshotterController(ctx, rt, opt)
}
return newGraphDriverController(ctx, rt, opt)
}

func newSnapshotterController(ctx context.Context, rt http.RoundTripper, opt Opt) (*control.Controller, error) {
if err := os.MkdirAll(opt.Root, 0o711); err != nil {
return nil, err
}

historyDB, historyConf, err := openHistoryDB(opt.Root, opt.BuilderConfig.History)
if err != nil {
return nil, err
}

cacheStorage, err := bboltcachestorage.NewStore(filepath.Join(opt.Root, "cache.db"))
if err != nil {
return nil, err
}

nc := netproviders.Opt{
Mode: "host",
}
dns := getDNSConfig(opt.DNSConfig)

wo, err := containerd.NewWorkerOpt(opt.Root, opt.ContainerdAddress, opt.Snapshotter, opt.ContainerdNamespace,
opt.Rootless, map[string]string{
label.Snapshotter: opt.Snapshotter,
}, dns, nc, opt.ApparmorProfile, false, nil, "", ctd.WithTimeout(60*time.Second))
if err != nil {
return nil, err
}

policy, err := getGCPolicy(opt.BuilderConfig, opt.Root)
if err != nil {
return nil, err
}

wo.GCPolicy = policy
wo.RegistryHosts = opt.RegistryHosts

exec, err := newExecutor(opt.Root, opt.DefaultCgroupParent, opt.NetworkController, dns, opt.Rootless, opt.IdentityMapping, opt.ApparmorProfile)
if err != nil {
return nil, err
}
wo.Executor = exec

w, err := mobyworker.NewContainerdWorker(ctx, wo)
if err != nil {
return nil, err
}

wc := &worker.Controller{}

err = wc.Add(w)
if err != nil {
return nil, err
}
frontends := map[string]frontend.Frontend{
"dockerfile.v0": forwarder.NewGatewayForwarder(wc, dockerfile.Build),
"gateway.v0": gateway.NewGatewayFrontend(wc),
}

return control.NewController(control.Opt{
SessionManager: opt.SessionManager,
WorkerController: wc,
Frontends: frontends,
CacheKeyStorage: cacheStorage,
ResolveCacheImporterFuncs: map[string]remotecache.ResolveCacheImporterFunc{
"gha": gha.ResolveCacheImporterFunc(),
"local": localremotecache.ResolveCacheImporterFunc(opt.SessionManager),
"registry": registryremotecache.ResolveCacheImporterFunc(opt.SessionManager, wo.ContentStore, opt.RegistryHosts),
},
ResolveCacheExporterFuncs: map[string]remotecache.ResolveCacheExporterFunc{
"gha": gha.ResolveCacheExporterFunc(),
"inline": inlineremotecache.ResolveCacheExporterFunc(),
"local": localremotecache.ResolveCacheExporterFunc(opt.SessionManager),
"registry": registryremotecache.ResolveCacheExporterFunc(opt.SessionManager, opt.RegistryHosts),
},
Entitlements: getEntitlements(opt.BuilderConfig),
HistoryDB: historyDB,
HistoryConfig: historyConf,
LeaseManager: wo.LeaseManager,
ContentStore: wo.ContentStore,
})
}

func openHistoryDB(root string, cfg *config.BuilderHistoryConfig) (*bolt.DB, *bkconfig.HistoryConfig, error) {
db, err := bbolt.Open(filepath.Join(root, "history.db"), 0o600, nil)
if err != nil {
return nil, nil, err
}

var conf *bkconfig.HistoryConfig
if cfg != nil {
conf = &bkconfig.HistoryConfig{
MaxAge: cfg.MaxAge,
MaxEntries: cfg.MaxEntries,
}
}

return db, conf, nil
}

func newGraphDriverController(ctx context.Context, rt http.RoundTripper, opt Opt) (*control.Controller, error) {
if err := os.MkdirAll(opt.Root, 0711); err != nil {
return nil, err
}
Expand Down Expand Up @@ -140,12 +254,12 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
return nil, err
}

differ, ok := snapshotter.(containerimageexp.Differ)
differ, ok := snapshotter.(mobyexporter.Differ)
if !ok {
return nil, errors.Errorf("snapshotter doesn't support differ")
}

exp, err := containerimageexp.New(containerimageexp.Opt{
exp, err := mobyexporter.New(mobyexporter.Opt{
ImageStore: dist.ImageStore,
ReferenceStore: dist.ReferenceStore,
Differ: differ,
Expand All @@ -159,7 +273,7 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
return nil, err
}

historyDB, err := bbolt.Open(filepath.Join(opt.Root, "history.db"), 0o600, nil)
historyDB, historyConf, err := openHistoryDB(opt.Root, opt.BuilderConfig.History)
if err != nil {
return nil, err
}
Expand All @@ -174,16 +288,16 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
return nil, errors.Errorf("snapshotter doesn't support differ")
}

leases, err := lm.List(context.TODO(), "labels.\"buildkit/lease.temporary\"")
leases, err := lm.List(ctx, "labels.\"buildkit/lease.temporary\"")
if err != nil {
return nil, err
}
for _, l := range leases {
lm.Delete(context.TODO(), l)
lm.Delete(ctx, l)
}

wopt := mobyworker.Opt{
ID: "moby",
ID: exporter.Moby,
ContentStore: store,
CacheManager: cm,
GCPolicy: gcPolicy,
Expand Down Expand Up @@ -211,14 +325,6 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
"gateway.v0": gateway.NewGatewayFrontend(wc),
}

var hconf *bkconfig.HistoryConfig
if opt.BuilderConfig.History != nil {
hconf = &bkconfig.HistoryConfig{
MaxAge: opt.BuilderConfig.History.MaxAge,
MaxEntries: opt.BuilderConfig.History.MaxEntries,
}
}

return control.NewController(control.Opt{
SessionManager: opt.SessionManager,
WorkerController: wc,
Expand All @@ -235,7 +341,7 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
LeaseManager: lm,
ContentStore: store,
HistoryDB: historyDB,
HistoryConfig: hconf,
HistoryConfig: historyConf,
})
}

Expand Down
3 changes: 3 additions & 0 deletions builder/builder-next/exporter/exporter.go
@@ -0,0 +1,3 @@
package exporter

const Moby = "moby"
@@ -1,4 +1,4 @@
package containerimage
package mobyexporter

import (
"context"
Expand Down
@@ -1,4 +1,4 @@
package containerimage
package mobyexporter

import (
"context"
Expand Down
34 changes: 34 additions & 0 deletions builder/builder-next/exporter/overrides/overrides.go
@@ -0,0 +1,34 @@
package overrides

import (
"errors"

"github.com/docker/distribution/reference"
)

// SanitizeRepoAndTags parses the raw names to a slice of repoAndTag.
// It removes duplicates and validates each repoName and tag to not contain a digest.
func SanitizeRepoAndTags(names []string) (repoAndTags []string, err error) {
uniqNames := map[string]struct{}{}
for _, repo := range names {
if repo == "" {
continue
}

ref, err := reference.ParseNormalizedNamed(repo)
if err != nil {
return nil, err
}

if _, ok := ref.(reference.Digested); ok {
return nil, errors.New("build tag cannot contain a digest")
}

nameWithTag := reference.TagNameOnly(ref).String()
if _, exists := uniqNames[nameWithTag]; !exists {
uniqNames[nameWithTag] = struct{}{}
repoAndTags = append(repoAndTags, nameWithTag)
}
}
return repoAndTags, nil
}

0 comments on commit b3428bc

Please sign in to comment.