diff --git a/cmd/buildkitd/config/config.go b/cmd/buildkitd/config/config.go index 54df63d00133..bd568574326e 100644 --- a/cmd/buildkitd/config/config.go +++ b/cmd/buildkitd/config/config.go @@ -26,6 +26,8 @@ type Config struct { } `toml:"worker"` Registries map[string]RegistryConfig `toml:"registry"` + + DNS *DNSConfig `toml:"dns"` } type GRPCConfig struct { @@ -85,6 +87,12 @@ type GCPolicy struct { Filters []string `toml:"filters"` } +type DNSConfig struct { + Nameservers []string `toml:"nameservers"` + Options []string `toml:"options"` + SearchDomains []string `toml:"searchDomains"` +} + func Load(r io.Reader) (Config, *toml.MetaData, error) { var c Config md, err := toml.DecodeReader(r, &c) diff --git a/cmd/buildkitd/config/config_test.go b/cmd/buildkitd/config/config_test.go index 3f8dee5090f9..fe27c7d630fa 100644 --- a/cmd/buildkitd/config/config_test.go +++ b/cmd/buildkitd/config/config_test.go @@ -51,6 +51,11 @@ keepDuration=7200 [registry."docker.io"] mirrors=["hub.docker.io"] http=true + +[dns] +nameservers=["1.1.1.1","8.8.8.8"] +options=["edns0"] +searchDomains=["example.com"] ` cfg, md, err := Load(bytes.NewBuffer([]byte(testConfig))) @@ -98,4 +103,9 @@ http=true require.Equal(t, cfg.Registries["docker.io"].PlainHTTP, true) require.Equal(t, cfg.Registries["docker.io"].Mirrors[0], "hub.docker.io") + + require.NotNil(t, cfg.DNS) + require.Equal(t, cfg.DNS.Nameservers, []string{"1.1.1.1", "8.8.8.8"}) + require.Equal(t, cfg.DNS.SearchDomains, []string{"example.com"}) + require.Equal(t, cfg.DNS.Options, []string{"edns0"}) } diff --git a/cmd/buildkitd/main.go b/cmd/buildkitd/main.go index d2ec6818580b..afcbc248c330 100644 --- a/cmd/buildkitd/main.go +++ b/cmd/buildkitd/main.go @@ -31,6 +31,7 @@ import ( "github.com/moby/buildkit/client" "github.com/moby/buildkit/cmd/buildkitd/config" "github.com/moby/buildkit/control" + "github.com/moby/buildkit/executor/oci" "github.com/moby/buildkit/frontend" dockerfile "github.com/moby/buildkit/frontend/dockerfile/builder" "github.com/moby/buildkit/frontend/gateway" @@ -685,3 +686,15 @@ func getGCPolicy(cfg config.GCConfig, root string) []client.PruneInfo { } return out } + +func getDNSConfig(cfg *config.DNSConfig) *oci.DNSConfig { + var dns *oci.DNSConfig + if cfg != nil { + dns = &oci.DNSConfig{ + Nameservers: cfg.Nameservers, + Options: cfg.Options, + SearchDomains: cfg.SearchDomains, + } + } + return dns +} diff --git a/cmd/buildkitd/main_containerd_worker.go b/cmd/buildkitd/main_containerd_worker.go index 9b94e91fb784..e3e933831545 100644 --- a/cmd/buildkitd/main_containerd_worker.go +++ b/cmd/buildkitd/main_containerd_worker.go @@ -172,7 +172,9 @@ func containerdWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([ return nil, nil } - opt, err := containerd.NewWorkerOpt(common.config.Root, cfg.Address, ctd.DefaultSnapshotter, cfg.Namespace, cfg.Labels, ctd.WithTimeout(60*time.Second)) + dns := getDNSConfig(common.config.DNS) + + opt, err := containerd.NewWorkerOpt(common.config.Root, cfg.Address, ctd.DefaultSnapshotter, cfg.Namespace, cfg.Labels, dns, ctd.WithTimeout(60*time.Second)) if err != nil { return nil, err } diff --git a/cmd/buildkitd/main_oci_worker.go b/cmd/buildkitd/main_oci_worker.go index d86d491d501b..93f94a97bf4c 100644 --- a/cmd/buildkitd/main_oci_worker.go +++ b/cmd/buildkitd/main_oci_worker.go @@ -192,7 +192,9 @@ func ociWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([]worker processMode = oci.NoProcessSandbox } - opt, err := runc.NewWorkerOpt(common.config.Root, snFactory, cfg.Rootless, processMode, cfg.Labels, idmapping) + dns := getDNSConfig(common.config.DNS) + + opt, err := runc.NewWorkerOpt(common.config.Root, snFactory, cfg.Rootless, processMode, cfg.Labels, idmapping, dns) if err != nil { return nil, err } diff --git a/executor/containerdexecutor/executor.go b/executor/containerdexecutor/executor.go index 748c457a772c..0ff4d3363bd9 100644 --- a/executor/containerdexecutor/executor.go +++ b/executor/containerdexecutor/executor.go @@ -30,10 +30,11 @@ type containerdExecutor struct { root string networkProviders map[pb.NetMode]network.Provider cgroupParent string + dnsConfig *oci.DNSConfig } // New creates a new executor backed by connection to containerd API -func New(client *containerd.Client, root, cgroup string, networkProviders map[pb.NetMode]network.Provider) executor.Executor { +func New(client *containerd.Client, root, cgroup string, networkProviders map[pb.NetMode]network.Provider, dnsConfig *oci.DNSConfig) executor.Executor { // clean up old hosts/resolv.conf file. ignore errors os.RemoveAll(filepath.Join(root, "hosts")) os.RemoveAll(filepath.Join(root, "resolv.conf")) @@ -43,13 +44,14 @@ func New(client *containerd.Client, root, cgroup string, networkProviders map[pb root: root, networkProviders: networkProviders, cgroupParent: cgroup, + dnsConfig: dnsConfig, } } func (w containerdExecutor) Exec(ctx context.Context, meta executor.Meta, root cache.Mountable, mounts []executor.Mount, stdin io.ReadCloser, stdout, stderr io.WriteCloser) (err error) { id := identity.NewID() - resolvConf, err := oci.GetResolvConf(ctx, w.root, nil) + resolvConf, err := oci.GetResolvConf(ctx, w.root, nil, w.dnsConfig) if err != nil { return err } diff --git a/executor/oci/resolvconf.go b/executor/oci/resolvconf.go index 422f1ab9621b..3d568f7b5d13 100644 --- a/executor/oci/resolvconf.go +++ b/executor/oci/resolvconf.go @@ -8,6 +8,7 @@ import ( "github.com/docker/docker/pkg/idtools" "github.com/docker/libnetwork/resolvconf" + "github.com/docker/libnetwork/types" "github.com/moby/buildkit/util/flightcontrol" ) @@ -15,7 +16,13 @@ var g flightcontrol.Group var notFirstRun bool var lastNotEmpty bool -func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.IdentityMapping) (string, error) { +type DNSConfig struct { + Nameservers []string + Options []string + SearchDomains []string +} + +func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.IdentityMapping, dns *DNSConfig) (string, error) { p := filepath.Join(stateDir, "resolv.conf") _, err := g.Do(ctx, stateDir, func(ctx context.Context) (interface{}, error) { generate := !notFirstRun @@ -61,9 +68,34 @@ func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.Identity dt = f.Content } - f, err = resolvconf.FilterResolvDNS(dt, true) - if err != nil { - return "", err + if dns != nil { + var ( + dnsNameservers = resolvconf.GetNameservers(dt, types.IP) + dnsSearchDomains = resolvconf.GetSearchDomains(dt) + dnsOptions = resolvconf.GetOptions(dt) + ) + if len(dns.Nameservers) > 0 { + dnsNameservers = dns.Nameservers + } + if len(dns.SearchDomains) > 0 { + dnsSearchDomains = dns.SearchDomains + } + if len(dns.Options) > 0 { + dnsOptions = dns.Options + } + + f, err = resolvconf.Build(p+".tmp", dnsNameservers, dnsSearchDomains, dnsOptions) + if err != nil { + return "", err + } + } else { + // Logic seems odd here: why are we filtering localhost IPs + // only if neither of the DNS configs were specified? + // Logic comes from https://github.com/docker/libnetwork/blob/164a77ee6d24fb2b1d61f8ad3403a51d8453899e/sandbox_dns_unix.go#L230-L269 + f, err = resolvconf.FilterResolvDNS(f.Content, true) + if err != nil { + return "", err + } } tmpPath := p + ".tmp" diff --git a/executor/runcexecutor/executor.go b/executor/runcexecutor/executor.go index 680bc7b34665..741c8b897845 100644 --- a/executor/runcexecutor/executor.go +++ b/executor/runcexecutor/executor.go @@ -43,6 +43,7 @@ type Opt struct { IdentityMapping *idtools.IdentityMapping // runc run --no-pivot (unrecommended) NoPivot bool + DNS *oci.DNSConfig } var defaultCommandCandidates = []string{"buildkit-runc", "runc"} @@ -57,6 +58,7 @@ type runcExecutor struct { processMode oci.ProcessMode idmap *idtools.IdentityMapping noPivot bool + dns *oci.DNSConfig } func New(opt Opt, networkProviders map[pb.NetMode]network.Provider) (executor.Executor, error) { @@ -115,6 +117,7 @@ func New(opt Opt, networkProviders map[pb.NetMode]network.Provider) (executor.Ex processMode: opt.ProcessMode, idmap: opt.IdentityMapping, noPivot: opt.NoPivot, + dns: opt.DNS, } return w, nil } @@ -134,7 +137,7 @@ func (w *runcExecutor) Exec(ctx context.Context, meta executor.Meta, root cache. logrus.Info("enabling HostNetworking") } - resolvConf, err := oci.GetResolvConf(ctx, w.root, w.idmap) + resolvConf, err := oci.GetResolvConf(ctx, w.root, w.idmap, w.dns) if err != nil { return err } diff --git a/vendor/modules.txt b/vendor/modules.txt index ab3edc485b22..889c9fbe52ef 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -151,8 +151,8 @@ github.com/docker/go-events github.com/docker/go-units # github.com/docker/libnetwork v0.8.0-dev.2.0.20190604151032-3c26b4e7495e github.com/docker/libnetwork/resolvconf -github.com/docker/libnetwork/resolvconf/dns github.com/docker/libnetwork/types +github.com/docker/libnetwork/resolvconf/dns # github.com/gofrs/flock v0.7.0 github.com/gofrs/flock # github.com/gogo/googleapis v1.1.0 diff --git a/worker/containerd/containerd.go b/worker/containerd/containerd.go index c2ec480b2846..936f2cb26506 100644 --- a/worker/containerd/containerd.go +++ b/worker/containerd/containerd.go @@ -13,6 +13,7 @@ import ( "github.com/containerd/containerd/snapshots" "github.com/moby/buildkit/cache/metadata" "github.com/moby/buildkit/executor/containerdexecutor" + "github.com/moby/buildkit/executor/oci" "github.com/moby/buildkit/identity" containerdsnapshot "github.com/moby/buildkit/snapshot/containerd" "github.com/moby/buildkit/util/leaseutil" @@ -26,16 +27,16 @@ import ( ) // NewWorkerOpt creates a WorkerOpt. -func NewWorkerOpt(root string, address, snapshotterName, ns string, labels map[string]string, opts ...containerd.ClientOpt) (base.WorkerOpt, error) { +func NewWorkerOpt(root string, address, snapshotterName, ns string, labels map[string]string, dns *oci.DNSConfig, opts ...containerd.ClientOpt) (base.WorkerOpt, error) { opts = append(opts, containerd.WithDefaultNamespace(ns)) client, err := containerd.New(address, opts...) if err != nil { return base.WorkerOpt{}, errors.Wrapf(err, "failed to connect client to %q . make sure containerd is running", address) } - return newContainerd(root, client, snapshotterName, ns, labels) + return newContainerd(root, client, snapshotterName, ns, labels, dns) } -func newContainerd(root string, client *containerd.Client, snapshotterName, ns string, labels map[string]string) (base.WorkerOpt, error) { +func newContainerd(root string, client *containerd.Client, snapshotterName, ns string, labels map[string]string, dns *oci.DNSConfig) (base.WorkerOpt, error) { if strings.Contains(snapshotterName, "/") { return base.WorkerOpt{}, errors.Errorf("bad snapshotter name: %q", snapshotterName) } @@ -106,7 +107,7 @@ func newContainerd(root string, client *containerd.Client, snapshotterName, ns s ID: id, Labels: xlabels, MetadataStore: md, - Executor: containerdexecutor.New(client, root, "", network.Default()), + Executor: containerdexecutor.New(client, root, "", network.Default(), dns), Snapshotter: containerdsnapshot.NewSnapshotter(snapshotterName, client.SnapshotService(snapshotterName), cs, md, ns, gc, nil), ContentStore: cs, Applier: winlayers.NewFileSystemApplierWithWindows(cs, df), diff --git a/worker/runc/runc.go b/worker/runc/runc.go index 7654ab27c5d1..34ce4f0105a9 100644 --- a/worker/runc/runc.go +++ b/worker/runc/runc.go @@ -34,7 +34,7 @@ type SnapshotterFactory struct { } // NewWorkerOpt creates a WorkerOpt. -func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, processMode oci.ProcessMode, labels map[string]string, idmap *idtools.IdentityMapping) (base.WorkerOpt, error) { +func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, processMode oci.ProcessMode, labels map[string]string, idmap *idtools.IdentityMapping, dns *oci.DNSConfig) (base.WorkerOpt, error) { var opt base.WorkerOpt name := "runc-" + snFactory.Name root = filepath.Join(root, name) @@ -52,6 +52,7 @@ func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, proc Rootless: rootless, ProcessMode: processMode, IdentityMapping: idmap, + DNS: dns, }, network.Default()) if err != nil { return opt, err diff --git a/worker/runc/runc_test.go b/worker/runc/runc_test.go index 5c2082ed8f03..4060f2441a3f 100644 --- a/worker/runc/runc_test.go +++ b/worker/runc/runc_test.go @@ -39,7 +39,7 @@ func newWorkerOpt(t *testing.T, processMode oci.ProcessMode) (base.WorkerOpt, fu }, } rootless := false - workerOpt, err := NewWorkerOpt(tmpdir, snFactory, rootless, processMode, nil, nil) + workerOpt, err := NewWorkerOpt(tmpdir, snFactory, rootless, processMode, nil, nil, nil) require.NoError(t, err) return workerOpt, cleanup