Compare commits

...

24 Commits

Author SHA1 Message Date
CrazyMax
2af40b75b7 Merge pull request #1415 from jedevc/cherry-pick-1383-to-0.9
[0.9] driver: don't create tracer delegate opt if tracer is nil
2022-11-21 10:29:09 +01:00
Justin Chadwell
83f3691c15 driver: don't create tracer delegate opt if tracer is nil
The error handling for the cast to client.TracerDelegate was incorrect,
and previously, a client would unconditionally append an opt.

This results in the scenario that while the ClientOpt was not nil, the
tracer delegate in the ClientOpt was, which isn't an error case
explicitly handled by buildkit.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2022-11-18 13:36:31 +00:00
CrazyMax
4e93e87991 Merge pull request #1409 from jedevc/cherry-pick-1406-to-0.9
[0.9] Synchronise access to the map when printing
2022-11-18 13:48:30 +01:00
Felix de Souza
3f1516d3fe Synchronise access to the map when printing.
Signed-off-by: Felix de Souza <fdesouza@palantir.com>
2022-11-15 15:54:43 +00:00
Tõnis Tiigi
09d1e1ee99 Merge pull request #1348 from AkihiroSuda/gcos-rootless-0.9
[v0.9] kubernetes: rootless: support Google Container-Optimized OS
2022-11-01 22:34:53 -07:00
Akihiro Suda
2e9906ba20 kubernetes: rootless: support Google Container-Optimized OS
Tested with GKE Autopilot 1.24.3-gke.200 (kernel 5.10.123+, containerd 1.6.6).

ref: moby/buildkit PR 3097

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
(cherry picked from commit 33e5f47c6c)
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
2022-10-07 18:57:26 +09:00
Tõnis Tiigi
ed00243a0c Merge pull request #1279 from jedevc/inspect-buildkit-version
inspect: add buildkit version information to command output
2022-08-18 09:44:29 -07:00
Tõnis Tiigi
1223e759a4 Merge pull request #1281 from jedevc/fixup-1273
Prevent duplicate "failed to find driver" message
2022-08-18 09:43:09 -07:00
Tõnis Tiigi
4fd3ec1a50 Merge pull request #1277 from crazy-max/fix-compose-merge
bake(compose): fix unskipped services without build context
2022-08-18 09:41:49 -07:00
Justin Chadwell
7f9cad1e4e buildx: prevent duplicate "failed to find driver" message
Signed-off-by: Justin Chadwell <me@jedevc.com>
2022-08-18 14:20:47 +01:00
Justin Chadwell
437b8b140f docs: update buildx inspect reference with buildkit version
Signed-off-by: Justin Chadwell <me@jedevc.com>
2022-08-18 11:27:38 +01:00
Justin Chadwell
8f0d9bd71f inspect: add buildkit version information to command output
Signed-off-by: Justin Chadwell <me@jedevc.com>
2022-08-18 11:03:03 +01:00
CrazyMax
9c22be5d9c bake: test compose file validation
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2022-08-18 11:34:41 +02:00
CrazyMax
42dea89247 bake: test for unknown extensions
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2022-08-18 11:34:40 +02:00
CrazyMax
982a332679 bake(compose): fix unskipped services without build context
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2022-08-18 11:34:40 +02:00
Justin Chadwell
441853f189 Merge pull request #1274 from jedevc/consistent-experimental-help
Consistent experimental help
2022-08-18 09:37:47 +01:00
Tõnis Tiigi
611329fc7f Merge pull request #1273 from jedevc/fix-1269
create: improve interface when attempting to create docker driver
2022-08-16 10:50:04 -07:00
Tõnis Tiigi
f3c135e583 Merge pull request #1275 from tonistiigi/update-buildx-220816
vendor: update buildkit to 55ba9d14
2022-08-16 10:47:40 -07:00
Tonis Tiigi
7f84582b37 vendor: update buildkit to 55ba9d14
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2022-08-16 10:22:36 -07:00
Justin Chadwell
297526c49d docs: add experimental options to build command reference
Signed-off-by: Justin Chadwell <me@jedevc.com>
2022-08-16 12:40:46 +01:00
Justin Chadwell
d01d394a2b build: ensure consistent help messages for experimental cli help
Append an [experimental] tag to the end of each experimental command to
highlight that these are experimental options. Square brackets are used
instead of parentheses as parentheses are already in use to highlight
examples and defaults.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2022-08-16 11:07:36 +01:00
Justin Chadwell
17d4369866 create: improve interface when attempting to create docker driver
Previously, the help information for buildx indicated that users could
create a new instance of the docker driver - which is explicitly
something we don't support, driver of this form are automatically
derived from the available list of docker contexts.

This patch ensures that don't have AllowsInstance set will not appear in
the help text, and additionally provide a new more specific error
message instead of the generic "failed to find driver". This should help
point users in the correct direction.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2022-08-16 10:58:23 +01:00
Tonis Tiigi
fb5e1393a4 commands: use buildx env for experimental opt-in
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2022-08-16 10:37:56 +01:00
Tonis Tiigi
18dbde9ed6 build: update outline fallback image
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2022-08-16 10:25:26 +01:00
24 changed files with 326 additions and 125 deletions

View File

@@ -200,15 +200,15 @@ func ParseFiles(files []File, defaults map[string]string) (_ *Config, err error)
}()
var c Config
var fs []*hcl.File
var composeFiles []File
var hclFiles []*hcl.File
for _, f := range files {
cfg, isCompose, composeErr := ParseComposeFile(f.Data, f.Name)
isCompose, composeErr := validateComposeFile(f.Data, f.Name)
if isCompose {
if composeErr != nil {
return nil, composeErr
}
c = mergeConfig(c, *cfg)
c = dedupeConfig(c)
composeFiles = append(composeFiles, f)
}
if !isCompose {
hf, isHCL, err := ParseHCLFile(f.Data, f.Name)
@@ -216,7 +216,7 @@ func ParseFiles(files []File, defaults map[string]string) (_ *Config, err error)
if err != nil {
return nil, err
}
fs = append(fs, hf)
hclFiles = append(hclFiles, hf)
} else if composeErr != nil {
return nil, fmt.Errorf("failed to parse %s: parsing yaml: %v, parsing hcl: %w", f.Name, composeErr, err)
} else {
@@ -225,8 +225,17 @@ func ParseFiles(files []File, defaults map[string]string) (_ *Config, err error)
}
}
if len(fs) > 0 {
if err := hclparser.Parse(hcl.MergeFiles(fs), hclparser.Opt{
if len(composeFiles) > 0 {
cfg, cmperr := ParseComposeFiles(composeFiles)
if cmperr != nil {
return nil, errors.Wrap(cmperr, "failed to parse compose file")
}
c = mergeConfig(c, *cfg)
c = dedupeConfig(c)
}
if len(hclFiles) > 0 {
if err := hclparser.Parse(hcl.MergeFiles(hclFiles), hclparser.Opt{
LookupVar: os.LookupEnv,
Vars: defaults,
ValidateLabel: validateTargetName,
@@ -234,18 +243,25 @@ func ParseFiles(files []File, defaults map[string]string) (_ *Config, err error)
return nil, err
}
}
return &c, nil
}
func dedupeConfig(c Config) Config {
c2 := c
c2.Groups = make([]*Group, 0, len(c2.Groups))
for _, g := range c.Groups {
g1 := *g
g1.Targets = dedupSlice(g1.Targets)
c2.Groups = append(c2.Groups, &g1)
}
c2.Targets = make([]*Target, 0, len(c2.Targets))
m := map[string]*Target{}
mt := map[string]*Target{}
for _, t := range c.Targets {
if t2, ok := m[t.Name]; ok {
if t2, ok := mt[t.Name]; ok {
t2.Merge(t)
} else {
m[t.Name] = t
mt[t.Name] = t
c2.Targets = append(c2.Targets, t)
}
}
@@ -256,26 +272,6 @@ func ParseFile(dt []byte, fn string) (*Config, error) {
return ParseFiles([]File{{Data: dt, Name: fn}}, nil)
}
func ParseComposeFile(dt []byte, fn string) (*Config, bool, error) {
envs := sliceToMap(os.Environ())
if wd, err := os.Getwd(); err == nil {
envs, err = loadDotEnv(envs, wd)
if err != nil {
return nil, true, err
}
}
fnl := strings.ToLower(fn)
if strings.HasSuffix(fnl, ".yml") || strings.HasSuffix(fnl, ".yaml") {
cfg, err := ParseCompose(dt, envs)
return cfg, true, err
}
if strings.HasSuffix(fnl, ".json") || strings.HasSuffix(fnl, ".hcl") {
return nil, false, nil
}
cfg, err := ParseCompose(dt, envs)
return cfg, err == nil, err
}
type Config struct {
Groups []*Group `json:"group" hcl:"group,block"`
Targets []*Target `json:"target" hcl:"target,block"`

View File

@@ -530,7 +530,8 @@ func TestReadEmptyTargets(t *testing.T) {
Name: "docker-compose.yml",
Data: []byte(`
services:
app2: {}
app2:
build: {}
`),
}
@@ -1226,3 +1227,35 @@ target "f" {
})
}
}
func TestUnknownExt(t *testing.T) {
dt := []byte(`
target "app" {
context = "dir"
args = {
v1 = "foo"
}
}
`)
dt2 := []byte(`
services:
app:
build:
dockerfile: Dockerfile-alternate
args:
v2: "bar"
`)
c, err := ParseFiles([]File{
{Data: dt, Name: "c1.foo"},
{Data: dt2, Name: "c2.bar"},
}, nil)
require.NoError(t, err)
require.Equal(t, 1, len(c.Targets))
require.Equal(t, "app", c.Targets[0].Name)
require.Equal(t, "foo", c.Targets[0].Args["v1"])
require.Equal(t, "bar", c.Targets[0].Args["v2"])
require.Equal(t, "dir", *c.Targets[0].Context)
require.Equal(t, "Dockerfile-alternate", *c.Targets[0].Dockerfile)
}

View File

@@ -1,7 +1,6 @@
package bake
import (
"fmt"
"os"
"path/filepath"
"strings"
@@ -13,25 +12,29 @@ import (
"gopkg.in/yaml.v3"
)
// errComposeInvalid is returned when a compose file is invalid
var errComposeInvalid = errors.New("invalid compose file")
func ParseCompose(dt []byte, envs map[string]string) (*Config, error) {
cfg, err := loader.Load(compose.ConfigDetails{
ConfigFiles: []compose.ConfigFile{
{
Content: dt,
},
},
Environment: envs,
}, func(options *loader.Options) {
options.SkipNormalization = true
options.SkipConsistencyCheck = true
})
func ParseComposeFiles(fs []File) (*Config, error) {
envs, err := composeEnv()
if err != nil {
return nil, err
}
if err = composeValidate(cfg); err != nil {
var cfgs []compose.ConfigFile
for _, f := range fs {
cfgs = append(cfgs, compose.ConfigFile{
Filename: f.Name,
Content: f.Data,
})
}
return ParseCompose(cfgs, envs)
}
func ParseCompose(cfgs []compose.ConfigFile, envs map[string]string) (*Config, error) {
cfg, err := loader.Load(compose.ConfigDetails{
ConfigFiles: cfgs,
Environment: envs,
}, func(options *loader.Options) {
options.SkipNormalization = true
})
if err != nil {
return nil, err
}
@@ -44,7 +47,7 @@ func ParseCompose(dt []byte, envs map[string]string) (*Config, error) {
for _, s := range cfg.Services {
if s.Build == nil {
s.Build = &compose.BuildConfig{}
continue
}
targetName := sanitizeTargetName(s.Name)
@@ -110,6 +113,50 @@ func ParseCompose(dt []byte, envs map[string]string) (*Config, error) {
return &c, nil
}
func validateComposeFile(dt []byte, fn string) (bool, error) {
envs, err := composeEnv()
if err != nil {
return true, err
}
fnl := strings.ToLower(fn)
if strings.HasSuffix(fnl, ".yml") || strings.HasSuffix(fnl, ".yaml") {
return true, validateCompose(dt, envs)
}
if strings.HasSuffix(fnl, ".json") || strings.HasSuffix(fnl, ".hcl") {
return false, nil
}
err = validateCompose(dt, envs)
return err == nil, err
}
func validateCompose(dt []byte, envs map[string]string) error {
_, err := loader.Load(compose.ConfigDetails{
ConfigFiles: []compose.ConfigFile{
{
Content: dt,
},
},
Environment: envs,
}, func(options *loader.Options) {
options.SkipNormalization = true
// consistency is checked later in ParseCompose to ensure multiple
// compose files can be merged together
options.SkipConsistencyCheck = true
})
return err
}
func composeEnv() (map[string]string, error) {
envs := sliceToMap(os.Environ())
if wd, err := os.Getwd(); err == nil {
envs, err = loadDotEnv(envs, wd)
if err != nil {
return nil, err
}
}
return envs, nil
}
func loadDotEnv(curenv map[string]string, workingDir string) (map[string]string, error) {
if curenv == nil {
curenv = make(map[string]string)
@@ -248,28 +295,6 @@ func (t *Target) composeExtTarget(exts map[string]interface{}) error {
return nil
}
// composeValidate validates a compose file
func composeValidate(project *compose.Project) error {
for _, s := range project.Services {
if s.Build != nil {
for _, secret := range s.Build.Secrets {
if _, ok := project.Secrets[secret.Source]; !ok {
return errors.Wrap(errComposeInvalid, fmt.Sprintf("service %q refers to undefined build secret %s", sanitizeTargetName(s.Name), secret.Source))
}
}
}
}
for name, secret := range project.Secrets {
if secret.External.External {
continue
}
if secret.File == "" && secret.Environment == "" {
return errors.Wrap(errComposeInvalid, fmt.Sprintf("secret %q must declare either `file` or `environment`", name))
}
}
return nil
}
// composeToBuildkitSecret converts secret from compose format to buildkit's
// csv format.
func composeToBuildkitSecret(inp compose.ServiceSecretConfig, psecret compose.SecretConfig) (string, error) {

View File

@@ -6,6 +6,8 @@ import (
"sort"
"testing"
compose "github.com/compose-spec/compose-go/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -38,7 +40,7 @@ secrets:
file: /root/.aws/credentials
`)
c, err := ParseCompose(dt, nil)
c, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
require.NoError(t, err)
require.Equal(t, 1, len(c.Groups))
@@ -76,9 +78,10 @@ services:
webapp:
build: ./db
`)
c, err := ParseCompose(dt, nil)
c, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
require.NoError(t, err)
require.Equal(t, 1, len(c.Groups))
require.Equal(t, 1, len(c.Targets))
}
func TestParseComposeTarget(t *testing.T) {
@@ -94,7 +97,7 @@ services:
target: webapp
`)
c, err := ParseCompose(dt, nil)
c, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
require.NoError(t, err)
require.Equal(t, 2, len(c.Targets))
@@ -119,7 +122,7 @@ services:
target: webapp
`)
c, err := ParseCompose(dt, nil)
c, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
require.NoError(t, err)
require.Equal(t, 2, len(c.Targets))
sort.Slice(c.Targets, func(i, j int) bool {
@@ -153,7 +156,7 @@ services:
os.Setenv("ZZZ_BAR", "zzz_foo")
defer os.Unsetenv("ZZZ_BAR")
c, err := ParseCompose(dt, sliceToMap(os.Environ()))
c, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, sliceToMap(os.Environ()))
require.NoError(t, err)
require.Equal(t, "bar", c.Targets[0].Args["FOO"])
require.Equal(t, "zzz_foo", c.Targets[0].Args["BAR"])
@@ -167,8 +170,8 @@ services:
entrypoint: echo 1
`)
_, err := ParseCompose(dt, nil)
require.NoError(t, err)
_, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
require.Error(t, err)
}
func TestAdvancedNetwork(t *testing.T) {
@@ -192,7 +195,7 @@ networks:
gateway: 10.5.0.254
`)
_, err := ParseCompose(dt, nil)
_, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
require.NoError(t, err)
}
@@ -209,7 +212,7 @@ services:
- bar
`)
c, err := ParseCompose(dt, nil)
c, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
require.NoError(t, err)
require.Equal(t, []string{"foo", "bar"}, c.Targets[0].Tags)
}
@@ -246,7 +249,7 @@ networks:
name: test-net
`)
_, err := ParseCompose(dt, nil)
_, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
require.NoError(t, err)
}
@@ -299,7 +302,7 @@ services:
no-cache: true
`)
c, err := ParseCompose(dt, nil)
c, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
require.NoError(t, err)
require.Equal(t, 2, len(c.Targets))
sort.Slice(c.Targets, func(i, j int) bool {
@@ -343,7 +346,7 @@ services:
- type=local,dest=path/to/cache
`)
c, err := ParseCompose(dt, nil)
c, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
require.NoError(t, err)
require.Equal(t, 1, len(c.Targets))
require.Equal(t, []string{"ct-addon:foo", "ct-addon:baz"}, c.Targets[0].Tags)
@@ -376,7 +379,7 @@ services:
- ` + envf.Name() + `
`)
c, err := ParseCompose(dt, nil)
c, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
require.NoError(t, err)
require.Equal(t, map[string]string{"CT_ECR": "foo", "FOO": "bsdf -csdf", "NODE_ENV": "test"}, c.Targets[0].Args)
}
@@ -397,7 +400,10 @@ services:
`)
chdir(t, tmpdir)
c, _, err := ParseComposeFile(dt, "docker-compose.yml")
c, err := ParseComposeFiles([]File{{
Name: "docker-compose.yml",
Data: dt,
}})
require.NoError(t, err)
require.Equal(t, map[string]string{"FOO": "bar"}, c.Targets[0].Args)
}
@@ -419,7 +425,7 @@ services:
published: "3306"
protocol: tcp
`)
_, err := ParseCompose(dt, nil)
_, err := ParseCompose([]compose.ConfigFile{{Content: dt}}, nil)
require.NoError(t, err)
}
@@ -465,12 +471,12 @@ func TestServiceName(t *testing.T) {
for _, tt := range cases {
tt := tt
t.Run(tt.svc, func(t *testing.T) {
_, err := ParseCompose([]byte(`
_, err := ParseCompose([]compose.ConfigFile{{Content: []byte(`
services:
`+tt.svc+`:
` + tt.svc + `:
build:
context: .
`), nil)
`)}}, nil)
if tt.wantErr {
require.Error(t, err)
} else {
@@ -536,7 +542,84 @@ services:
for _, tt := range cases {
tt := tt
t.Run(tt.name, func(t *testing.T) {
_, err := ParseCompose(tt.dt, nil)
_, err := ParseCompose([]compose.ConfigFile{{Content: tt.dt}}, nil)
if tt.wantErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
})
}
}
func TestValidateComposeFile(t *testing.T) {
cases := []struct {
name string
fn string
dt []byte
isCompose bool
wantErr bool
}{
{
name: "empty service",
fn: "docker-compose.yml",
dt: []byte(`
services:
foo:
`),
isCompose: true,
wantErr: true,
},
{
name: "build",
fn: "docker-compose.yml",
dt: []byte(`
services:
foo:
build: .
`),
isCompose: true,
wantErr: false,
},
{
name: "image",
fn: "docker-compose.yml",
dt: []byte(`
services:
simple:
image: nginx
`),
isCompose: true,
wantErr: false,
},
{
name: "unknown ext",
fn: "docker-compose.foo",
dt: []byte(`
services:
simple:
image: nginx
`),
isCompose: true,
wantErr: false,
},
{
name: "hcl",
fn: "docker-bake.hcl",
dt: []byte(`
target "default" {
dockerfile = "test"
}
`),
isCompose: false,
wantErr: false,
},
}
for _, tt := range cases {
tt := tt
t.Run(tt.name, func(t *testing.T) {
isCompose, err := validateComposeFile(tt.dt, tt.fn)
assert.Equal(t, tt.isCompose, isCompose)
if tt.wantErr {
require.Error(t, err)
} else {

View File

@@ -59,7 +59,7 @@ var (
)
const (
printFallbackImage = "docker/dockerfile-upstream:1.4-outline@sha256:ccd574ab34a8875c64bb6a8fb3cfae2e6d62d31b28b9f688075cc14c9b669a59"
printFallbackImage = "docker/dockerfile-upstream:1.4-outline@sha256:627443ff4e2d0f635d429cfc1da5388bcd5a70949c38adcd3cd7c4e5df67c73c"
)
type Options struct {

View File

@@ -479,7 +479,7 @@ func buildCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
flags.StringArrayVar(&options.platforms, "platform", platformsDefault, "Set target platform for build")
if isExperimental() {
flags.StringVar(&options.printFunc, "print", "", "Print result of information request (outline, targets)")
flags.StringVar(&options.printFunc, "print", "", "Print result of information request (e.g., outline, targets) [experimental]")
}
flags.BoolVar(&options.exportPush, "push", false, `Shorthand for "--output=type=registry"`)
@@ -501,7 +501,7 @@ func buildCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
flags.Var(options.ulimits, "ulimit", "Ulimit options")
if isExperimental() {
flags.StringVar(&options.invoke, "invoke", "", "Invoke a command after the build. BUILDX_EXPERIMENTAL=1 is required.")
flags.StringVar(&options.invoke, "invoke", "", "Invoke a command after the build [experimental]")
}
// hidden flags
@@ -701,7 +701,7 @@ func (w *wrapped) Unwrap() error {
}
func isExperimental() bool {
if v, ok := os.LookupEnv("BUILDKIT_EXPERIMENTAL"); ok {
if v, ok := os.LookupEnv("BUILDX_EXPERIMENTAL"); ok {
vv, _ := strconv.ParseBool(v)
return vv
}

View File

@@ -135,8 +135,8 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
}
}
if driver.GetFactory(driverName, true) == nil {
return errors.Errorf("failed to find driver %q", driverName)
if _, err := driver.GetFactory(driverName, true); err != nil {
return err
}
ngOriginal := ng
@@ -282,7 +282,7 @@ func createCmd(dockerCli command.Cli) *cobra.Command {
var options createOptions
var drivers bytes.Buffer
for _, d := range driver.GetFactories() {
for _, d := range driver.GetFactories(true) {
if len(drivers.String()) > 0 {
drivers.WriteString(", ")
}

View File

@@ -115,6 +115,9 @@ func runInspect(dockerCli command.Cli, in inspectOptions) error {
if len(n.Flags) > 0 {
fmt.Fprintf(w, "Flags:\t%s\n", strings.Join(n.Flags, " "))
}
if ngi.drivers[i].version != "" {
fmt.Fprintf(w, "Buildkit:\t%s\n", ngi.drivers[i].version)
}
fmt.Fprintf(w, "Platforms:\t%s\n", strings.Join(platformutil.FormatInGroups(n.Platforms, ngi.drivers[i].platforms), ", "))
}
}

View File

@@ -60,9 +60,10 @@ func driversForNodeGroup(ctx context.Context, dockerCli command.Cli, ng *store.N
var f driver.Factory
if ng.Driver != "" {
f = driver.GetFactory(ng.Driver, true)
if f == nil {
return nil, errors.Errorf("failed to find driver %q", f)
var err error
f, err = driver.GetFactory(ng.Driver, true)
if err != nil {
return nil, err
}
} else {
// empty driver means nodegroup was implicitly created as a default

View File

@@ -20,6 +20,7 @@ target "_common" {
args = {
GO_VERSION = GO_VERSION
BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1
BUILDX_EXPERIMENTAL = 1
}
}

View File

@@ -25,6 +25,7 @@ Start a build
| [`--cgroup-parent`](https://docs.docker.com/engine/reference/commandline/build/#use-a-custom-parent-cgroup---cgroup-parent) | `string` | | Optional parent cgroup for the container |
| [`-f`](https://docs.docker.com/engine/reference/commandline/build/#specify-a-dockerfile--f), [`--file`](https://docs.docker.com/engine/reference/commandline/build/#specify-a-dockerfile--f) | `string` | | Name of the Dockerfile (default: `PATH/Dockerfile`) |
| `--iidfile` | `string` | | Write the image ID to the file |
| `--invoke` | `string` | | Invoke a command after the build [experimental] |
| `--label` | `stringArray` | | Set metadata for an image |
| [`--load`](#load) | | | Shorthand for `--output=type=docker` |
| [`--metadata-file`](#metadata-file) | `string` | | Write build result metadata to the file |
@@ -33,6 +34,7 @@ Start a build
| `--no-cache-filter` | `stringArray` | | Do not cache specified stages |
| [`-o`](#output), [`--output`](#output) | `stringArray` | | Output destination (format: `type=local,dest=path`) |
| [`--platform`](#platform) | `stringArray` | | Set target platform for build |
| `--print` | `string` | | Print result of information request (e.g., outline, targets) [experimental] |
| [`--progress`](#progress) | `string` | `auto` | Set type of progress output (`auto`, `plain`, `tty`). Use plain to show container output |
| `--pull` | | | Always attempt to pull all referenced images |
| [`--push`](#push) | | | Shorthand for `--output=type=registry` |
@@ -47,6 +49,9 @@ Start a build
<!---MARKER_GEN_END-->
Flags marked with `[experimental]` need to be explicitly enabled by setting the
`BUILDX_EXPERIMENTAL=1` environment variable.
## Description
The `buildx build` command starts a build using BuildKit. This command is similar

View File

@@ -15,7 +15,7 @@ Create a new builder instance
| `--bootstrap` | | | Boot builder after creation |
| [`--buildkitd-flags`](#buildkitd-flags) | `string` | | Flags for buildkitd daemon |
| [`--config`](#config) | `string` | | BuildKit config file |
| [`--driver`](#driver) | `string` | | Driver to use (available: `docker`, `docker-container`, `kubernetes`, `remote`) |
| [`--driver`](#driver) | `string` | | Driver to use (available: `docker-container`, `kubernetes`, `remote`) |
| [`--driver-opt`](#driver-opt) | `stringArray` | | Options for the driver |
| [`--leave`](#leave) | | | Remove a node from builder instead of changing it |
| [`--name`](#name) | `string` | | Builder instance name |

View File

@@ -44,7 +44,7 @@ The following example shows information about a builder instance named
`elated_tesla`:
> **Note**
>
>
> Asterisk `*` next to node build platform(s) indicate they had been set manually during `buildx create`. Otherwise, it had been autodetected.
```console
@@ -57,10 +57,12 @@ Nodes:
Name: elated_tesla0
Endpoint: unix:///var/run/docker.sock
Status: running
Buildkit: v0.10.3
Platforms: linux/amd64
Name: elated_tesla1
Endpoint: ssh://ubuntu@1.2.3.4
Status: running
Buildkit: v0.10.3
Platforms: linux/arm64*, linux/arm/v7, linux/arm/v6
```

View File

@@ -357,11 +357,14 @@ func (d *Driver) Client(ctx context.Context) (*client.Client, error) {
return nil, err
}
td, _ := exp.(client.TracerDelegate)
return client.New(ctx, "", client.WithContextDialer(func(context.Context, string) (net.Conn, error) {
var opts []client.ClientOpt
opts = append(opts, client.WithContextDialer(func(context.Context, string) (net.Conn, error) {
return conn, nil
}), client.WithTracerDelegate(td))
}))
if td, ok := exp.(client.TracerDelegate); ok {
opts = append(opts, client.WithTracerDelegate(td))
}
return client.New(ctx, "", opts...)
}
func (d *Driver) Factory() driver.Factory {

View File

@@ -215,11 +215,14 @@ func (d *Driver) Client(ctx context.Context) (*client.Client, error) {
return nil, err
}
td, _ := exp.(client.TracerDelegate)
return client.New(ctx, "", client.WithContextDialer(func(context.Context, string) (net.Conn, error) {
var opts []client.ClientOpt
opts = append(opts, client.WithContextDialer(func(context.Context, string) (net.Conn, error) {
return conn, nil
}), client.WithTracerDelegate(td))
}))
if td, ok := exp.(client.TracerDelegate); ok {
opts = append(opts, client.WithTracerDelegate(td))
}
return client.New(ctx, "", opts...)
}
func (d *Driver) Factory() driver.Factory {

View File

@@ -213,6 +213,24 @@ func toRootless(d *appsv1.Deployment) error {
d.Spec.Template.ObjectMeta.Annotations = make(map[string]string, 1)
}
d.Spec.Template.ObjectMeta.Annotations["container.apparmor.security.beta.kubernetes.io/"+containerName] = "unconfined"
// Dockerfile has `VOLUME /home/user/.local/share/buildkit` by default too,
// but the default VOLUME does not work with rootless on Google's Container-Optimized OS
// as it is mounted with `nosuid,nodev`.
// https://github.com/moby/buildkit/issues/879#issuecomment-1240347038
// https://github.com/moby/buildkit/pull/3097
const emptyDirVolName = "buildkitd"
d.Spec.Template.Spec.Containers[0].VolumeMounts = append(d.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
Name: emptyDirVolName,
MountPath: "/home/user/.local/share/buildkit",
})
d.Spec.Template.Spec.Volumes = append(d.Spec.Template.Spec.Volumes, corev1.Volume{
Name: emptyDirVolName,
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
})
return nil
}

View File

@@ -92,16 +92,16 @@ func GetDefaultFactory(ctx context.Context, ep string, c dockerclient.APIClient,
return dd[0].f, nil
}
func GetFactory(name string, instanceRequired bool) Factory {
func GetFactory(name string, instanceRequired bool) (Factory, error) {
for _, f := range drivers {
if instanceRequired && !f.AllowsInstances() {
continue
}
if f.Name() == name {
return f
if instanceRequired && !f.AllowsInstances() {
return nil, errors.Errorf("additional instances of driver %q cannot be created", name)
}
return f, nil
}
}
return nil
return nil, errors.Errorf("failed to find driver %q", name)
}
func GetDriver(ctx context.Context, name string, f Factory, endpointAddr string, api dockerclient.APIClient, auth Auth, kcc KubeClientConfig, flags []string, files map[string][]byte, do map[string]string, platforms []specs.Platform, contextPathHash string) (Driver, error) {
@@ -131,9 +131,12 @@ func GetDriver(ctx context.Context, name string, f Factory, endpointAddr string,
return &cachedDriver{Driver: d}, nil
}
func GetFactories() []Factory {
func GetFactories(instanceRequired bool) []Factory {
ds := make([]Factory, 0, len(drivers))
for _, d := range drivers {
if instanceRequired && !d.AllowsInstances() {
continue
}
ds = append(ds, d)
}
sort.Slice(ds, func(i, j int) bool {

2
go.mod
View File

@@ -15,7 +15,7 @@ require (
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/hashicorp/go-cty-funcs v0.0.0-20200930094925-2721b1e36840
github.com/hashicorp/hcl/v2 v2.8.2
github.com/moby/buildkit v0.10.1-0.20220809151411-8488654e899b
github.com/moby/buildkit v0.10.1-0.20220816171719-55ba9d14360a
github.com/morikuni/aec v1.0.0
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799

4
go.sum
View File

@@ -411,8 +411,8 @@ github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZX
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/buildkit v0.10.1-0.20220809151411-8488654e899b h1:F/f/Ixaw8REoF5EjkMLh/2RBrsP0jeCPGBlczfqy9aw=
github.com/moby/buildkit v0.10.1-0.20220809151411-8488654e899b/go.mod h1:Wa+LkeUQ9NJTVXTAY38rhkfKVQcuCIo2fbavRSuGsbI=
github.com/moby/buildkit v0.10.1-0.20220816171719-55ba9d14360a h1:NI01Z14Hbwo1MHq8ylu4HNkmKGnhk8UZsD6c6FVMcA8=
github.com/moby/buildkit v0.10.1-0.20220816171719-55ba9d14360a/go.mod h1:Wa+LkeUQ9NJTVXTAY38rhkfKVQcuCIo2fbavRSuGsbI=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=

View File

@@ -14,6 +14,7 @@ RUN apk add --no-cache rsync git
WORKDIR /src
COPY --from=docsgen /out/docsgen /usr/bin
ARG FORMATS
ARG BUILDX_EXPERIMENTAL
RUN --mount=target=/context \
--mount=target=.,type=tmpfs <<EOT
set -e

View File

@@ -8,6 +8,7 @@ import (
"os"
"sort"
"strings"
"sync"
"text/tabwriter"
"text/template"
@@ -112,7 +113,9 @@ func (p *Printer) Print(raw bool, out io.Writer) error {
}
imageconfigs := make(map[string]*ocispecs.Image)
imageconfigsMutex := sync.Mutex{}
buildinfos := make(map[string]*binfotypes.BuildInfo)
buildinfosMutex := sync.Mutex{}
eg, _ := errgroup.WithContext(p.ctx)
for _, platform := range p.platforms {
@@ -122,12 +125,16 @@ func (p *Printer) Print(raw bool, out io.Writer) error {
if err != nil {
return err
} else if img != nil {
imageconfigsMutex.Lock()
imageconfigs[platforms.Format(platform)] = img
imageconfigsMutex.Unlock()
}
if bi, err := imageutil.BuildInfo(dtic); err != nil {
return err
} else if bi != nil {
buildinfosMutex.Lock()
buildinfos[platforms.Format(platform)] = bi
buildinfosMutex.Unlock()
}
return nil
})

View File

@@ -101,7 +101,7 @@ func PrintOutline(dt []byte, w io.Writer) error {
fmt.Fprintf(tw, "DESCRIPTION:\t%s\n", o.Description)
}
tw.Flush()
fmt.Println()
fmt.Fprintln(tw)
}
if len(o.Args) > 0 {
@@ -111,7 +111,7 @@ func PrintOutline(dt []byte, w io.Writer) error {
fmt.Fprintf(tw, "%s\t%s\t%s\n", a.Name, a.Value, a.Description)
}
tw.Flush()
fmt.Println()
fmt.Fprintln(tw)
}
if len(o.Secrets) > 0 {
@@ -125,7 +125,7 @@ func PrintOutline(dt []byte, w io.Writer) error {
fmt.Fprintf(tw, "%s\t%s\n", s.Name, b)
}
tw.Flush()
fmt.Println()
fmt.Fprintln(tw)
}
if len(o.SSH) > 0 {
@@ -139,7 +139,7 @@ func PrintOutline(dt []byte, w io.Writer) error {
fmt.Fprintf(tw, "%s\t%s\n", s.Name, b)
}
tw.Flush()
fmt.Println()
fmt.Fprintln(tw)
}
return nil

View File

@@ -274,3 +274,20 @@ func (pw *noOpWriter) Write(_ string, _ interface{}) error {
func (pw *noOpWriter) Close() error {
return nil
}
func OneOff(ctx context.Context, id string) func(err error) error {
pw, _, _ := NewFromContext(ctx)
now := time.Now()
st := Status{
Started: &now,
}
pw.Write(id, st)
return func(err error) error {
// TODO: set error on status
now := time.Now()
st.Completed = &now
pw.Write(id, st)
pw.Close()
return err
}
}

2
vendor/modules.txt vendored
View File

@@ -358,7 +358,7 @@ github.com/mitchellh/go-wordwrap
# github.com/mitchellh/mapstructure v1.5.0
## explicit; go 1.14
github.com/mitchellh/mapstructure
# github.com/moby/buildkit v0.10.1-0.20220809151411-8488654e899b
# github.com/moby/buildkit v0.10.1-0.20220816171719-55ba9d14360a
## explicit; go 1.17
github.com/moby/buildkit/api/services/control
github.com/moby/buildkit/api/types