mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-08-15 16:25:54 +08:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
30feaa1a91 | ||
![]() |
8fb1163577 | ||
![]() |
b68ee824c6 | ||
![]() |
2175f9ec7c | ||
![]() |
ba1ee7af6e | ||
![]() |
565b0b8991 | ||
![]() |
a494e9ccc4 | ||
![]() |
542e5d810e | ||
![]() |
89fb005922 | ||
![]() |
d353f6c426 | ||
![]() |
2271096e46 | ||
![]() |
95062ce8df | ||
![]() |
255aff71fb |
286
build/build.go
286
build/build.go
@@ -135,6 +135,218 @@ func filterAvailableNodes(nodes []builder.Node) ([]builder.Node, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type driverPair struct {
|
||||||
|
driverIndex int
|
||||||
|
platforms []specs.Platform
|
||||||
|
so *client.SolveOpt
|
||||||
|
bopts gateway.BuildOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
func driverIndexes(m map[string][]driverPair) []int {
|
||||||
|
out := make([]int, 0, len(m))
|
||||||
|
visited := map[int]struct{}{}
|
||||||
|
for _, dp := range m {
|
||||||
|
for _, d := range dp {
|
||||||
|
if _, ok := visited[d.driverIndex]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
visited[d.driverIndex] = struct{}{}
|
||||||
|
out = append(out, d.driverIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func allIndexes(l int) []int {
|
||||||
|
out := make([]int, 0, l)
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
out = append(out, i)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureBooted(ctx context.Context, nodes []builder.Node, idxs []int, pw progress.Writer) ([]*client.Client, error) {
|
||||||
|
clients := make([]*client.Client, len(nodes))
|
||||||
|
|
||||||
|
baseCtx := ctx
|
||||||
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
|
|
||||||
|
for _, i := range idxs {
|
||||||
|
func(i int) {
|
||||||
|
eg.Go(func() error {
|
||||||
|
c, err := driver.Boot(ctx, baseCtx, nodes[i].Driver, pw)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
clients[i] = c
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := eg.Wait(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return clients, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitToDriverPairs(availablePlatforms map[string]int, opt map[string]Options) map[string][]driverPair {
|
||||||
|
m := map[string][]driverPair{}
|
||||||
|
for k, opt := range opt {
|
||||||
|
mm := map[int][]specs.Platform{}
|
||||||
|
for _, p := range opt.Platforms {
|
||||||
|
k := platforms.Format(p)
|
||||||
|
idx := availablePlatforms[k] // default 0
|
||||||
|
pp := mm[idx]
|
||||||
|
pp = append(pp, p)
|
||||||
|
mm[idx] = pp
|
||||||
|
}
|
||||||
|
// if no platform is specified, use first driver
|
||||||
|
if len(mm) == 0 {
|
||||||
|
mm[0] = nil
|
||||||
|
}
|
||||||
|
dps := make([]driverPair, 0, 2)
|
||||||
|
for idx, pp := range mm {
|
||||||
|
dps = append(dps, driverPair{driverIndex: idx, platforms: pp})
|
||||||
|
}
|
||||||
|
m[k] = dps
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveDrivers(ctx context.Context, nodes []builder.Node, opt map[string]Options, pw progress.Writer) (map[string][]driverPair, []*client.Client, error) {
|
||||||
|
dps, clients, err := resolveDriversBase(ctx, nodes, opt, pw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bopts := make([]gateway.BuildOpts, len(clients))
|
||||||
|
|
||||||
|
span, ctx := tracing.StartSpan(ctx, "load buildkit capabilities", trace.WithSpanKind(trace.SpanKindInternal))
|
||||||
|
|
||||||
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
|
for i, c := range clients {
|
||||||
|
if c == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
func(i int, c *client.Client) {
|
||||||
|
eg.Go(func() error {
|
||||||
|
clients[i].Build(ctx, client.SolveOpt{
|
||||||
|
Internal: true,
|
||||||
|
}, "buildx", func(ctx context.Context, c gateway.Client) (*gateway.Result, error) {
|
||||||
|
bopts[i] = c.BuildOpts()
|
||||||
|
return nil, nil
|
||||||
|
}, nil)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}(i, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = eg.Wait()
|
||||||
|
tracing.FinishWithError(span, err)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
for key := range dps {
|
||||||
|
for i, dp := range dps[key] {
|
||||||
|
dps[key][i].bopts = bopts[dp.driverIndex]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dps, clients, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveDriversBase(ctx context.Context, nodes []builder.Node, opt map[string]Options, pw progress.Writer) (map[string][]driverPair, []*client.Client, error) {
|
||||||
|
availablePlatforms := map[string]int{}
|
||||||
|
for i, node := range nodes {
|
||||||
|
for _, p := range node.Platforms {
|
||||||
|
availablePlatforms[platforms.Format(p)] = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
undetectedPlatform := false
|
||||||
|
allPlatforms := map[string]struct{}{}
|
||||||
|
for _, opt := range opt {
|
||||||
|
for _, p := range opt.Platforms {
|
||||||
|
k := platforms.Format(p)
|
||||||
|
allPlatforms[k] = struct{}{}
|
||||||
|
if _, ok := availablePlatforms[k]; !ok {
|
||||||
|
undetectedPlatform = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fast path
|
||||||
|
if len(nodes) == 1 || len(allPlatforms) == 0 {
|
||||||
|
m := map[string][]driverPair{}
|
||||||
|
for k, opt := range opt {
|
||||||
|
m[k] = []driverPair{{driverIndex: 0, platforms: opt.Platforms}}
|
||||||
|
}
|
||||||
|
clients, err := ensureBooted(ctx, nodes, driverIndexes(m), pw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return m, clients, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// map based on existing platforms
|
||||||
|
if !undetectedPlatform {
|
||||||
|
m := splitToDriverPairs(availablePlatforms, opt)
|
||||||
|
clients, err := ensureBooted(ctx, nodes, driverIndexes(m), pw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return m, clients, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// boot all drivers in k
|
||||||
|
clients, err := ensureBooted(ctx, nodes, allIndexes(len(nodes)), pw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
|
workers := make([][]*client.WorkerInfo, len(clients))
|
||||||
|
|
||||||
|
for i, c := range clients {
|
||||||
|
if c == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
func(i int) {
|
||||||
|
eg.Go(func() error {
|
||||||
|
ww, err := clients[i].ListWorkers(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "listing workers")
|
||||||
|
}
|
||||||
|
workers[i] = ww
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := eg.Wait(); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, ww := range workers {
|
||||||
|
for _, w := range ww {
|
||||||
|
for _, p := range w.Platforms {
|
||||||
|
p = platforms.Normalize(p)
|
||||||
|
ps := platforms.Format(p)
|
||||||
|
|
||||||
|
if _, ok := availablePlatforms[ps]; !ok {
|
||||||
|
availablePlatforms[ps] = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return splitToDriverPairs(availablePlatforms, opt), clients, nil
|
||||||
|
}
|
||||||
|
|
||||||
func toRepoOnly(in string) (string, error) {
|
func toRepoOnly(in string) (string, error) {
|
||||||
m := map[string]struct{}{}
|
m := map[string]struct{}{}
|
||||||
p := strings.Split(in, ",")
|
p := strings.Split(in, ",")
|
||||||
@@ -505,14 +717,10 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drivers, err := resolveDrivers(ctx, nodes, opt, w)
|
m, clients, err := resolveDrivers(ctx, nodes, opt, w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
driversSolveOpts := make(map[string][]*client.SolveOpt, len(drivers))
|
|
||||||
for k, dps := range drivers {
|
|
||||||
driversSolveOpts[k] = make([]*client.SolveOpt, len(dps))
|
|
||||||
}
|
|
||||||
|
|
||||||
defers := make([]func(), 0, 2)
|
defers := make([]func(), 0, 2)
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -526,33 +734,30 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
|||||||
eg, ctx := errgroup.WithContext(ctx)
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
|
|
||||||
for k, opt := range opt {
|
for k, opt := range opt {
|
||||||
multiDriver := len(drivers[k]) > 1
|
multiDriver := len(m[k]) > 1
|
||||||
hasMobyDriver := false
|
hasMobyDriver := false
|
||||||
gitattrs, err := getGitAttributes(ctx, opt.Inputs.ContextPath, opt.Inputs.DockerfilePath)
|
gitattrs, err := getGitAttributes(ctx, opt.Inputs.ContextPath, opt.Inputs.DockerfilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Warn("current commit information was not captured by the build")
|
logrus.WithError(err).Warn("current commit information was not captured by the build")
|
||||||
}
|
}
|
||||||
for i, np := range drivers[k] {
|
for i, np := range m[k] {
|
||||||
if np.Node().Driver.IsMobyDriver() {
|
node := nodes[np.driverIndex]
|
||||||
|
if node.Driver.IsMobyDriver() {
|
||||||
hasMobyDriver = true
|
hasMobyDriver = true
|
||||||
}
|
}
|
||||||
opt.Platforms = np.platforms
|
opt.Platforms = np.platforms
|
||||||
gatewayOpts, err := np.BuildOpts(ctx)
|
so, release, err := toSolveOpt(ctx, node, multiDriver, opt, np.bopts, configDir, w, docker)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
so, release, err := toSolveOpt(ctx, np.Node(), multiDriver, opt, gatewayOpts, configDir, w, docker)
|
if err := saveLocalState(so, k, opt, node, configDir); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := saveLocalState(so, k, opt, np.Node(), configDir); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for k, v := range gitattrs {
|
for k, v := range gitattrs {
|
||||||
so.FrontendAttrs[k] = v
|
so.FrontendAttrs[k] = v
|
||||||
}
|
}
|
||||||
defers = append(defers, release)
|
defers = append(defers, release)
|
||||||
driversSolveOpts[k][i] = so
|
m[k][i].so = so
|
||||||
}
|
}
|
||||||
for _, at := range opt.Session {
|
for _, at := range opt.Session {
|
||||||
if s, ok := at.(interface {
|
if s, ok := at.(interface {
|
||||||
@@ -566,8 +771,8 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
|||||||
|
|
||||||
// validate for multi-node push
|
// validate for multi-node push
|
||||||
if hasMobyDriver && multiDriver {
|
if hasMobyDriver && multiDriver {
|
||||||
for _, so := range driversSolveOpts[k] {
|
for _, dp := range m[k] {
|
||||||
for _, e := range so.Exports {
|
for _, e := range dp.so.Exports {
|
||||||
if e.Type == "moby" {
|
if e.Type == "moby" {
|
||||||
if ok, _ := strconv.ParseBool(e.Attrs["push"]); ok {
|
if ok, _ := strconv.ParseBool(e.Attrs["push"]); ok {
|
||||||
return nil, errors.Errorf("multi-node push can't currently be performed with the docker driver, please switch to a different driver")
|
return nil, errors.Errorf("multi-node push can't currently be performed with the docker driver, please switch to a different driver")
|
||||||
@@ -580,13 +785,12 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
|||||||
|
|
||||||
// validate that all links between targets use same drivers
|
// validate that all links between targets use same drivers
|
||||||
for name := range opt {
|
for name := range opt {
|
||||||
dps := drivers[name]
|
dps := m[name]
|
||||||
for i, dp := range dps {
|
for _, dp := range dps {
|
||||||
so := driversSolveOpts[name][i]
|
for k, v := range dp.so.FrontendAttrs {
|
||||||
for k, v := range so.FrontendAttrs {
|
|
||||||
if strings.HasPrefix(k, "context:") && strings.HasPrefix(v, "target:") {
|
if strings.HasPrefix(k, "context:") && strings.HasPrefix(v, "target:") {
|
||||||
k2 := strings.TrimPrefix(v, "target:")
|
k2 := strings.TrimPrefix(v, "target:")
|
||||||
dps2, ok := drivers[k2]
|
dps2, ok := m[k2]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.Errorf("failed to find target %s for context %s", k2, strings.TrimPrefix(k, "context:")) // should be validated before already
|
return nil, errors.Errorf("failed to find target %s for context %s", k2, strings.TrimPrefix(k, "context:")) // should be validated before already
|
||||||
}
|
}
|
||||||
@@ -610,13 +814,13 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
|||||||
results := waitmap.New()
|
results := waitmap.New()
|
||||||
|
|
||||||
multiTarget := len(opt) > 1
|
multiTarget := len(opt) > 1
|
||||||
childTargets := calculateChildTargets(drivers, driversSolveOpts, opt)
|
childTargets := calculateChildTargets(m, opt)
|
||||||
|
|
||||||
for k, opt := range opt {
|
for k, opt := range opt {
|
||||||
err := func(k string) error {
|
err := func(k string) error {
|
||||||
opt := opt
|
opt := opt
|
||||||
dps := drivers[k]
|
dps := m[k]
|
||||||
multiDriver := len(drivers[k]) > 1
|
multiDriver := len(m[k]) > 1
|
||||||
|
|
||||||
var span trace.Span
|
var span trace.Span
|
||||||
ctx := ctx
|
ctx := ctx
|
||||||
@@ -632,9 +836,8 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
|||||||
var insecurePush bool
|
var insecurePush bool
|
||||||
|
|
||||||
for i, dp := range dps {
|
for i, dp := range dps {
|
||||||
i, dp := i, dp
|
i, dp, so := i, dp, *dp.so
|
||||||
node := dp.Node()
|
node := nodes[dp.driverIndex]
|
||||||
so := driversSolveOpts[k][i]
|
|
||||||
if multiDriver {
|
if multiDriver {
|
||||||
for i, e := range so.Exports {
|
for i, e := range so.Exports {
|
||||||
switch e.Type {
|
switch e.Type {
|
||||||
@@ -665,14 +868,11 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
|||||||
|
|
||||||
pw := progress.WithPrefix(w, k, multiTarget)
|
pw := progress.WithPrefix(w, k, multiTarget)
|
||||||
|
|
||||||
c, err := dp.Client(ctx)
|
c := clients[dp.driverIndex]
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
eg2.Go(func() error {
|
eg2.Go(func() error {
|
||||||
pw = progress.ResetTime(pw)
|
pw = progress.ResetTime(pw)
|
||||||
|
|
||||||
if err := waitContextDeps(ctx, dp.driverIndex, results, so); err != nil {
|
if err := waitContextDeps(ctx, dp.driverIndex, results, &so); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -770,10 +970,10 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
|||||||
var rr *client.SolveResponse
|
var rr *client.SolveResponse
|
||||||
if resultHandleFunc != nil {
|
if resultHandleFunc != nil {
|
||||||
var resultHandle *ResultHandle
|
var resultHandle *ResultHandle
|
||||||
resultHandle, rr, err = NewResultHandle(ctx, cc, *so, "buildx", buildFunc, ch)
|
resultHandle, rr, err = NewResultHandle(ctx, cc, so, "buildx", buildFunc, ch)
|
||||||
resultHandleFunc(dp.driverIndex, resultHandle)
|
resultHandleFunc(dp.driverIndex, resultHandle)
|
||||||
} else {
|
} else {
|
||||||
rr, err = c.Build(ctx, *so, "buildx", buildFunc, ch)
|
rr, err = c.Build(ctx, so, "buildx", buildFunc, ch)
|
||||||
}
|
}
|
||||||
if desktop.BuildBackendEnabled() && node.Driver.HistoryAPISupported(ctx) {
|
if desktop.BuildBackendEnabled() && node.Driver.HistoryAPISupported(ctx) {
|
||||||
buildRef := fmt.Sprintf("%s/%s/%s", node.Builder, node.Name, so.Ref)
|
buildRef := fmt.Sprintf("%s/%s/%s", node.Builder, node.Name, so.Ref)
|
||||||
@@ -797,7 +997,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
|||||||
rr.ExporterResponse[k] = string(v)
|
rr.ExporterResponse[k] = string(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
node := dp.Node().Driver
|
node := nodes[dp.driverIndex].Driver
|
||||||
if node.IsMobyDriver() {
|
if node.IsMobyDriver() {
|
||||||
for _, e := range so.Exports {
|
for _, e := range so.Exports {
|
||||||
if e.Type == "moby" && e.Attrs["push"] != "" {
|
if e.Type == "moby" && e.Attrs["push"] != "" {
|
||||||
@@ -889,7 +1089,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
|
|||||||
if len(descs) > 0 {
|
if len(descs) > 0 {
|
||||||
var imageopt imagetools.Opt
|
var imageopt imagetools.Opt
|
||||||
for _, dp := range dps {
|
for _, dp := range dps {
|
||||||
imageopt = dp.Node().ImageOpt
|
imageopt = nodes[dp.driverIndex].ImageOpt
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
names := strings.Split(pushNames, ",")
|
names := strings.Split(pushNames, ",")
|
||||||
@@ -1303,16 +1503,16 @@ func resultKey(index int, name string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// calculateChildTargets returns all the targets that depend on current target for reverse index
|
// calculateChildTargets returns all the targets that depend on current target for reverse index
|
||||||
func calculateChildTargets(drivers map[string][]*resolvedNode, driversSolveOpts map[string][]*client.SolveOpt, opt map[string]Options) map[string][]string {
|
func calculateChildTargets(drivers map[string][]driverPair, opt map[string]Options) map[string][]string {
|
||||||
out := make(map[string][]string)
|
out := make(map[string][]string)
|
||||||
for name := range opt {
|
for src := range opt {
|
||||||
dps := drivers[name]
|
dps := drivers[src]
|
||||||
for i, dp := range dps {
|
for _, dp := range dps {
|
||||||
so := driversSolveOpts[name][i]
|
so := *dp.so
|
||||||
for k, v := range so.FrontendAttrs {
|
for k, v := range so.FrontendAttrs {
|
||||||
if strings.HasPrefix(k, "context:") && strings.HasPrefix(v, "target:") {
|
if strings.HasPrefix(k, "context:") && strings.HasPrefix(v, "target:") {
|
||||||
target := resultKey(dp.driverIndex, strings.TrimPrefix(v, "target:"))
|
target := resultKey(dp.driverIndex, strings.TrimPrefix(v, "target:"))
|
||||||
out[target] = append(out[target], resultKey(dp.driverIndex, name))
|
out[target] = append(out[target], resultKey(dp.driverIndex, src))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
305
build/driver.go
305
build/driver.go
@@ -1,305 +0,0 @@
|
|||||||
package build
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/containerd/containerd/platforms"
|
|
||||||
"github.com/docker/buildx/builder"
|
|
||||||
"github.com/docker/buildx/driver"
|
|
||||||
"github.com/docker/buildx/util/progress"
|
|
||||||
"github.com/moby/buildkit/client"
|
|
||||||
gateway "github.com/moby/buildkit/frontend/gateway/client"
|
|
||||||
"github.com/moby/buildkit/util/flightcontrol"
|
|
||||||
"github.com/moby/buildkit/util/tracing"
|
|
||||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opentelemetry.io/otel/trace"
|
|
||||||
"golang.org/x/sync/errgroup"
|
|
||||||
)
|
|
||||||
|
|
||||||
type resolvedNode struct {
|
|
||||||
resolver *nodeResolver
|
|
||||||
driverIndex int
|
|
||||||
platforms []specs.Platform
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dp resolvedNode) Node() builder.Node {
|
|
||||||
return dp.resolver.nodes[dp.driverIndex]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dp resolvedNode) Client(ctx context.Context) (*client.Client, error) {
|
|
||||||
clients, err := dp.resolver.boot(ctx, []int{dp.driverIndex}, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return clients[0], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dp resolvedNode) BuildOpts(ctx context.Context) (gateway.BuildOpts, error) {
|
|
||||||
opts, err := dp.resolver.opts(ctx, []int{dp.driverIndex}, nil)
|
|
||||||
if err != nil {
|
|
||||||
return gateway.BuildOpts{}, err
|
|
||||||
}
|
|
||||||
return opts[0], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type matchMaker func(specs.Platform) platforms.MatchComparer
|
|
||||||
|
|
||||||
type nodeResolver struct {
|
|
||||||
nodes []builder.Node
|
|
||||||
clients flightcontrol.Group[*client.Client]
|
|
||||||
opt flightcontrol.Group[gateway.BuildOpts]
|
|
||||||
}
|
|
||||||
|
|
||||||
func resolveDrivers(ctx context.Context, nodes []builder.Node, opt map[string]Options, pw progress.Writer) (map[string][]*resolvedNode, error) {
|
|
||||||
driverRes := newDriverResolver(nodes)
|
|
||||||
drivers, err := driverRes.Resolve(ctx, opt, pw)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return drivers, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func newDriverResolver(nodes []builder.Node) *nodeResolver {
|
|
||||||
r := &nodeResolver{
|
|
||||||
nodes: nodes,
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *nodeResolver) Resolve(ctx context.Context, opt map[string]Options, pw progress.Writer) (map[string][]*resolvedNode, error) {
|
|
||||||
if len(r.nodes) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes := map[string][]*resolvedNode{}
|
|
||||||
for k, opt := range opt {
|
|
||||||
node, perfect, err := r.resolve(ctx, opt.Platforms, pw, platforms.OnlyStrict, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !perfect {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
nodes[k] = node
|
|
||||||
}
|
|
||||||
if len(nodes) != len(opt) {
|
|
||||||
// if we didn't get a perfect match, we need to boot all drivers
|
|
||||||
allIndexes := make([]int, len(r.nodes))
|
|
||||||
for i := range allIndexes {
|
|
||||||
allIndexes[i] = i
|
|
||||||
}
|
|
||||||
|
|
||||||
clients, err := r.boot(ctx, allIndexes, pw)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
eg, egCtx := errgroup.WithContext(ctx)
|
|
||||||
workers := make([][]specs.Platform, len(clients))
|
|
||||||
for i, c := range clients {
|
|
||||||
i, c := i, c
|
|
||||||
if c == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
eg.Go(func() error {
|
|
||||||
ww, err := c.ListWorkers(egCtx)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "listing workers")
|
|
||||||
}
|
|
||||||
|
|
||||||
ps := make(map[string]specs.Platform, len(ww))
|
|
||||||
for _, w := range ww {
|
|
||||||
for _, p := range w.Platforms {
|
|
||||||
pk := platforms.Format(platforms.Normalize(p))
|
|
||||||
ps[pk] = p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, p := range ps {
|
|
||||||
workers[i] = append(workers[i], p)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if err := eg.Wait(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// then we can attempt to match against all the available platforms
|
|
||||||
// (this time we don't care about imperfect matches)
|
|
||||||
nodes = map[string][]*resolvedNode{}
|
|
||||||
for k, opt := range opt {
|
|
||||||
node, _, err := r.resolve(ctx, opt.Platforms, pw, platforms.Only, func(idx int, n builder.Node) []specs.Platform {
|
|
||||||
return workers[idx]
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
nodes[k] = node
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
idxs := make([]int, 0, len(r.nodes))
|
|
||||||
for _, nodes := range nodes {
|
|
||||||
for _, node := range nodes {
|
|
||||||
idxs = append(idxs, node.driverIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// preload capabilities
|
|
||||||
span, ctx := tracing.StartSpan(ctx, "load buildkit capabilities", trace.WithSpanKind(trace.SpanKindInternal))
|
|
||||||
_, err := r.opts(ctx, idxs, pw)
|
|
||||||
tracing.FinishWithError(span, err)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nodes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *nodeResolver) resolve(ctx context.Context, ps []specs.Platform, pw progress.Writer, matcher matchMaker, additional func(idx int, n builder.Node) []specs.Platform) ([]*resolvedNode, bool, error) {
|
|
||||||
if len(r.nodes) == 0 {
|
|
||||||
return nil, true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ps) == 0 {
|
|
||||||
ps = []specs.Platform{platforms.DefaultSpec()}
|
|
||||||
}
|
|
||||||
|
|
||||||
perfect := true
|
|
||||||
nodeIdxs := make([]int, 0)
|
|
||||||
for _, p := range ps {
|
|
||||||
idx := r.get(p, matcher, additional)
|
|
||||||
if idx == -1 {
|
|
||||||
idx = 0
|
|
||||||
perfect = false
|
|
||||||
}
|
|
||||||
nodeIdxs = append(nodeIdxs, idx)
|
|
||||||
}
|
|
||||||
|
|
||||||
var nodes []*resolvedNode
|
|
||||||
for i, idx := range nodeIdxs {
|
|
||||||
nodes = append(nodes, &resolvedNode{
|
|
||||||
resolver: r,
|
|
||||||
driverIndex: idx,
|
|
||||||
platforms: []specs.Platform{ps[i]},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
nodes = recombineNodes(nodes)
|
|
||||||
if _, err := r.boot(ctx, nodeIdxs, pw); err != nil {
|
|
||||||
return nil, false, err
|
|
||||||
}
|
|
||||||
return nodes, perfect, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *nodeResolver) get(p specs.Platform, matcher matchMaker, additionalPlatforms func(int, builder.Node) []specs.Platform) int {
|
|
||||||
best := -1
|
|
||||||
bestPlatform := specs.Platform{}
|
|
||||||
for i, node := range r.nodes {
|
|
||||||
platforms := node.Platforms
|
|
||||||
if additionalPlatforms != nil {
|
|
||||||
platforms = append([]specs.Platform{}, platforms...)
|
|
||||||
platforms = append(platforms, additionalPlatforms(i, node)...)
|
|
||||||
}
|
|
||||||
for _, p2 := range platforms {
|
|
||||||
m := matcher(p2)
|
|
||||||
if !m.Match(p) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if best == -1 {
|
|
||||||
best = i
|
|
||||||
bestPlatform = p2
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if matcher(p2).Less(p, bestPlatform) {
|
|
||||||
best = i
|
|
||||||
bestPlatform = p2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return best
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *nodeResolver) boot(ctx context.Context, idxs []int, pw progress.Writer) ([]*client.Client, error) {
|
|
||||||
clients := make([]*client.Client, len(idxs))
|
|
||||||
|
|
||||||
baseCtx := ctx
|
|
||||||
eg, ctx := errgroup.WithContext(ctx)
|
|
||||||
|
|
||||||
for i, idx := range idxs {
|
|
||||||
i, idx := i, idx
|
|
||||||
eg.Go(func() error {
|
|
||||||
c, err := r.clients.Do(ctx, fmt.Sprint(idx), func(ctx context.Context) (*client.Client, error) {
|
|
||||||
if r.nodes[idx].Driver == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return driver.Boot(ctx, baseCtx, r.nodes[idx].Driver, pw)
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
clients[i] = c
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if err := eg.Wait(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return clients, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *nodeResolver) opts(ctx context.Context, idxs []int, pw progress.Writer) ([]gateway.BuildOpts, error) {
|
|
||||||
clients, err := r.boot(ctx, idxs, pw)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
bopts := make([]gateway.BuildOpts, len(clients))
|
|
||||||
eg, ctx := errgroup.WithContext(ctx)
|
|
||||||
for i, idxs := range idxs {
|
|
||||||
i, idx := i, idxs
|
|
||||||
c := clients[i]
|
|
||||||
if c == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
eg.Go(func() error {
|
|
||||||
opt, err := r.opt.Do(ctx, fmt.Sprint(idx), func(ctx context.Context) (gateway.BuildOpts, error) {
|
|
||||||
opt := gateway.BuildOpts{}
|
|
||||||
_, err := c.Build(ctx, client.SolveOpt{
|
|
||||||
Internal: true,
|
|
||||||
}, "buildx", func(ctx context.Context, c gateway.Client) (*gateway.Result, error) {
|
|
||||||
opt = c.BuildOpts()
|
|
||||||
return nil, nil
|
|
||||||
}, nil)
|
|
||||||
return opt, err
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
bopts[i] = opt
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if err := eg.Wait(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return bopts, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// recombineDriverPairs recombines resolved nodes that are on the same driver
|
|
||||||
// back together into a single node.
|
|
||||||
func recombineNodes(nodes []*resolvedNode) []*resolvedNode {
|
|
||||||
result := make([]*resolvedNode, 0, len(nodes))
|
|
||||||
lookup := map[int]int{}
|
|
||||||
for _, node := range nodes {
|
|
||||||
if idx, ok := lookup[node.driverIndex]; ok {
|
|
||||||
result[idx].platforms = append(result[idx].platforms, node.platforms...)
|
|
||||||
} else {
|
|
||||||
lookup[node.driverIndex] = len(result)
|
|
||||||
result = append(result, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
@@ -1,313 +0,0 @@
|
|||||||
package build
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"sort"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/containerd/containerd/platforms"
|
|
||||||
"github.com/docker/buildx/builder"
|
|
||||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFindDriverSanity(t *testing.T) {
|
|
||||||
r := makeTestResolver(map[string][]specs.Platform{
|
|
||||||
"aaa": {platforms.DefaultSpec()},
|
|
||||||
})
|
|
||||||
|
|
||||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.DefaultSpec()}, nil, platforms.OnlyStrict, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, 0, res[0].driverIndex)
|
|
||||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFindDriverEmpty(t *testing.T) {
|
|
||||||
r := makeTestResolver(nil)
|
|
||||||
|
|
||||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.DefaultSpec()}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Nil(t, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFindDriverWeirdName(t *testing.T) {
|
|
||||||
r := makeTestResolver(map[string][]specs.Platform{
|
|
||||||
"aaa": {platforms.MustParse("linux/amd64")},
|
|
||||||
"bbb": {platforms.MustParse("linux/foobar")},
|
|
||||||
})
|
|
||||||
|
|
||||||
// find first platform
|
|
||||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/foobar")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, 1, res[0].driverIndex)
|
|
||||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFindDriverUnknown(t *testing.T) {
|
|
||||||
r := makeTestResolver(map[string][]specs.Platform{
|
|
||||||
"aaa": {platforms.MustParse("linux/amd64")},
|
|
||||||
})
|
|
||||||
|
|
||||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.False(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, 0, res[0].driverIndex)
|
|
||||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectNodeSinglePlatform(t *testing.T) {
|
|
||||||
r := makeTestResolver(map[string][]specs.Platform{
|
|
||||||
"aaa": {platforms.MustParse("linux/amd64")},
|
|
||||||
"bbb": {platforms.MustParse("linux/riscv64")},
|
|
||||||
})
|
|
||||||
|
|
||||||
// find first platform
|
|
||||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/amd64")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, 0, res[0].driverIndex)
|
|
||||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
|
||||||
|
|
||||||
// find second platform
|
|
||||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, 1, res[0].driverIndex)
|
|
||||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
|
||||||
|
|
||||||
// find an unknown platform, should match the first driver
|
|
||||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/s390x")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.False(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, 0, res[0].driverIndex)
|
|
||||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectNodeMultiPlatform(t *testing.T) {
|
|
||||||
r := makeTestResolver(map[string][]specs.Platform{
|
|
||||||
"aaa": {platforms.MustParse("linux/amd64"), platforms.MustParse("linux/arm64")},
|
|
||||||
"bbb": {platforms.MustParse("linux/riscv64")},
|
|
||||||
})
|
|
||||||
|
|
||||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/amd64")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, 0, res[0].driverIndex)
|
|
||||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
|
||||||
|
|
||||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm64")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, 0, res[0].driverIndex)
|
|
||||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
|
||||||
|
|
||||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, 1, res[0].driverIndex)
|
|
||||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectNodeNonStrict(t *testing.T) {
|
|
||||||
r := makeTestResolver(map[string][]specs.Platform{
|
|
||||||
"aaa": {platforms.MustParse("linux/amd64")},
|
|
||||||
"bbb": {platforms.MustParse("linux/arm64")},
|
|
||||||
})
|
|
||||||
|
|
||||||
// arm64 should match itself
|
|
||||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm64")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
|
||||||
|
|
||||||
// arm64 may support arm/v8
|
|
||||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v8")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
|
||||||
|
|
||||||
// arm64 may support arm/v7
|
|
||||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectNodeNonStrictARM(t *testing.T) {
|
|
||||||
r := makeTestResolver(map[string][]specs.Platform{
|
|
||||||
"aaa": {platforms.MustParse("linux/amd64")},
|
|
||||||
"bbb": {platforms.MustParse("linux/arm64")},
|
|
||||||
"ccc": {platforms.MustParse("linux/arm/v8")},
|
|
||||||
})
|
|
||||||
|
|
||||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v8")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, "ccc", res[0].Node().Builder)
|
|
||||||
|
|
||||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, "ccc", res[0].Node().Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectNodeNonStrictLower(t *testing.T) {
|
|
||||||
r := makeTestResolver(map[string][]specs.Platform{
|
|
||||||
"aaa": {platforms.MustParse("linux/amd64")},
|
|
||||||
"bbb": {platforms.MustParse("linux/arm/v7")},
|
|
||||||
})
|
|
||||||
|
|
||||||
// v8 can't be built on v7 (so we should select the default)...
|
|
||||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v8")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.False(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
|
||||||
|
|
||||||
// ...but v6 can be built on v8
|
|
||||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v6")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectNodePreferStart(t *testing.T) {
|
|
||||||
r := makeTestResolver(map[string][]specs.Platform{
|
|
||||||
"aaa": {platforms.MustParse("linux/amd64")},
|
|
||||||
"bbb": {platforms.MustParse("linux/riscv64")},
|
|
||||||
"ccc": {platforms.MustParse("linux/riscv64")},
|
|
||||||
})
|
|
||||||
|
|
||||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectNodePreferExact(t *testing.T) {
|
|
||||||
r := makeTestResolver(map[string][]specs.Platform{
|
|
||||||
"aaa": {platforms.MustParse("linux/arm/v8")},
|
|
||||||
"bbb": {platforms.MustParse("linux/arm/v7")},
|
|
||||||
})
|
|
||||||
|
|
||||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectNodeCurrentPlatform(t *testing.T) {
|
|
||||||
r := makeTestResolver(map[string][]specs.Platform{
|
|
||||||
"aaa": {platforms.MustParse("linux/foobar")},
|
|
||||||
"bbb": {platforms.DefaultSpec()},
|
|
||||||
})
|
|
||||||
|
|
||||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectNodeAdditionalPlatforms(t *testing.T) {
|
|
||||||
r := makeTestResolver(map[string][]specs.Platform{
|
|
||||||
"aaa": {platforms.MustParse("linux/amd64")},
|
|
||||||
"bbb": {platforms.MustParse("linux/arm/v8")},
|
|
||||||
})
|
|
||||||
|
|
||||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, "bbb", res[0].Node().Builder)
|
|
||||||
|
|
||||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, func(idx int, n builder.Node) []specs.Platform {
|
|
||||||
if n.Builder == "aaa" {
|
|
||||||
return []specs.Platform{platforms.MustParse("linux/arm/v7")}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSplitNodeMultiPlatform(t *testing.T) {
|
|
||||||
r := makeTestResolver(map[string][]specs.Platform{
|
|
||||||
"aaa": {platforms.MustParse("linux/amd64"), platforms.MustParse("linux/arm64")},
|
|
||||||
"bbb": {platforms.MustParse("linux/riscv64")},
|
|
||||||
})
|
|
||||||
|
|
||||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{
|
|
||||||
platforms.MustParse("linux/amd64"),
|
|
||||||
platforms.MustParse("linux/arm64"),
|
|
||||||
}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 1)
|
|
||||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
|
||||||
|
|
||||||
res, perfect, err = r.resolve(context.TODO(), []specs.Platform{
|
|
||||||
platforms.MustParse("linux/amd64"),
|
|
||||||
platforms.MustParse("linux/riscv64"),
|
|
||||||
}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 2)
|
|
||||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
|
||||||
require.Equal(t, "bbb", res[1].Node().Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSplitNodeMultiPlatformNoUnify(t *testing.T) {
|
|
||||||
r := makeTestResolver(map[string][]specs.Platform{
|
|
||||||
"aaa": {platforms.MustParse("linux/amd64")},
|
|
||||||
"bbb": {platforms.MustParse("linux/amd64"), platforms.MustParse("linux/riscv64")},
|
|
||||||
})
|
|
||||||
|
|
||||||
// the "best" choice would be the node with both platforms, but we're using
|
|
||||||
// a naive algorithm that doesn't try to unify the platforms
|
|
||||||
res, perfect, err := r.resolve(context.TODO(), []specs.Platform{
|
|
||||||
platforms.MustParse("linux/amd64"),
|
|
||||||
platforms.MustParse("linux/riscv64"),
|
|
||||||
}, nil, platforms.Only, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, perfect)
|
|
||||||
require.Len(t, res, 2)
|
|
||||||
require.Equal(t, "aaa", res[0].Node().Builder)
|
|
||||||
require.Equal(t, "bbb", res[1].Node().Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeTestResolver(nodes map[string][]specs.Platform) *nodeResolver {
|
|
||||||
var ns []builder.Node
|
|
||||||
for name, platforms := range nodes {
|
|
||||||
ns = append(ns, builder.Node{
|
|
||||||
Builder: name,
|
|
||||||
Platforms: platforms,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
sort.Slice(ns, func(i, j int) bool {
|
|
||||||
return ns[i].Builder < ns[j].Builder
|
|
||||||
})
|
|
||||||
return newDriverResolver(ns)
|
|
||||||
}
|
|
@@ -274,13 +274,13 @@ target "db" {
|
|||||||
|
|
||||||
### `target.annotations`
|
### `target.annotations`
|
||||||
|
|
||||||
The `annotations` attribute is a shortcut to allow you to easily set a list of
|
The `annotations` attribute lets you add annotations to images built with bake.
|
||||||
annotations on the target.
|
The key takes a list of annotations, in the format of `KEY=VALUE`.
|
||||||
|
|
||||||
```hcl
|
```hcl
|
||||||
target "default" {
|
target "default" {
|
||||||
output = ["type=image,name=foo"]
|
output = ["type=image,name=foo"]
|
||||||
annotations = ["key=value"]
|
annotations = ["org.opencontainers.image.authors=dvdksn"]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -288,10 +288,25 @@ is the same as
|
|||||||
|
|
||||||
```hcl
|
```hcl
|
||||||
target "default" {
|
target "default" {
|
||||||
output = ["type=image,name=foo,annotation.key=value"]
|
output = ["type=image,name=foo,annotation.org.opencontainers.image.authors=dvdksn"]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
By default, the annotation is added to image manifests. You can configure the
|
||||||
|
level of the annotations by adding a prefix to the annotation, containing a
|
||||||
|
comma-separated list of all the levels that you want to annotate. The following
|
||||||
|
example adds annotations to both the image index and manifests.
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
target "default" {
|
||||||
|
output = ["type=image,name=foo"]
|
||||||
|
annotations = ["index,manifest:org.opencontainers.image.authors=dvdksn"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Read about the supported levels in
|
||||||
|
[Specifying annotation levels](https://docs.docker.com/build/building/annotations/#specifying-annotation-levels).
|
||||||
|
|
||||||
### `target.attest`
|
### `target.attest`
|
||||||
|
|
||||||
The `attest` attribute lets you apply [build attestations][attestations] to the target.
|
The `attest` attribute lets you apply [build attestations][attestations] to the target.
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# buildx
|
# buildx
|
||||||
|
|
||||||
```
|
```text
|
||||||
docker buildx [OPTIONS] COMMAND
|
docker buildx [OPTIONS] COMMAND
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# buildx bake
|
# buildx bake
|
||||||
|
|
||||||
```
|
```text
|
||||||
docker buildx bake [OPTIONS] [TARGET...]
|
docker buildx bake [OPTIONS] [TARGET...]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ Build from a file
|
|||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
Bake is a high-level build command. Each specified target will run in parallel
|
Bake is a high-level build command. Each specified target runs in parallel
|
||||||
as part of the build.
|
as part of the build.
|
||||||
|
|
||||||
Read [High-level build options with Bake](https://docs.docker.com/build/bake/)
|
Read [High-level build options with Bake](https://docs.docker.com/build/bake/)
|
||||||
@@ -54,8 +54,8 @@ Same as [`buildx --builder`](buildx.md#builder).
|
|||||||
### <a name="file"></a> Specify a build definition file (-f, --file)
|
### <a name="file"></a> Specify a build definition file (-f, --file)
|
||||||
|
|
||||||
Use the `-f` / `--file` option to specify the build definition file to use.
|
Use the `-f` / `--file` option to specify the build definition file to use.
|
||||||
The file can be an HCL, JSON or Compose file. If multiple files are specified
|
The file can be an HCL, JSON or Compose file. If multiple files are specified,
|
||||||
they are all read and configurations are combined.
|
all are read and the build configurations are combined.
|
||||||
|
|
||||||
You can pass the names of the targets to build, to build only specific target(s).
|
You can pass the names of the targets to build, to build only specific target(s).
|
||||||
The following example builds the `db` and `webapp-release` targets that are
|
The following example builds the `db` and `webapp-release` targets that are
|
||||||
@@ -90,9 +90,9 @@ $ docker buildx bake -f docker-bake.dev.hcl db webapp-release
|
|||||||
See the [Bake file reference](https://docs.docker.com/build/bake/reference/)
|
See the [Bake file reference](https://docs.docker.com/build/bake/reference/)
|
||||||
for more details.
|
for more details.
|
||||||
|
|
||||||
### <a name="no-cache"></a> Do not use cache when building the image (--no-cache)
|
### <a name="no-cache"></a> Don't use cache when building the image (--no-cache)
|
||||||
|
|
||||||
Same as `build --no-cache`. Do not use cache when building the image.
|
Same as `build --no-cache`. Don't use cache when building the image.
|
||||||
|
|
||||||
### <a name="print"></a> Print the options without building (--print)
|
### <a name="print"></a> Print the options without building (--print)
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ $ docker buildx bake --set *.platform=linux/arm64 # overrides platform for a
|
|||||||
$ docker buildx bake --set foo*.no-cache # bypass caching only for targets starting with 'foo'
|
$ docker buildx bake --set foo*.no-cache # bypass caching only for targets starting with 'foo'
|
||||||
```
|
```
|
||||||
|
|
||||||
Complete list of overridable fields:
|
You can override the following fields:
|
||||||
|
|
||||||
* `args`
|
* `args`
|
||||||
* `cache-from`
|
* `cache-from`
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# buildx build
|
# buildx build
|
||||||
|
|
||||||
```
|
```text
|
||||||
docker buildx build [OPTIONS] PATH | URL | -
|
docker buildx build [OPTIONS] PATH | URL | -
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ Start a build
|
|||||||
|:-------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------|:----------|:----------------------------------------------------------------------------------------------------|
|
|:-------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------|:----------|:----------------------------------------------------------------------------------------------------|
|
||||||
| [`--add-host`](https://docs.docker.com/engine/reference/commandline/build/#add-host) | `stringSlice` | | Add a custom host-to-IP mapping (format: `host:ip`) |
|
| [`--add-host`](https://docs.docker.com/engine/reference/commandline/build/#add-host) | `stringSlice` | | Add a custom host-to-IP mapping (format: `host:ip`) |
|
||||||
| [`--allow`](#allow) | `stringSlice` | | Allow extra privileged entitlement (e.g., `network.host`, `security.insecure`) |
|
| [`--allow`](#allow) | `stringSlice` | | Allow extra privileged entitlement (e.g., `network.host`, `security.insecure`) |
|
||||||
| `--annotation` | `stringArray` | | Add annotation to the image |
|
| [`--annotation`](#annotation) | `stringArray` | | Add annotation to the image |
|
||||||
| [`--attest`](#attest) | `stringArray` | | Attestation parameters (format: `type=sbom,generator=image`) |
|
| [`--attest`](#attest) | `stringArray` | | Attestation parameters (format: `type=sbom,generator=image`) |
|
||||||
| [`--build-arg`](#build-arg) | `stringArray` | | Set build-time variables |
|
| [`--build-arg`](#build-arg) | `stringArray` | | Set build-time variables |
|
||||||
| [`--build-context`](#build-context) | `stringArray` | | Additional build contexts (e.g., name=path) |
|
| [`--build-context`](#build-context) | `stringArray` | | Additional build contexts (e.g., name=path) |
|
||||||
@@ -64,14 +64,60 @@ The `buildx build` command starts a build using BuildKit. This command is simila
|
|||||||
to the UI of `docker build` command and takes the same flags and arguments.
|
to the UI of `docker build` command and takes the same flags and arguments.
|
||||||
|
|
||||||
For documentation on most of these flags, refer to the [`docker build`
|
For documentation on most of these flags, refer to the [`docker build`
|
||||||
documentation](https://docs.docker.com/engine/reference/commandline/build/). In
|
documentation](https://docs.docker.com/engine/reference/commandline/build/).
|
||||||
here we'll document a subset of the new flags.
|
This page describes a subset of the new flags.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
### <a name="annotation"></a> Create annotations (--annotation)
|
||||||
|
|
||||||
|
```text
|
||||||
|
--annotation="key=value"
|
||||||
|
--annotation="[type:]key=value"
|
||||||
|
```
|
||||||
|
|
||||||
|
Add OCI annotations to the image index, manifest, or descriptor.
|
||||||
|
The following example adds the `foo=bar` annotation to the image manifests:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ docker buildx build -t TAG --annotation "foo=bar" --push .
|
||||||
|
```
|
||||||
|
|
||||||
|
You can optionally add a type prefix to specify the level of the annotation. By
|
||||||
|
default, the image manifest is annotated. The following example adds the
|
||||||
|
`foo=bar` annotation the image index instead of the manifests:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ docker buildx build -t TAG --annotation "index:foo=bar" --push .
|
||||||
|
```
|
||||||
|
|
||||||
|
You can specify multiple types, separated by a comma (,) to add the annotation
|
||||||
|
to multiple image components. The following example adds the `foo=bar`
|
||||||
|
annotation to image index, descriptors, manifests:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ docker buildx build -t TAG --annotation "index,manifest,manifest-descriptor:foo=bar" --push .
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also specify a platform qualifier in square brackets (`[os/arch]`) in
|
||||||
|
the type prefix, to apply the annotation to a subset of manifests with the
|
||||||
|
matching platform. The following example adds the `foo=bar` annotation only to
|
||||||
|
the manifest with the `linux/amd64` platform:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ docker buildx build -t TAG --annotation "manifest[linux/amd64]:foo=bar" --push .
|
||||||
|
```
|
||||||
|
|
||||||
|
Wildcards are not supported in the platform qualifier; you can't specify a type
|
||||||
|
prefix like `manifest[linux/*]` to add annotations only to manifests which has
|
||||||
|
`linux` as the OS platform.
|
||||||
|
|
||||||
|
For more information about annotations, see
|
||||||
|
[Annotations](https://docs.docker.com/build/building/annotations/).
|
||||||
|
|
||||||
### <a name="attest"></a> Create attestations (--attest)
|
### <a name="attest"></a> Create attestations (--attest)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--attest=type=sbom,...
|
--attest=type=sbom,...
|
||||||
--attest=type=provenance,...
|
--attest=type=provenance,...
|
||||||
```
|
```
|
||||||
@@ -98,7 +144,7 @@ BuildKit currently supports:
|
|||||||
|
|
||||||
### <a name="allow"></a> Allow extra privileged entitlement (--allow)
|
### <a name="allow"></a> Allow extra privileged entitlement (--allow)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--allow=ENTITLEMENT
|
--allow=ENTITLEMENT
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -109,9 +155,7 @@ Allow extra privileged entitlement. List of entitlements:
|
|||||||
[related Dockerfile extensions](https://docs.docker.com/engine/reference/builder/#run---securitysandbox).
|
[related Dockerfile extensions](https://docs.docker.com/engine/reference/builder/#run---securitysandbox).
|
||||||
|
|
||||||
For entitlements to be enabled, the `buildkitd` daemon also needs to allow them
|
For entitlements to be enabled, the `buildkitd` daemon also needs to allow them
|
||||||
with `--allow-insecure-entitlement` (see [`create --buildkitd-flags`](buildx_create.md#buildkitd-flags))
|
with `--allow-insecure-entitlement` (see [`create --buildkitd-flags`](buildx_create.md#buildkitd-flags)).
|
||||||
|
|
||||||
**Examples**
|
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker buildx create --use --name insecure-builder --buildkitd-flags '--allow-insecure-entitlement security.insecure'
|
$ docker buildx create --use --name insecure-builder --buildkitd-flags '--allow-insecure-entitlement security.insecure'
|
||||||
@@ -122,23 +166,21 @@ $ docker buildx build --allow security.insecure .
|
|||||||
|
|
||||||
Same as [`docker build` command](https://docs.docker.com/engine/reference/commandline/build/#build-arg).
|
Same as [`docker build` command](https://docs.docker.com/engine/reference/commandline/build/#build-arg).
|
||||||
|
|
||||||
There are also useful built-in build args like:
|
There are also useful built-in build arguments, such as:
|
||||||
|
|
||||||
* `BUILDKIT_CONTEXT_KEEP_GIT_DIR=<bool>` trigger git context to keep the `.git` directory
|
* `BUILDKIT_CONTEXT_KEEP_GIT_DIR=<bool>`: trigger git context to keep the `.git` directory
|
||||||
* `BUILDKIT_INLINE_CACHE=<bool>` inline cache metadata to image config or not
|
* `BUILDKIT_INLINE_CACHE=<bool>`: inline cache metadata to image config or not
|
||||||
* `BUILDKIT_MULTI_PLATFORM=<bool>` opt into deterministic output regardless of multi-platform output or not
|
* `BUILDKIT_MULTI_PLATFORM=<bool>`: opt into deterministic output regardless of multi-platform output or not
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker buildx build --build-arg BUILDKIT_MULTI_PLATFORM=1 .
|
$ docker buildx build --build-arg BUILDKIT_MULTI_PLATFORM=1 .
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note**
|
Learn more about the built-in build arguments in the [Dockerfile reference docs](https://docs.docker.com/engine/reference/builder/#buildkit-built-in-build-args).
|
||||||
>
|
|
||||||
> More built-in build args can be found in [Dockerfile reference docs](https://docs.docker.com/engine/reference/builder/#buildkit-built-in-build-args).
|
|
||||||
|
|
||||||
### <a name="build-context"></a> Additional build contexts (--build-context)
|
### <a name="build-context"></a> Additional build contexts (--build-context)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--build-context=name=VALUE
|
--build-context=name=VALUE
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -166,7 +208,7 @@ FROM alpine
|
|||||||
COPY --from=project myfile /
|
COPY --from=project myfile /
|
||||||
```
|
```
|
||||||
|
|
||||||
#### <a name="source-oci-layout"></a> Source image from OCI layout directory
|
#### <a name="source-oci-layout"></a> Use an OCI layout directory as build context
|
||||||
|
|
||||||
Source an image from a local [OCI layout compliant directory](https://github.com/opencontainers/image-spec/blob/main/image-layout.md),
|
Source an image from a local [OCI layout compliant directory](https://github.com/opencontainers/image-spec/blob/main/image-layout.md),
|
||||||
either by tag, or by digest:
|
either by tag, or by digest:
|
||||||
@@ -194,7 +236,7 @@ Same as [`buildx --builder`](buildx.md#builder).
|
|||||||
|
|
||||||
### <a name="cache-from"></a> Use an external cache source for a build (--cache-from)
|
### <a name="cache-from"></a> Use an external cache source for a build (--cache-from)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--cache-from=[NAME|type=TYPE[,KEY=VALUE]]
|
--cache-from=[NAME|type=TYPE[,KEY=VALUE]]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -230,7 +272,7 @@ More info about cache exporters and available attributes: https://github.com/mob
|
|||||||
|
|
||||||
### <a name="cache-to"></a> Export build cache to an external cache destination (--cache-to)
|
### <a name="cache-to"></a> Export build cache to an external cache destination (--cache-to)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--cache-to=[NAME|type=TYPE[,KEY=VALUE]]
|
--cache-to=[NAME|type=TYPE[,KEY=VALUE]]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -247,9 +289,8 @@ Export build cache to an external cache destination. Supported types are
|
|||||||
- [`s3` type](https://github.com/moby/buildkit#s3-cache-experimental) exports
|
- [`s3` type](https://github.com/moby/buildkit#s3-cache-experimental) exports
|
||||||
cache to a S3 bucket.
|
cache to a S3 bucket.
|
||||||
|
|
||||||
`docker` driver currently only supports exporting inline cache metadata to image
|
The `docker` driver only supports cache exports using the `inline` and `local`
|
||||||
configuration. Alternatively, `--build-arg BUILDKIT_INLINE_CACHE=1` can be used
|
cache backends.
|
||||||
to trigger inline cache exporter.
|
|
||||||
|
|
||||||
Attribute key:
|
Attribute key:
|
||||||
|
|
||||||
@@ -283,6 +324,7 @@ directory of the specified file must already exist and be writable.
|
|||||||
$ docker buildx build --load --metadata-file metadata.json .
|
$ docker buildx build --load --metadata-file metadata.json .
|
||||||
$ cat metadata.json
|
$ cat metadata.json
|
||||||
```
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"containerimage.config.digest": "sha256:2937f66a9722f7f4a2df583de2f8cb97fc9196059a410e7f00072fc918930e66",
|
"containerimage.config.digest": "sha256:2937f66a9722f7f4a2df583de2f8cb97fc9196059a410e7f00072fc918930e66",
|
||||||
@@ -301,14 +343,14 @@ $ cat metadata.json
|
|||||||
|
|
||||||
### <a name="output"></a> Set the export action for the build result (-o, --output)
|
### <a name="output"></a> Set the export action for the build result (-o, --output)
|
||||||
|
|
||||||
```
|
```text
|
||||||
-o, --output=[PATH,-,type=TYPE[,KEY=VALUE]
|
-o, --output=[PATH,-,type=TYPE[,KEY=VALUE]
|
||||||
```
|
```
|
||||||
|
|
||||||
Sets the export action for the build result. In `docker build` all builds finish
|
Sets the export action for the build result. In `docker build` all builds finish
|
||||||
by creating a container image and exporting it to `docker images`. `buildx` makes
|
by creating a container image and exporting it to `docker images`. `buildx` makes
|
||||||
this step configurable allowing results to be exported directly to the client,
|
this step configurable allowing results to be exported directly to the client,
|
||||||
oci image tarballs, registry etc.
|
OCI image tarballs, registry etc.
|
||||||
|
|
||||||
Buildx with `docker` driver currently only supports local, tarball exporter and
|
Buildx with `docker` driver currently only supports local, tarball exporter and
|
||||||
image exporter. `docker-container` driver supports all the exporters.
|
image exporter. `docker-container` driver supports all the exporters.
|
||||||
@@ -363,15 +405,15 @@ The `docker` export type writes the single-platform result image as a [Docker im
|
|||||||
specification](https://github.com/docker/docker/blob/v20.10.2/image/spec/v1.2.md)
|
specification](https://github.com/docker/docker/blob/v20.10.2/image/spec/v1.2.md)
|
||||||
tarball on the client. Tarballs created by this exporter are also OCI compatible.
|
tarball on the client. Tarballs created by this exporter are also OCI compatible.
|
||||||
|
|
||||||
Currently, multi-platform images cannot be exported with the `docker` export type.
|
The default image store in Docker Engine doesn't support loading multi-platform
|
||||||
The most common usecase for multi-platform images is to directly push to a registry
|
images. You can enable the containerd image store, or push multi-platform images
|
||||||
(see [`registry`](#registry)).
|
is to directly push to a registry, see [`registry`](#registry).
|
||||||
|
|
||||||
Attribute keys:
|
Attribute keys:
|
||||||
|
|
||||||
- `dest` - destination path where tarball will be written. If not specified the
|
- `dest` - destination path where tarball will be written. If not specified,
|
||||||
tar will be loaded automatically to the current docker instance.
|
the tar will be loaded automatically to the local image store.
|
||||||
- `context` - name for the docker context where to import the result
|
- `context` - name for the Docker context where to import the result
|
||||||
|
|
||||||
#### `image`
|
#### `image`
|
||||||
|
|
||||||
@@ -382,7 +424,7 @@ can be automatically pushed to a registry by specifying attributes.
|
|||||||
Attribute keys:
|
Attribute keys:
|
||||||
|
|
||||||
- `name` - name (references) for the new image.
|
- `name` - name (references) for the new image.
|
||||||
- `push` - boolean to automatically push the image.
|
- `push` - Boolean to automatically push the image.
|
||||||
|
|
||||||
#### `registry`
|
#### `registry`
|
||||||
|
|
||||||
@@ -390,7 +432,7 @@ The `registry` exporter is a shortcut for `type=image,push=true`.
|
|||||||
|
|
||||||
### <a name="platform"></a> Set the target platforms for the build (--platform)
|
### <a name="platform"></a> Set the target platforms for the build (--platform)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--platform=value[,value]
|
--platform=value[,value]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -419,12 +461,12 @@ and `arm` architectures. You can see what runtime platforms your current builder
|
|||||||
instance supports by running `docker buildx inspect --bootstrap`.
|
instance supports by running `docker buildx inspect --bootstrap`.
|
||||||
|
|
||||||
Inside a `Dockerfile`, you can access the current platform value through
|
Inside a `Dockerfile`, you can access the current platform value through
|
||||||
`TARGETPLATFORM` build argument. Please refer to the [`docker build`
|
`TARGETPLATFORM` build argument. Refer to the [`docker build`
|
||||||
documentation](https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope)
|
documentation](https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope)
|
||||||
for the full description of automatic platform argument variants .
|
for the full description of automatic platform argument variants .
|
||||||
|
|
||||||
The formatting for the platform specifier is defined in the [containerd source
|
You can find the formatting definition for the platform specifier in the
|
||||||
code](https://github.com/containerd/containerd/blob/v1.4.3/platforms/platforms.go#L63).
|
[containerd source code](https://github.com/containerd/containerd/blob/v1.4.3/platforms/platforms.go#L63).
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker buildx build --platform=linux/arm64 .
|
$ docker buildx build --platform=linux/arm64 .
|
||||||
@@ -434,11 +476,11 @@ $ docker buildx build --platform=darwin .
|
|||||||
|
|
||||||
### <a name="progress"></a> Set type of progress output (--progress)
|
### <a name="progress"></a> Set type of progress output (--progress)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--progress=VALUE
|
--progress=VALUE
|
||||||
```
|
```
|
||||||
|
|
||||||
Set type of progress output (auto, plain, tty). Use plain to show container
|
Set type of progress output (`auto`, `plain`, `tty`). Use plain to show container
|
||||||
output (default "auto").
|
output (default "auto").
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
@@ -472,15 +514,18 @@ provenance attestations for the build result. For example,
|
|||||||
`--provenance=mode=max` can be used as an abbreviation for
|
`--provenance=mode=max` can be used as an abbreviation for
|
||||||
`--attest=type=provenance,mode=max`.
|
`--attest=type=provenance,mode=max`.
|
||||||
|
|
||||||
Additionally, `--provenance` can be used with boolean values to broadly enable
|
Additionally, `--provenance` can be used with Boolean values to enable or disable
|
||||||
or disable provenance attestations. For example, `--provenance=false` can be
|
provenance attestations. For example, `--provenance=false` disables all provenance attestations,
|
||||||
used to disable all provenance attestations, while `--provenance=true` can be
|
while `--provenance=true` enables all provenance attestations.
|
||||||
used to enable all provenance attestations.
|
|
||||||
|
|
||||||
By default, a minimal provenance attestation will be created for the build
|
By default, a minimal provenance attestation will be created for the build
|
||||||
result, which will only be attached for images pushed to registries.
|
result. Note that the default image store in Docker Engine doesn't support
|
||||||
|
attestations. Provenance attestations only persist for images pushed directly
|
||||||
|
to a registry if you use the default image store. Alternatively, you can switch
|
||||||
|
to using the containerd image store.
|
||||||
|
|
||||||
For more information, see [here](https://docs.docker.com/build/attestations/slsa-provenance/).
|
For more information about provenance attestations, see
|
||||||
|
[here](https://docs.docker.com/build/attestations/slsa-provenance/).
|
||||||
|
|
||||||
### <a name="push"></a> Push the build result to a registry (--push)
|
### <a name="push"></a> Push the build result to a registry (--push)
|
||||||
|
|
||||||
@@ -494,15 +539,19 @@ attestations for the build result. For example,
|
|||||||
`--sbom=generator=<user>/<generator-image>` can be used as an abbreviation for
|
`--sbom=generator=<user>/<generator-image>` can be used as an abbreviation for
|
||||||
`--attest=type=sbom,generator=<user>/<generator-image>`.
|
`--attest=type=sbom,generator=<user>/<generator-image>`.
|
||||||
|
|
||||||
Additionally, `--sbom` can be used with boolean values to broadly enable or
|
Additionally, `--sbom` can be used with Boolean values to enable or disable
|
||||||
disable SBOM attestations. For example, `--sbom=false` can be used to disable
|
SBOM attestations. For example, `--sbom=false` disables all SBOM attestations.
|
||||||
all SBOM attestations.
|
|
||||||
|
Note that the default image store in Docker Engine doesn't support
|
||||||
|
attestations. Provenance attestations only persist for images pushed directly
|
||||||
|
to a registry if you use the default image store. Alternatively, you can switch
|
||||||
|
to using the containerd image store.
|
||||||
|
|
||||||
For more information, see [here](https://docs.docker.com/build/attestations/sbom/).
|
For more information, see [here](https://docs.docker.com/build/attestations/sbom/).
|
||||||
|
|
||||||
### <a name="secret"></a> Secret to expose to the build (--secret)
|
### <a name="secret"></a> Secret to expose to the build (--secret)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--secret=[type=TYPE[,KEY=VALUE]
|
--secret=[type=TYPE[,KEY=VALUE]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -515,7 +564,7 @@ If `type` is unset it will be detected. Supported types are:
|
|||||||
|
|
||||||
Attribute keys:
|
Attribute keys:
|
||||||
|
|
||||||
- `id` - ID of the secret. Defaults to basename of the `src` path.
|
- `id` - ID of the secret. Defaults to base name of the `src` path.
|
||||||
- `src`, `source` - Secret filename. `id` used if unset.
|
- `src`, `source` - Secret filename. `id` used if unset.
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
@@ -557,7 +606,7 @@ optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g`
|
|||||||
|
|
||||||
### <a name="ssh"></a> SSH agent socket or keys to expose to the build (--ssh)
|
### <a name="ssh"></a> SSH agent socket or keys to expose to the build (--ssh)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--ssh=default|<id>[=<socket>|<key>[,<key>]]
|
--ssh=default|<id>[=<socket>|<key>[,<key>]]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -597,6 +646,6 @@ $ docker buildx build --ulimit nofile=1024:1024 .
|
|||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
> If you do not provide a `hard limit`, the `soft limit` is used
|
> If you don't provide a `hard limit`, the `soft limit` is used
|
||||||
> for both values. If no `ulimits` are set, they are inherited from
|
> for both values. If no `ulimits` are set, they're inherited from
|
||||||
> the default `ulimits` set on the daemon.
|
> the default `ulimits` set on the daemon.
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# buildx create
|
# buildx create
|
||||||
|
|
||||||
```
|
```text
|
||||||
docker buildx create [OPTIONS] [CONTEXT|ENDPOINT]
|
docker buildx create [OPTIONS] [CONTEXT|ENDPOINT]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -29,9 +29,9 @@ Create a new builder instance
|
|||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
Create makes a new builder instance pointing to a docker context or endpoint,
|
Create makes a new builder instance pointing to a Docker context or endpoint,
|
||||||
where context is the name of a context from `docker context ls` and endpoint is
|
where context is the name of a context from `docker context ls` and endpoint is
|
||||||
the address for docker socket (eg. `DOCKER_HOST` value).
|
the address for Docker socket (eg. `DOCKER_HOST` value).
|
||||||
|
|
||||||
By default, the current Docker configuration is used for determining the
|
By default, the current Docker configuration is used for determining the
|
||||||
context/endpoint value.
|
context/endpoint value.
|
||||||
@@ -57,7 +57,7 @@ eager_beaver
|
|||||||
|
|
||||||
### <a name="buildkitd-flags"></a> Specify options for the buildkitd daemon (--buildkitd-flags)
|
### <a name="buildkitd-flags"></a> Specify options for the buildkitd daemon (--buildkitd-flags)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--buildkitd-flags FLAGS
|
--buildkitd-flags FLAGS
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -65,13 +65,13 @@ Adds flags when starting the buildkitd daemon. They take precedence over the
|
|||||||
configuration file specified by [`--config`](#config). See `buildkitd --help`
|
configuration file specified by [`--config`](#config). See `buildkitd --help`
|
||||||
for the available flags.
|
for the available flags.
|
||||||
|
|
||||||
```
|
```text
|
||||||
--buildkitd-flags '--debug --debugaddr 0.0.0.0:6666'
|
--buildkitd-flags '--debug --debugaddr 0.0.0.0:6666'
|
||||||
```
|
```
|
||||||
|
|
||||||
### <a name="config"></a> Specify a configuration file for the buildkitd daemon (--config)
|
### <a name="config"></a> Specify a configuration file for the buildkitd daemon (--config)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--config FILE
|
--config FILE
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -79,7 +79,8 @@ Specifies the configuration file for the buildkitd daemon to use. The configurat
|
|||||||
can be overridden by [`--buildkitd-flags`](#buildkitd-flags).
|
can be overridden by [`--buildkitd-flags`](#buildkitd-flags).
|
||||||
See an [example buildkitd configuration file](https://github.com/moby/buildkit/blob/master/docs/buildkitd.toml.md).
|
See an [example buildkitd configuration file](https://github.com/moby/buildkit/blob/master/docs/buildkitd.toml.md).
|
||||||
|
|
||||||
If the configuration file is not specified, will look for one by default in:
|
If you don't specify a configuration file, Buildx looks for one by default in:
|
||||||
|
|
||||||
* `$BUILDX_CONFIG/buildkitd.default.toml`
|
* `$BUILDX_CONFIG/buildkitd.default.toml`
|
||||||
* `$DOCKER_CONFIG/buildx/buildkitd.default.toml`
|
* `$DOCKER_CONFIG/buildx/buildkitd.default.toml`
|
||||||
* `~/.docker/buildx/buildkitd.default.toml`
|
* `~/.docker/buildx/buildkitd.default.toml`
|
||||||
@@ -91,23 +92,30 @@ will be updated to reflect that.
|
|||||||
|
|
||||||
### <a name="driver"></a> Set the builder driver to use (--driver)
|
### <a name="driver"></a> Set the builder driver to use (--driver)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--driver DRIVER
|
--driver DRIVER
|
||||||
```
|
```
|
||||||
|
|
||||||
Sets the builder driver to be used. There are two available drivers, each have
|
Sets the builder driver to be used. A driver is a configuration of a BuildKit
|
||||||
their own specificities.
|
backend. Buildx supports the following drivers:
|
||||||
|
|
||||||
|
* `docker` (default)
|
||||||
|
* `docker-container`
|
||||||
|
* `kubernetes`
|
||||||
|
* `remote`
|
||||||
|
|
||||||
|
For more information about build drivers, see [here](https://docs.docker.com/build/drivers/).
|
||||||
|
|
||||||
#### `docker` driver
|
#### `docker` driver
|
||||||
|
|
||||||
Uses the builder that is built into the docker daemon. With this driver,
|
Uses the builder that is built into the Docker daemon. With this driver,
|
||||||
the [`--load`](buildx_build.md#load) flag is implied by default on
|
the [`--load`](buildx_build.md#load) flag is implied by default on
|
||||||
`buildx build`. However, building multi-platform images or exporting cache is
|
`buildx build`. However, building multi-platform images or exporting cache is
|
||||||
not currently supported.
|
not currently supported.
|
||||||
|
|
||||||
#### `docker-container` driver
|
#### `docker-container` driver
|
||||||
|
|
||||||
Uses a BuildKit container that will be spawned via docker. With this driver,
|
Uses a BuildKit container that will be spawned via Docker. With this driver,
|
||||||
both building multi-platform images and exporting cache are supported.
|
both building multi-platform images and exporting cache are supported.
|
||||||
|
|
||||||
Unlike `docker` driver, built images will not automatically appear in
|
Unlike `docker` driver, built images will not automatically appear in
|
||||||
@@ -116,7 +124,7 @@ to achieve that.
|
|||||||
|
|
||||||
#### `kubernetes` driver
|
#### `kubernetes` driver
|
||||||
|
|
||||||
Uses a kubernetes pods. With this driver, you can spin up pods with defined
|
Uses Kubernetes pods. With this driver, you can spin up pods with defined
|
||||||
BuildKit container image to build your images.
|
BuildKit container image to build your images.
|
||||||
|
|
||||||
Unlike `docker` driver, built images will not automatically appear in
|
Unlike `docker` driver, built images will not automatically appear in
|
||||||
@@ -135,59 +143,18 @@ to achieve that.
|
|||||||
|
|
||||||
### <a name="driver-opt"></a> Set additional driver-specific options (--driver-opt)
|
### <a name="driver-opt"></a> Set additional driver-specific options (--driver-opt)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--driver-opt OPTIONS
|
--driver-opt OPTIONS
|
||||||
```
|
```
|
||||||
|
|
||||||
Passes additional driver-specific options.
|
Passes additional driver-specific options.
|
||||||
|
For information about available driver options, refer to the detailed
|
||||||
|
documentation for the specific driver:
|
||||||
|
|
||||||
Note: When using quoted values for the `nodeselector`, `annotations`, `labels` or
|
* [`docker` driver](https://docs.docker.com/build/drivers/docker/)
|
||||||
`tolerations` options, ensure that quotes are escaped correctly for your shell.
|
* [`docker-container` driver](https://docs.docker.com/build/drivers/docker-container/)
|
||||||
|
* [`kubernetes` driver](https://docs.docker.com/build/drivers/kubernetes/)
|
||||||
#### `docker` driver
|
* [`remote` driver](https://docs.docker.com/build/drivers/remote/)
|
||||||
|
|
||||||
No driver options.
|
|
||||||
|
|
||||||
#### `docker-container` driver
|
|
||||||
|
|
||||||
- `image=IMAGE` - Sets the BuildKit image to use for the container.
|
|
||||||
- `memory=MEMORY` - Sets the amount of memory the container can use.
|
|
||||||
- `memory-swap=MEMORY_SWAP` - Sets the memory swap limit for the container.
|
|
||||||
- `cpu-quota=CPU_QUOTA` - Imposes a CPU CFS quota on the container.
|
|
||||||
- `cpu-period=CPU_PERIOD` - Sets the CPU CFS scheduler period for the container.
|
|
||||||
- `cpu-shares=CPU_SHARES` - Configures CPU shares (relative weight) of the container.
|
|
||||||
- `cpuset-cpus=CPUSET_CPUS` - Limits the set of CPU cores the container can use.
|
|
||||||
- `cpuset-mems=CPUSET_MEMS` - Limits the set of CPU memory nodes the container can use.
|
|
||||||
- `network=NETMODE` - Sets the network mode for the container.
|
|
||||||
- `cgroup-parent=CGROUP` - Sets the cgroup parent of the container if docker is using the "cgroupfs" driver. Defaults to `/docker/buildx`.
|
|
||||||
|
|
||||||
Before you configure the resource limits for the container, read about [configuring runtime resource constraints for containers](https://docs.docker.com/config/containers/resource_constraints/).
|
|
||||||
|
|
||||||
#### `kubernetes` driver
|
|
||||||
|
|
||||||
- `image=IMAGE` - Sets the container image to be used for running buildkit.
|
|
||||||
- `namespace=NS` - Sets the Kubernetes namespace. Defaults to the current namespace.
|
|
||||||
- `replicas=N` - Sets the number of `Pod` replicas. Defaults to 1.
|
|
||||||
- `requests.cpu` - Sets the request CPU value specified in units of Kubernetes CPU. Example `requests.cpu=100m`, `requests.cpu=2`
|
|
||||||
- `requests.memory` - Sets the request memory value specified in bytes or with a valid suffix. Example `requests.memory=500Mi`, `requests.memory=4G`
|
|
||||||
- `limits.cpu` - Sets the limit CPU value specified in units of Kubernetes CPU. Example `limits.cpu=100m`, `limits.cpu=2`
|
|
||||||
- `limits.memory` - Sets the limit memory value specified in bytes or with a valid suffix. Example `limits.memory=500Mi`, `limits.memory=4G`
|
|
||||||
- `serviceaccount` - Sets the created pod's service account. Example `serviceaccount=example-sa`
|
|
||||||
- `"nodeselector=label1=value1,label2=value2"` - Sets the kv of `Pod` nodeSelector. No Defaults. Example `nodeselector=kubernetes.io/arch=arm64`
|
|
||||||
- `"annotations=domain/thing1=value1,domain/thing2=value2"` - Sets additional annotations on the deployments and pods. No Defaults. Example `annotations=example.com/owner=sarah`
|
|
||||||
- `"labels=domain/thing1=value1,domain/thing2=value2"` - Sets additional labels on the deployments and pods. No Defaults. Example `labels=example.com/team=rd`
|
|
||||||
- `"tolerations=key=foo,value=bar;key=foo2,operator=exists;key=foo3,effect=NoSchedule"` - Sets the `Pod` tolerations. Accepts the same values as the kube manifest tolera>tions. Key-value pairs are separated by `,`, tolerations are separated by `;`. No Defaults. Example `tolerations=operator=exists`
|
|
||||||
- `rootless=(true|false)` - Run the container as a non-root user without `securityContext.privileged`. Needs Kubernetes 1.19 or later. [Using Ubuntu host kernel is recommended](https://github.com/moby/buildkit/blob/master/docs/rootless.md). Defaults to false.
|
|
||||||
- `loadbalance=(sticky|random)` - Load-balancing strategy. If set to "sticky", the pod is chosen using the hash of the context path. Defaults to "sticky"
|
|
||||||
- `qemu.install=(true|false)` - Install QEMU emulation for multi platforms support.
|
|
||||||
- `qemu.image=IMAGE` - Sets the QEMU emulation image. Defaults to `tonistiigi/binfmt:latest`
|
|
||||||
|
|
||||||
#### `remote` driver
|
|
||||||
|
|
||||||
- `key=KEY` - Sets the TLS client key.
|
|
||||||
- `cert=CERT` - Sets the TLS client certificate to present to buildkitd.
|
|
||||||
- `cacert=CACERT` - Sets the TLS certificate authority used for validation.
|
|
||||||
- `servername=SERVER` - Sets the TLS server name to be used in requests (defaults to the endpoint hostname).
|
|
||||||
|
|
||||||
### <a name="leave"></a> Remove a node from a builder (--leave)
|
### <a name="leave"></a> Remove a node from a builder (--leave)
|
||||||
|
|
||||||
@@ -201,7 +168,7 @@ $ docker buildx create --name mybuilder --node mybuilder0 --leave
|
|||||||
|
|
||||||
### <a name="name"></a> Specify the name of the builder (--name)
|
### <a name="name"></a> Specify the name of the builder (--name)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--name NAME
|
--name NAME
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -210,17 +177,17 @@ If none is specified, one will be automatically generated.
|
|||||||
|
|
||||||
### <a name="node"></a> Specify the name of the node (--node)
|
### <a name="node"></a> Specify the name of the node (--node)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--node NODE
|
--node NODE
|
||||||
```
|
```
|
||||||
|
|
||||||
The `--node` flag specifies the name of the node to be created or modified. If
|
The `--node` flag specifies the name of the node to be created or modified. If
|
||||||
none is specified, it is the name of the builder it belongs to, with an index
|
you don't specify a name, the node name defaults to the name of the builder it
|
||||||
number suffix.
|
belongs to, with an index number suffix.
|
||||||
|
|
||||||
### <a name="platform"></a> Set the platforms supported by the node (--platform)
|
### <a name="platform"></a> Set the platforms supported by the node (--platform)
|
||||||
|
|
||||||
```
|
```text
|
||||||
--platform PLATFORMS
|
--platform PLATFORMS
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# buildx du
|
# buildx du
|
||||||
|
|
||||||
```
|
```text
|
||||||
docker buildx du
|
docker buildx du
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# buildx imagetools
|
# buildx imagetools
|
||||||
|
|
||||||
```
|
```text
|
||||||
docker buildx imagetools [OPTIONS] COMMAND
|
docker buildx imagetools [OPTIONS] COMMAND
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -26,8 +26,9 @@ Commands to work on images in registry
|
|||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
Imagetools contains commands for working with manifest lists in the registry.
|
The `imagetools` commands contains subcommands for working with manifest lists
|
||||||
These commands are useful for inspecting multi-platform build results.
|
in container registries. These commands are useful for inspecting manifests
|
||||||
|
to check multi-platform configuration and attestations.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# buildx imagetools create
|
# buildx imagetools create
|
||||||
|
|
||||||
```
|
```text
|
||||||
docker buildx imagetools create [OPTIONS] [SOURCE] [SOURCE...]
|
docker buildx imagetools create [OPTIONS] [SOURCE] [SOURCE...]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ Create a new image based on source images
|
|||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
|:---------------------------------|:--------------|:--------|:-----------------------------------------------------------------------------------------|
|
|:---------------------------------|:--------------|:--------|:-----------------------------------------------------------------------------------------|
|
||||||
| `--annotation` | `stringArray` | | Add annotation to the image |
|
| [`--annotation`](#annotation) | `stringArray` | | Add annotation to the image |
|
||||||
| [`--append`](#append) | | | Append to existing manifest |
|
| [`--append`](#append) | | | Append to existing manifest |
|
||||||
| [`--builder`](#builder) | `string` | | Override the configured builder instance |
|
| [`--builder`](#builder) | `string` | | Override the configured builder instance |
|
||||||
| [`--dry-run`](#dry-run) | | | Show final image instead of pushing |
|
| [`--dry-run`](#dry-run) | | | Show final image instead of pushing |
|
||||||
@@ -31,6 +31,34 @@ specified, create performs a carbon copy.
|
|||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
### <a name="annotation"></a> Add annotations to an image (--annotation)
|
||||||
|
|
||||||
|
The `--annotation` flag lets you add annotations the image index, manifest,
|
||||||
|
and descriptors when creating a new image.
|
||||||
|
|
||||||
|
The following command creates a `foo/bar:latest` image with the
|
||||||
|
`org.opencontainers.image.authors` annotation on the image index.
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ docker buildx imagetools create \
|
||||||
|
--annotation "index:org.opencontainers.image.authors=dvdksn" \
|
||||||
|
--tag foo/bar:latest \
|
||||||
|
foo/bar:alpha foo/bar:beta foo/bar:gamma
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> The `imagetools create` command supports adding annotations to the image
|
||||||
|
> index and descriptor, using the following type prefixes:
|
||||||
|
>
|
||||||
|
> - `index:`
|
||||||
|
> - `manifest-descriptor:`
|
||||||
|
>
|
||||||
|
> It doesn't support annotating manifests or OCI layouts.
|
||||||
|
|
||||||
|
For more information about annotations, see
|
||||||
|
[Annotations](https://docs.docker.com/build/building/annotations/).
|
||||||
|
|
||||||
### <a name="append"></a> Append new sources to an existing manifest list (--append)
|
### <a name="append"></a> Append new sources to an existing manifest list (--append)
|
||||||
|
|
||||||
Use the `--append` flag to append the new sources to an existing manifest list
|
Use the `--append` flag to append the new sources to an existing manifest list
|
||||||
@@ -46,7 +74,7 @@ Use the `--dry-run` flag to not push the image, just show it.
|
|||||||
|
|
||||||
### <a name="file"></a> Read source descriptor from a file (-f, --file)
|
### <a name="file"></a> Read source descriptor from a file (-f, --file)
|
||||||
|
|
||||||
```
|
```text
|
||||||
-f FILE or --file FILE
|
-f FILE or --file FILE
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -67,7 +95,7 @@ The supported fields for the descriptor are defined in [OCI spec](https://github
|
|||||||
|
|
||||||
### <a name="tag"></a> Set reference for new image (-t, --tag)
|
### <a name="tag"></a> Set reference for new image (-t, --tag)
|
||||||
|
|
||||||
```
|
```text
|
||||||
-t IMAGE or --tag IMAGE
|
-t IMAGE or --tag IMAGE
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# buildx imagetools inspect
|
# buildx imagetools inspect
|
||||||
|
|
||||||
```
|
```text
|
||||||
docker buildx imagetools inspect [OPTIONS] NAME
|
docker buildx imagetools inspect [OPTIONS] NAME
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -123,23 +123,93 @@ Manifests:
|
|||||||
|
|
||||||
#### JSON output
|
#### JSON output
|
||||||
|
|
||||||
A `json` go template func is also available if you want to render fields as
|
A `json` template function is also available if you want to render fields in
|
||||||
JSON bytes:
|
JSON format:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker buildx imagetools inspect crazymax/loop --format "{{json .Manifest}}"
|
$ docker buildx imagetools inspect crazymax/buildkit:attest --format "{{json .Manifest}}"
|
||||||
```
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
"schemaVersion": 2,
|
||||||
"digest": "sha256:a9ca35b798e0b198f9be7f3b8b53982e9a6cf96814cb10d78083f40ad8c127f1",
|
"mediaType": "application/vnd.oci.image.index.v1+json",
|
||||||
"size": 949
|
"digest": "sha256:7007b387ccd52bd42a050f2e8020e56e64622c9269bf7bbe257b326fe99daf19",
|
||||||
|
"size": 855,
|
||||||
|
"manifests": [
|
||||||
|
{
|
||||||
|
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||||
|
"digest": "sha256:fbd10fe50b4b174bb9ea273e2eb9827fa8bf5c88edd8635a93dc83e0d1aecb55",
|
||||||
|
"size": 673,
|
||||||
|
"platform": {
|
||||||
|
"architecture": "amd64",
|
||||||
|
"os": "linux"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||||
|
"digest": "sha256:a9de632c16998489fd63fbca42a03431df00639cfb2ecb8982bf9984b83c5b2b",
|
||||||
|
"size": 839,
|
||||||
|
"annotations": {
|
||||||
|
"vnd.docker.reference.digest": "sha256:fbd10fe50b4b174bb9ea273e2eb9827fa8bf5c88edd8635a93dc83e0d1aecb55",
|
||||||
|
"vnd.docker.reference.type": "attestation-manifest"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"architecture": "unknown",
|
||||||
|
"os": "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ docker buildx imagetools inspect crazymax/buildkit:attest --format "{{json .Image}}"
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"created": "2022-12-01T11:46:47.713777178Z",
|
||||||
|
"architecture": "amd64",
|
||||||
|
"os": "linux",
|
||||||
|
"config": {
|
||||||
|
"Env": [
|
||||||
|
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
|
],
|
||||||
|
"Cmd": [
|
||||||
|
"/bin/sh"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rootfs": {
|
||||||
|
"type": "layers",
|
||||||
|
"diff_ids": [
|
||||||
|
"sha256:ded7a220bb058e28ee3254fbba04ca90b679070424424761a53a043b93b612bf",
|
||||||
|
"sha256:d85d09ab4b4e921666ccc2db8532e857bf3476b7588e52c9c17741d7af14204f"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"history": [
|
||||||
|
{
|
||||||
|
"created": "2022-11-22T22:19:28.870801855Z",
|
||||||
|
"created_by": "/bin/sh -c #(nop) ADD file:587cae71969871d3c6456d844a8795df9b64b12c710c275295a1182b46f630e7 in / "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"created": "2022-11-22T22:19:29.008562326Z",
|
||||||
|
"created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]",
|
||||||
|
"empty_layer": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"created": "2022-12-01T11:46:47.713777178Z",
|
||||||
|
"created_by": "RUN /bin/sh -c apk add curl # buildkit",
|
||||||
|
"comment": "buildkit.dockerfile.v0"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker buildx imagetools inspect moby/buildkit:master --format "{{json .Manifest}}"
|
$ docker buildx imagetools inspect moby/buildkit:master --format "{{json .Manifest}}"
|
||||||
```
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"schemaVersion": 2,
|
"schemaVersion": 2,
|
||||||
@@ -284,11 +354,13 @@ $ docker buildx imagetools inspect moby/buildkit:master --format "{{json .Manife
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Following command provides [SLSA](https://github.com/moby/buildkit/blob/master/docs/attestations/slsa-provenance.md) JSON output:
|
The following command provides [SLSA](https://github.com/moby/buildkit/blob/master/docs/attestations/slsa-provenance.md)
|
||||||
|
JSON output:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker buildx imagetools inspect crazymax/buildkit:attest --format "{{json .Provenance}}"
|
$ docker buildx imagetools inspect crazymax/buildkit:attest --format "{{json .Provenance}}"
|
||||||
```
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"SLSA": {
|
"SLSA": {
|
||||||
@@ -343,11 +415,13 @@ $ docker buildx imagetools inspect crazymax/buildkit:attest --format "{{json .Pr
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Following command provides [SBOM](https://github.com/moby/buildkit/blob/master/docs/attestations/sbom.md) JSON output:
|
The following command provides [SBOM](https://github.com/moby/buildkit/blob/master/docs/attestations/sbom.md)
|
||||||
|
JSON output:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker buildx imagetools inspect crazymax/buildkit:attest --format "{{json .SBOM}}"
|
$ docker buildx imagetools inspect crazymax/buildkit:attest --format "{{json .SBOM}}"
|
||||||
```
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"SPDX": {
|
"SPDX": {
|
||||||
@@ -372,6 +446,7 @@ $ docker buildx imagetools inspect crazymax/buildkit:attest --format "{{json .SB
|
|||||||
```console
|
```console
|
||||||
$ docker buildx imagetools inspect crazymax/buildkit:attest --format "{{json .}}"
|
$ docker buildx imagetools inspect crazymax/buildkit:attest --format "{{json .}}"
|
||||||
```
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"name": "crazymax/buildkit:attest",
|
"name": "crazymax/buildkit:attest",
|
||||||
@@ -440,75 +515,6 @@ $ docker buildx imagetools inspect crazymax/buildkit:attest --format "{{json .}}
|
|||||||
"comment": "buildkit.dockerfile.v0"
|
"comment": "buildkit.dockerfile.v0"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"Provenance": {
|
|
||||||
"SLSA": {
|
|
||||||
"builder": {
|
|
||||||
"id": ""
|
|
||||||
},
|
|
||||||
"buildType": "https://mobyproject.org/buildkit@v1",
|
|
||||||
"materials": [
|
|
||||||
{
|
|
||||||
"uri": "pkg:docker/docker/buildkit-syft-scanner@stable-1",
|
|
||||||
"digest": {
|
|
||||||
"sha256": "b45f1d207e16c3a3a5a10b254ad8ad358d01f7ea090d382b95c6b2ee2b3ef765"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uri": "pkg:docker/alpine@latest?platform=linux%2Famd64",
|
|
||||||
"digest": {
|
|
||||||
"sha256": "8914eb54f968791faf6a8638949e480fef81e697984fba772b3976835194c6d4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"invocation": {
|
|
||||||
"configSource": {},
|
|
||||||
"parameters": {
|
|
||||||
"frontend": "dockerfile.v0",
|
|
||||||
"locals": [
|
|
||||||
{
|
|
||||||
"name": "context"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "dockerfile"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"platform": "linux/amd64"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"metadata": {
|
|
||||||
"buildInvocationID": "02tdha2xkbxvin87mz9drhag4",
|
|
||||||
"buildStartedOn": "2022-12-01T11:50:07.264704131Z",
|
|
||||||
"buildFinishedOn": "2022-12-01T11:50:08.243788739Z",
|
|
||||||
"reproducible": false,
|
|
||||||
"completeness": {
|
|
||||||
"parameters": true,
|
|
||||||
"environment": true,
|
|
||||||
"materials": false
|
|
||||||
},
|
|
||||||
"https://mobyproject.org/buildkit@v1#metadata": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"SBOM": {
|
|
||||||
"SPDX": {
|
|
||||||
"SPDXID": "SPDXRef-DOCUMENT",
|
|
||||||
"creationInfo": {
|
|
||||||
"created": "2022-12-01T11:46:48.063400162Z",
|
|
||||||
"creators": [
|
|
||||||
"Tool: syft-v0.60.3",
|
|
||||||
"Tool: buildkit-1ace2bb",
|
|
||||||
"Organization: Anchore, Inc"
|
|
||||||
],
|
|
||||||
"licenseListVersion": "3.18"
|
|
||||||
},
|
|
||||||
"dataLicense": "CC0-1.0",
|
|
||||||
"documentNamespace": "https://anchore.com/syft/dir/run/src/core-0a4ccc6d-1a72-4c3a-a40e-3df1a2ffca94",
|
|
||||||
"files": [...],
|
|
||||||
"spdxVersion": "SPDX-2.2"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -522,6 +528,7 @@ go template function:
|
|||||||
```console
|
```console
|
||||||
$ docker buildx imagetools inspect --format '{{json (index .Image "linux/s390x")}}' moby/buildkit:master
|
$ docker buildx imagetools inspect --format '{{json (index .Image "linux/s390x")}}' moby/buildkit:master
|
||||||
```
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"created": "2022-11-30T17:42:26.414957336Z",
|
"created": "2022-11-30T17:42:26.414957336Z",
|
||||||
@@ -588,15 +595,14 @@ $ docker buildx imagetools inspect --format '{{json (index .Image "linux/s390x")
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### <a name="raw"></a> Show original, unformatted JSON manifest (--raw)
|
### <a name="raw"></a> Show original JSON manifest (--raw)
|
||||||
|
|
||||||
Use the `--raw` option to print the unformatted JSON manifest bytes.
|
Use the `--raw` option to print the raw JSON manifest.
|
||||||
|
|
||||||
> `jq` is used here to get a better rendering of the output result.
|
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker buildx imagetools inspect --raw crazymax/loop | jq
|
$ docker buildx imagetools inspect --raw crazymax/loop
|
||||||
```
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
||||||
@@ -629,6 +635,7 @@ $ docker buildx imagetools inspect --raw crazymax/loop | jq
|
|||||||
```console
|
```console
|
||||||
$ docker buildx imagetools inspect --raw moby/buildkit:master | jq
|
$ docker buildx imagetools inspect --raw moby/buildkit:master | jq
|
||||||
```
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
|
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# buildx inspect
|
# buildx inspect
|
||||||
|
|
||||||
```
|
```text
|
||||||
docker buildx inspect [NAME]
|
docker buildx inspect [NAME]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ Shows information about the current or specified builder.
|
|||||||
|
|
||||||
Use the `--bootstrap` option to ensure that the builder is running before
|
Use the `--bootstrap` option to ensure that the builder is running before
|
||||||
inspecting it. If the driver is `docker-container`, then `--bootstrap` starts
|
inspecting it. If the driver is `docker-container`, then `--bootstrap` starts
|
||||||
the buildkit container and waits until it is operational. Bootstrapping is
|
the BuildKit container and waits until it's operational. Bootstrapping is
|
||||||
automatically done during build, and therefore not necessary. The same BuildKit
|
automatically done during build, and therefore not necessary. The same BuildKit
|
||||||
container is used during the lifetime of the associated builder node (as
|
container is used during the lifetime of the associated builder node (as
|
||||||
displayed in `buildx ls`).
|
displayed in `buildx ls`).
|
||||||
@@ -45,7 +45,9 @@ The following example shows information about a builder instance named
|
|||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
> Asterisk `*` next to node build platform(s) indicate they had been set manually during `buildx create`. Otherwise, it had been autodetected.
|
> The asterisk (`*`) next to node build platform(s) indicate they have been
|
||||||
|
> manually set during `buildx create`. Otherwise the platforms were
|
||||||
|
> automatically detected.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker buildx inspect elated_tesla
|
$ docker buildx inspect elated_tesla
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# buildx ls
|
# buildx ls
|
||||||
|
|
||||||
```
|
```text
|
||||||
docker buildx ls
|
docker buildx ls
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# buildx prune
|
# buildx prune
|
||||||
|
|
||||||
```
|
```text
|
||||||
docker buildx prune
|
docker buildx prune
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# buildx rm
|
# buildx rm
|
||||||
|
|
||||||
```
|
```text
|
||||||
docker buildx rm [NAME]
|
docker buildx rm [NAME]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -50,10 +50,13 @@ $ docker buildx rm --all-inactive --force
|
|||||||
|
|
||||||
### <a name="keep-daemon"></a> Keep the buildkitd daemon running (--keep-daemon)
|
### <a name="keep-daemon"></a> Keep the buildkitd daemon running (--keep-daemon)
|
||||||
|
|
||||||
Keep the buildkitd daemon running after the buildx context is removed. This is useful when you manage buildkitd daemons and buildx contexts independently.
|
Keep the BuildKit daemon running after the buildx context is removed. This is
|
||||||
Currently, only supported by the [`docker-container` and `kubernetes` drivers](buildx_create.md#driver).
|
useful when you manage buildkitd daemons and buildx contexts independently.
|
||||||
|
Only supported by the
|
||||||
|
[`docker-container`](https://docs.docker.com/build/drivers/docker-container/)
|
||||||
|
and [`kubernetes`](https://docs.docker.com/build/drivers/kubernetes/) drivers.
|
||||||
|
|
||||||
### <a name="keep-state"></a> Keep BuildKit state (--keep-state)
|
### <a name="keep-state"></a> Keep BuildKit state (--keep-state)
|
||||||
|
|
||||||
Keep BuildKit state, so it can be reused by a new builder with the same name.
|
Keep BuildKit state, so it can be reused by a new builder with the same name.
|
||||||
Currently, only supported by the [`docker-container` driver](buildx_create.md#driver).
|
Currently, only supported by the [`docker-container` driver](https://docs.docker.com/build/drivers/docker-container/).
|
||||||
|
@@ -18,7 +18,7 @@ Stop builder instance
|
|||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
Stops the specified or current builder. This will not prevent buildx build to
|
Stops the specified or current builder. This does not prevent buildx build to
|
||||||
restart the builder. The implementation of stop depends on the driver.
|
restart the builder. The implementation of stop depends on the driver.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# buildx version
|
# buildx version
|
||||||
|
|
||||||
```
|
```text
|
||||||
docker buildx version
|
docker buildx version
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -16,5 +16,5 @@ View version information
|
|||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker buildx version
|
$ docker buildx version
|
||||||
github.com/docker/buildx v0.5.1-docker 11057da37336192bfc57d81e02359ba7ba848e4a
|
github.com/docker/buildx v0.11.2 9872040b6626fb7d87ef7296fd5b832e8cc2ad17
|
||||||
```
|
```
|
||||||
|
@@ -39,7 +39,10 @@ const (
|
|||||||
|
|
||||||
type Driver struct {
|
type Driver struct {
|
||||||
driver.InitConfig
|
driver.InitConfig
|
||||||
factory driver.Factory
|
factory driver.Factory
|
||||||
|
|
||||||
|
// if you add fields, remember to update docs:
|
||||||
|
// https://github.com/docker/docs/blob/main/content/build/drivers/docker-container.md
|
||||||
netMode string
|
netMode string
|
||||||
image string
|
image string
|
||||||
memory opts.MemBytes
|
memory opts.MemBytes
|
||||||
|
@@ -51,11 +51,11 @@ func (f *factory) New(ctx context.Context, cfg driver.InitConfig) (driver.Driver
|
|||||||
case k == "image":
|
case k == "image":
|
||||||
d.image = v
|
d.image = v
|
||||||
case k == "memory":
|
case k == "memory":
|
||||||
if err := d.memory.Set(v); err == nil {
|
if err := d.memory.Set(v); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case k == "memory-swap":
|
case k == "memory-swap":
|
||||||
if err := d.memorySwap.Set(v); err == nil {
|
if err := d.memorySwap.Set(v); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case k == "cpu-period":
|
case k == "cpu-period":
|
||||||
|
@@ -17,6 +17,8 @@ type Driver struct {
|
|||||||
factory driver.Factory
|
factory driver.Factory
|
||||||
driver.InitConfig
|
driver.InitConfig
|
||||||
|
|
||||||
|
// if you add fields, remember to update docs:
|
||||||
|
// https://github.com/docker/docs/blob/main/content/build/drivers/docker.md
|
||||||
features features
|
features features
|
||||||
hostGateway hostGateway
|
hostGateway hostGateway
|
||||||
}
|
}
|
||||||
|
@@ -38,7 +38,10 @@ const (
|
|||||||
|
|
||||||
type Driver struct {
|
type Driver struct {
|
||||||
driver.InitConfig
|
driver.InitConfig
|
||||||
factory driver.Factory
|
factory driver.Factory
|
||||||
|
|
||||||
|
// if you add fields, remember to update docs:
|
||||||
|
// https://github.com/docker/docs/blob/main/content/build/drivers/kubernetes.md
|
||||||
minReplicas int
|
minReplicas int
|
||||||
deployment *appsv1.Deployment
|
deployment *appsv1.Deployment
|
||||||
configMaps []*corev1.ConfigMap
|
configMaps []*corev1.ConfigMap
|
||||||
|
@@ -14,6 +14,9 @@ import (
|
|||||||
type Driver struct {
|
type Driver struct {
|
||||||
factory driver.Factory
|
factory driver.Factory
|
||||||
driver.InitConfig
|
driver.InitConfig
|
||||||
|
|
||||||
|
// if you add fields, remember to update docs:
|
||||||
|
// https://github.com/docker/docs/blob/main/content/build/drivers/remote.md
|
||||||
*tlsOpts
|
*tlsOpts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
39
tests/create.go
Normal file
39
tests/create.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/moby/buildkit/util/testutil/integration"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func createCmd(sb integration.Sandbox, opts ...cmdOpt) (string, error) {
|
||||||
|
opts = append([]cmdOpt{withArgs("create")}, opts...)
|
||||||
|
cmd := buildxCmd(sb, opts...)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
return string(out), err
|
||||||
|
}
|
||||||
|
|
||||||
|
var createTests = []func(t *testing.T, sb integration.Sandbox){
|
||||||
|
testCreateMemoryLimit,
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCreateMemoryLimit(t *testing.T, sb integration.Sandbox) {
|
||||||
|
if sb.Name() != "docker-container" {
|
||||||
|
t.Skip("only testing for docker-container driver")
|
||||||
|
}
|
||||||
|
|
||||||
|
var builderName string
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if builderName == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
out, err := rmCmd(sb, withArgs(builderName))
|
||||||
|
require.NoError(t, err, out)
|
||||||
|
})
|
||||||
|
|
||||||
|
out, err := createCmd(sb, withArgs("--driver", "docker-container", "--driver-opt", "network=host", "--driver-opt", "memory=1g"))
|
||||||
|
require.NoError(t, err, out)
|
||||||
|
builderName = strings.TrimSpace(out)
|
||||||
|
}
|
@@ -27,6 +27,7 @@ func TestIntegration(t *testing.T) {
|
|||||||
tests = append(tests, lsTests...)
|
tests = append(tests, lsTests...)
|
||||||
tests = append(tests, imagetoolsTests...)
|
tests = append(tests, imagetoolsTests...)
|
||||||
tests = append(tests, versionTests...)
|
tests = append(tests, versionTests...)
|
||||||
|
tests = append(tests, createTests...)
|
||||||
testIntegration(t, tests...)
|
testIntegration(t, tests...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
tests/rm.go
Normal file
12
tests/rm.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/moby/buildkit/util/testutil/integration"
|
||||||
|
)
|
||||||
|
|
||||||
|
func rmCmd(sb integration.Sandbox, opts ...cmdOpt) (string, error) {
|
||||||
|
opts = append([]cmdOpt{withArgs("rm")}, opts...)
|
||||||
|
cmd := buildxCmd(sb, opts...)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
return string(out), err
|
||||||
|
}
|
Reference in New Issue
Block a user