gopkg.in/docker/docker.v20@v20.10.27/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/pkg/idtools"
    14  	"github.com/docker/docker/pkg/stringid"
    15  	"github.com/docker/libnetwork"
    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  	return runcexecutor.New(runcexecutor.Opt{
    48  		Root:                filepath.Join(root, "executor"),
    49  		CommandCandidates:   []string{"runc"},
    50  		DefaultCgroupParent: cgroupParent,
    51  		Rootless:            rootless,
    52  		NoPivot:             os.Getenv("DOCKER_RAMDISK") != "",
    53  		IdentityMapping:     idmap,
    54  		DNS:                 dnsConfig,
    55  		ApparmorProfile:     apparmorProfile,
    56  	}, networkProviders)
    57  }
    58  
    59  type bridgeProvider struct {
    60  	libnetwork.NetworkController
    61  	Root string
    62  }
    63  
    64  func (p *bridgeProvider) New() (network.Namespace, error) {
    65  	n, err := p.NetworkByName(networkName)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	iface := &lnInterface{ready: make(chan struct{}), provider: p}
    71  	iface.Once.Do(func() {
    72  		go iface.init(p.NetworkController, n)
    73  	})
    74  
    75  	return iface, nil
    76  }
    77  
    78  type lnInterface struct {
    79  	ep  libnetwork.Endpoint
    80  	sbx libnetwork.Sandbox
    81  	sync.Once
    82  	err      error
    83  	ready    chan struct{}
    84  	provider *bridgeProvider
    85  }
    86  
    87  func (iface *lnInterface) init(c libnetwork.NetworkController, n libnetwork.Network) {
    88  	defer close(iface.ready)
    89  	id := identity.NewID()
    90  
    91  	ep, err := n.CreateEndpoint(id, libnetwork.CreateOptionDisableResolution())
    92  	if err != nil {
    93  		iface.err = err
    94  		return
    95  	}
    96  
    97  	sbx, err := c.NewSandbox(id, libnetwork.OptionUseExternalKey(), libnetwork.OptionHostsPath(filepath.Join(iface.provider.Root, id, "hosts")),
    98  		libnetwork.OptionResolvConfPath(filepath.Join(iface.provider.Root, id, "resolv.conf")))
    99  	if err != nil {
   100  		iface.err = err
   101  		return
   102  	}
   103  
   104  	if err := ep.Join(sbx); err != nil {
   105  		iface.err = err
   106  		return
   107  	}
   108  
   109  	iface.sbx = sbx
   110  	iface.ep = ep
   111  }
   112  
   113  func (iface *lnInterface) Set(s *specs.Spec) error {
   114  	<-iface.ready
   115  	if iface.err != nil {
   116  		logrus.WithError(iface.err).Error("failed to set networking spec")
   117  		return iface.err
   118  	}
   119  	shortNetCtlrID := stringid.TruncateID(iface.provider.NetworkController.ID())
   120  	// attach netns to bridge within the container namespace, using reexec in a prestart hook
   121  	s.Hooks = &specs.Hooks{
   122  		Prestart: []specs.Hook{{
   123  			Path: filepath.Join("/proc", strconv.Itoa(os.Getpid()), "exe"),
   124  			Args: []string{"libnetwork-setkey", "-exec-root=" + iface.provider.Config().Daemon.ExecRoot, iface.sbx.ContainerID(), shortNetCtlrID},
   125  		}},
   126  	}
   127  	return nil
   128  }
   129  
   130  func (iface *lnInterface) Close() error {
   131  	<-iface.ready
   132  	if iface.sbx != nil {
   133  		go func() {
   134  			if err := iface.sbx.Delete(); err != nil {
   135  				logrus.WithError(err).Errorf("failed to delete builder network sandbox")
   136  			}
   137  			if err := os.RemoveAll(filepath.Join(iface.provider.Root, iface.sbx.ContainerID())); err != nil {
   138  				logrus.WithError(err).Errorf("failed to delete builder sandbox directory")
   139  			}
   140  		}()
   141  	}
   142  	return iface.err
   143  }
   144  
   145  func getDNSConfig(cfg config.DNSConfig) *oci.DNSConfig {
   146  	if cfg.DNS != nil || cfg.DNSSearch != nil || cfg.DNSOptions != nil {
   147  		return &oci.DNSConfig{
   148  			Nameservers:   cfg.DNS,
   149  			SearchDomains: cfg.DNSSearch,
   150  			Options:       cfg.DNSOptions,
   151  		}
   152  	}
   153  	return nil
   154  }