github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/builder/builder-next/executor_unix.go (about)

     1  //go:build !windows
     2  // +build !windows
     3  
     4  package buildkit
     5  
     6  import (
     7  	"os"
     8  	"path/filepath"
     9  	"strconv"
    10  	"sync"
    11  
    12  	"github.com/docker/docker/daemon/config"
    13  	"github.com/docker/docker/libnetwork"
    14  	"github.com/docker/docker/pkg/idtools"
    15  	"github.com/docker/docker/pkg/stringid"
    16  	"github.com/moby/buildkit/executor"
    17  	"github.com/moby/buildkit/executor/oci"
    18  	"github.com/moby/buildkit/executor/runcexecutor"
    19  	"github.com/moby/buildkit/identity"
    20  	"github.com/moby/buildkit/solver/pb"
    21  	"github.com/moby/buildkit/util/network"
    22  	specs "github.com/opencontainers/runtime-spec/specs-go"
    23  	"github.com/sirupsen/logrus"
    24  )
    25  
    26  const networkName = "bridge"
    27  
    28  func newExecutor(root, cgroupParent string, net libnetwork.NetworkController, dnsConfig *oci.DNSConfig, rootless bool, idmap idtools.IdentityMapping, apparmorProfile string) (executor.Executor, error) {
    29  	netRoot := filepath.Join(root, "net")
    30  	networkProviders := map[pb.NetMode]network.Provider{
    31  		pb.NetMode_UNSET: &bridgeProvider{NetworkController: net, Root: netRoot},
    32  		pb.NetMode_HOST:  network.NewHostProvider(),
    33  		pb.NetMode_NONE:  network.NewNoneProvider(),
    34  	}
    35  
    36  	// make sure net state directory is cleared from previous state
    37  	fis, err := os.ReadDir(netRoot)
    38  	if err == nil {
    39  		for _, fi := range fis {
    40  			fp := filepath.Join(netRoot, fi.Name())
    41  			if err := os.RemoveAll(fp); err != nil {
    42  				logrus.WithError(err).Errorf("failed to delete old network state: %v", fp)
    43  			}
    44  		}
    45  	}
    46  
    47  	// Returning a non-nil but empty *IdentityMapping breaks BuildKit:
    48  	// https://github.com/moby/moby/pull/39444
    49  	pidmap := &idmap
    50  	if idmap.Empty() {
    51  		pidmap = nil
    52  	}
    53  
    54  	return runcexecutor.New(runcexecutor.Opt{
    55  		Root:                filepath.Join(root, "executor"),
    56  		CommandCandidates:   []string{"runc"},
    57  		DefaultCgroupParent: cgroupParent,
    58  		Rootless:            rootless,
    59  		NoPivot:             os.Getenv("DOCKER_RAMDISK") != "",
    60  		IdentityMapping:     pidmap,
    61  		DNS:                 dnsConfig,
    62  		ApparmorProfile:     apparmorProfile,
    63  	}, networkProviders)
    64  }
    65  
    66  type bridgeProvider struct {
    67  	libnetwork.NetworkController
    68  	Root string
    69  }
    70  
    71  func (p *bridgeProvider) New() (network.Namespace, error) {
    72  	n, err := p.NetworkByName(networkName)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	iface := &lnInterface{ready: make(chan struct{}), provider: p}
    78  	iface.Once.Do(func() {
    79  		go iface.init(p.NetworkController, n)
    80  	})
    81  
    82  	return iface, nil
    83  }
    84  
    85  type lnInterface struct {
    86  	ep  libnetwork.Endpoint
    87  	sbx libnetwork.Sandbox
    88  	sync.Once
    89  	err      error
    90  	ready    chan struct{}
    91  	provider *bridgeProvider
    92  }
    93  
    94  func (iface *lnInterface) init(c libnetwork.NetworkController, n libnetwork.Network) {
    95  	defer close(iface.ready)
    96  	id := identity.NewID()
    97  
    98  	ep, err := n.CreateEndpoint(id, libnetwork.CreateOptionDisableResolution())
    99  	if err != nil {
   100  		iface.err = err
   101  		return
   102  	}
   103  
   104  	sbx, err := c.NewSandbox(id, libnetwork.OptionUseExternalKey(), libnetwork.OptionHostsPath(filepath.Join(iface.provider.Root, id, "hosts")),
   105  		libnetwork.OptionResolvConfPath(filepath.Join(iface.provider.Root, id, "resolv.conf")))
   106  	if err != nil {
   107  		iface.err = err
   108  		return
   109  	}
   110  
   111  	if err := ep.Join(sbx); err != nil {
   112  		iface.err = err
   113  		return
   114  	}
   115  
   116  	iface.sbx = sbx
   117  	iface.ep = ep
   118  }
   119  
   120  func (iface *lnInterface) Set(s *specs.Spec) error {
   121  	<-iface.ready
   122  	if iface.err != nil {
   123  		logrus.WithError(iface.err).Error("failed to set networking spec")
   124  		return iface.err
   125  	}
   126  	shortNetCtlrID := stringid.TruncateID(iface.provider.NetworkController.ID())
   127  	// attach netns to bridge within the container namespace, using reexec in a prestart hook
   128  	s.Hooks = &specs.Hooks{
   129  		Prestart: []specs.Hook{{
   130  			Path: filepath.Join("/proc", strconv.Itoa(os.Getpid()), "exe"),
   131  			Args: []string{"libnetwork-setkey", "-exec-root=" + iface.provider.Config().ExecRoot, iface.sbx.ContainerID(), shortNetCtlrID},
   132  		}},
   133  	}
   134  	return nil
   135  }
   136  
   137  func (iface *lnInterface) Close() error {
   138  	<-iface.ready
   139  	if iface.sbx != nil {
   140  		go func() {
   141  			if err := iface.sbx.Delete(); err != nil {
   142  				logrus.WithError(err).Errorf("failed to delete builder network sandbox")
   143  			}
   144  			if err := os.RemoveAll(filepath.Join(iface.provider.Root, iface.sbx.ContainerID())); err != nil {
   145  				logrus.WithError(err).Errorf("failed to delete builder sandbox directory")
   146  			}
   147  		}()
   148  	}
   149  	return iface.err
   150  }
   151  
   152  func getDNSConfig(cfg config.DNSConfig) *oci.DNSConfig {
   153  	if cfg.DNS != nil || cfg.DNSSearch != nil || cfg.DNSOptions != nil {
   154  		return &oci.DNSConfig{
   155  			Nameservers:   cfg.DNS,
   156  			SearchDomains: cfg.DNSSearch,
   157  			Options:       cfg.DNSOptions,
   158  		}
   159  	}
   160  	return nil
   161  }