github.com/rish1988/moby@v25.0.2+incompatible/builder/builder-next/executor_linux.go (about)

     1  package buildkit
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"os"
     7  	"path/filepath"
     8  	"strconv"
     9  	"sync"
    10  
    11  	"github.com/containerd/log"
    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/resources"
    19  	"github.com/moby/buildkit/executor/runcexecutor"
    20  	"github.com/moby/buildkit/identity"
    21  	"github.com/moby/buildkit/solver/pb"
    22  	"github.com/moby/buildkit/util/network"
    23  	specs "github.com/opencontainers/runtime-spec/specs-go"
    24  )
    25  
    26  const networkName = "bridge"
    27  
    28  func newExecutor(root, cgroupParent string, net *libnetwork.Controller, 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{Controller: 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  				log.G(context.TODO()).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  	rm, err := resources.NewMonitor()
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	return runcexecutor.New(runcexecutor.Opt{
    60  		Root:                filepath.Join(root, "executor"),
    61  		CommandCandidates:   []string{"runc"},
    62  		DefaultCgroupParent: cgroupParent,
    63  		Rootless:            rootless,
    64  		NoPivot:             os.Getenv("DOCKER_RAMDISK") != "",
    65  		IdentityMapping:     pidmap,
    66  		DNS:                 dnsConfig,
    67  		ApparmorProfile:     apparmorProfile,
    68  		ResourceMonitor:     rm,
    69  	}, networkProviders)
    70  }
    71  
    72  type bridgeProvider struct {
    73  	*libnetwork.Controller
    74  	Root string
    75  }
    76  
    77  func (p *bridgeProvider) New(ctx context.Context, hostname string) (network.Namespace, error) {
    78  	n, err := p.NetworkByName(networkName)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  
    83  	iface := &lnInterface{ready: make(chan struct{}), provider: p}
    84  	iface.Once.Do(func() {
    85  		go iface.init(p.Controller, n)
    86  	})
    87  
    88  	return iface, nil
    89  }
    90  
    91  func (p *bridgeProvider) Close() error {
    92  	return nil
    93  }
    94  
    95  type lnInterface struct {
    96  	ep  *libnetwork.Endpoint
    97  	sbx *libnetwork.Sandbox
    98  	sync.Once
    99  	err      error
   100  	ready    chan struct{}
   101  	provider *bridgeProvider
   102  }
   103  
   104  func (iface *lnInterface) init(c *libnetwork.Controller, n *libnetwork.Network) {
   105  	defer close(iface.ready)
   106  	id := identity.NewID()
   107  
   108  	ep, err := n.CreateEndpoint(id, libnetwork.CreateOptionDisableResolution())
   109  	if err != nil {
   110  		iface.err = err
   111  		return
   112  	}
   113  
   114  	sbx, err := c.NewSandbox(id, libnetwork.OptionUseExternalKey(), libnetwork.OptionHostsPath(filepath.Join(iface.provider.Root, id, "hosts")),
   115  		libnetwork.OptionResolvConfPath(filepath.Join(iface.provider.Root, id, "resolv.conf")))
   116  	if err != nil {
   117  		iface.err = err
   118  		return
   119  	}
   120  
   121  	if err := ep.Join(sbx); err != nil {
   122  		iface.err = err
   123  		return
   124  	}
   125  
   126  	iface.sbx = sbx
   127  	iface.ep = ep
   128  }
   129  
   130  // TODO(neersighted): Unstub Sample(), and collect data from the libnetwork Endpoint.
   131  func (iface *lnInterface) Sample() (*network.Sample, error) {
   132  	return &network.Sample{}, nil
   133  }
   134  
   135  func (iface *lnInterface) Set(s *specs.Spec) error {
   136  	<-iface.ready
   137  	if iface.err != nil {
   138  		log.G(context.TODO()).WithError(iface.err).Error("failed to set networking spec")
   139  		return iface.err
   140  	}
   141  	shortNetCtlrID := stringid.TruncateID(iface.provider.Controller.ID())
   142  	// attach netns to bridge within the container namespace, using reexec in a prestart hook
   143  	s.Hooks = &specs.Hooks{
   144  		Prestart: []specs.Hook{{
   145  			Path: filepath.Join("/proc", strconv.Itoa(os.Getpid()), "exe"),
   146  			Args: []string{"libnetwork-setkey", "-exec-root=" + iface.provider.Config().ExecRoot, iface.sbx.ContainerID(), shortNetCtlrID},
   147  		}},
   148  	}
   149  	return nil
   150  }
   151  
   152  func (iface *lnInterface) Close() error {
   153  	<-iface.ready
   154  	if iface.sbx != nil {
   155  		go func() {
   156  			if err := iface.sbx.Delete(); err != nil {
   157  				log.G(context.TODO()).WithError(err).Errorf("failed to delete builder network sandbox")
   158  			}
   159  			if err := os.RemoveAll(filepath.Join(iface.provider.Root, iface.sbx.ContainerID())); err != nil {
   160  				log.G(context.TODO()).WithError(err).Errorf("failed to delete builder sandbox directory")
   161  			}
   162  		}()
   163  	}
   164  	return iface.err
   165  }
   166  
   167  func getDNSConfig(cfg config.DNSConfig) *oci.DNSConfig {
   168  	if cfg.DNS != nil || cfg.DNSSearch != nil || cfg.DNSOptions != nil {
   169  		return &oci.DNSConfig{
   170  			Nameservers:   ipAddresses(cfg.DNS),
   171  			SearchDomains: cfg.DNSSearch,
   172  			Options:       cfg.DNSOptions,
   173  		}
   174  	}
   175  	return nil
   176  }
   177  
   178  func ipAddresses(ips []net.IP) []string {
   179  	var addrs []string
   180  	for _, ip := range ips {
   181  		addrs = append(addrs, ip.String())
   182  	}
   183  	return addrs
   184  }