You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			242 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Go
		
	
			
		
		
	
	
			242 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Go
		
	
package integration
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"context"
 | 
						|
	"fmt"
 | 
						|
	"log"
 | 
						|
	"os"
 | 
						|
	"os/exec"
 | 
						|
	"path/filepath"
 | 
						|
	"runtime"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/moby/buildkit/util/bklog"
 | 
						|
	"github.com/pkg/errors"
 | 
						|
)
 | 
						|
 | 
						|
func InitContainerdWorker() {
 | 
						|
	Register(&Containerd{
 | 
						|
		ID:         "containerd",
 | 
						|
		Containerd: "containerd",
 | 
						|
	})
 | 
						|
	// defined in Dockerfile
 | 
						|
	// e.g. `containerd-1.1=/opt/containerd-1.1/bin,containerd-42.0=/opt/containerd-42.0/bin`
 | 
						|
	if s := os.Getenv("BUILDKIT_INTEGRATION_CONTAINERD_EXTRA"); s != "" {
 | 
						|
		entries := strings.Split(s, ",")
 | 
						|
		for _, entry := range entries {
 | 
						|
			pair := strings.Split(strings.TrimSpace(entry), "=")
 | 
						|
			if len(pair) != 2 {
 | 
						|
				panic(errors.Errorf("unexpected BUILDKIT_INTEGRATION_CONTAINERD_EXTRA: %q", s))
 | 
						|
			}
 | 
						|
			name, bin := pair[0], pair[1]
 | 
						|
			Register(&Containerd{
 | 
						|
				ID:         name,
 | 
						|
				Containerd: filepath.Join(bin, "containerd"),
 | 
						|
				// override PATH to make sure that the expected version of the shim binary is used
 | 
						|
				ExtraEnv: []string{fmt.Sprintf("PATH=%s:%s", bin, os.Getenv("PATH"))},
 | 
						|
			})
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// the rootless uid is defined in Dockerfile
 | 
						|
	if s := os.Getenv("BUILDKIT_INTEGRATION_ROOTLESS_IDPAIR"); s != "" {
 | 
						|
		var uid, gid int
 | 
						|
		if _, err := fmt.Sscanf(s, "%d:%d", &uid, &gid); err != nil {
 | 
						|
			bklog.L.Fatalf("unexpected BUILDKIT_INTEGRATION_ROOTLESS_IDPAIR: %q", s)
 | 
						|
		}
 | 
						|
		if rootlessSupported(uid) {
 | 
						|
			Register(&Containerd{
 | 
						|
				ID:          "containerd-rootless",
 | 
						|
				Containerd:  "containerd",
 | 
						|
				UID:         uid,
 | 
						|
				GID:         gid,
 | 
						|
				Snapshotter: "native", // TODO: test with fuse-overlayfs as well, or automatically determine snapshotter
 | 
						|
			})
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if s := os.Getenv("BUILDKIT_INTEGRATION_SNAPSHOTTER"); s != "" {
 | 
						|
		Register(&Containerd{
 | 
						|
			ID:          fmt.Sprintf("containerd-snapshotter-%s", s),
 | 
						|
			Containerd:  "containerd",
 | 
						|
			Snapshotter: s,
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type Containerd struct {
 | 
						|
	ID          string
 | 
						|
	Containerd  string
 | 
						|
	Snapshotter string
 | 
						|
	UID         int
 | 
						|
	GID         int
 | 
						|
	ExtraEnv    []string // e.g. "PATH=/opt/containerd-1.4/bin:/usr/bin:..."
 | 
						|
}
 | 
						|
 | 
						|
func (c *Containerd) Name() string {
 | 
						|
	return c.ID
 | 
						|
}
 | 
						|
 | 
						|
func (c *Containerd) Rootless() bool {
 | 
						|
	return c.UID != 0
 | 
						|
}
 | 
						|
 | 
						|
func (c *Containerd) New(ctx context.Context, cfg *BackendConfig) (b Backend, cl func() error, err error) {
 | 
						|
	if err := lookupBinary(c.Containerd); err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
	if err := lookupBinary("buildkitd"); err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
	if err := requireRoot(); err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	deferF := &multiCloser{}
 | 
						|
	cl = deferF.F()
 | 
						|
 | 
						|
	defer func() {
 | 
						|
		if err != nil {
 | 
						|
			deferF.F()()
 | 
						|
			cl = nil
 | 
						|
		}
 | 
						|
	}()
 | 
						|
 | 
						|
	rootless := false
 | 
						|
	if c.UID != 0 {
 | 
						|
		if c.GID == 0 {
 | 
						|
			return nil, nil, errors.Errorf("unsupported id pair: uid=%d, gid=%d", c.UID, c.GID)
 | 
						|
		}
 | 
						|
		rootless = true
 | 
						|
	}
 | 
						|
 | 
						|
	tmpdir, err := os.MkdirTemp("", "bktest_containerd")
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
	if rootless {
 | 
						|
		if err := os.Chown(tmpdir, c.UID, c.GID); err != nil {
 | 
						|
			return nil, nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	deferF.append(func() error { return os.RemoveAll(tmpdir) })
 | 
						|
 | 
						|
	address := filepath.Join(tmpdir, "containerd.sock")
 | 
						|
	config := fmt.Sprintf(`root = %q
 | 
						|
state = %q
 | 
						|
# CRI plugins listens on 10010/tcp for stream server.
 | 
						|
# We disable CRI plugin so that multiple instance can run simultaneously.
 | 
						|
disabled_plugins = ["cri"]
 | 
						|
 | 
						|
[grpc]
 | 
						|
  address = %q
 | 
						|
 | 
						|
[debug]
 | 
						|
  level = "debug"
 | 
						|
  address = %q
 | 
						|
`, filepath.Join(tmpdir, "root"), filepath.Join(tmpdir, "state"), address, filepath.Join(tmpdir, "debug.sock"))
 | 
						|
 | 
						|
	var snBuildkitdArgs []string
 | 
						|
	if c.Snapshotter != "" {
 | 
						|
		snBuildkitdArgs = append(snBuildkitdArgs,
 | 
						|
			fmt.Sprintf("--containerd-worker-snapshotter=%s", c.Snapshotter))
 | 
						|
		if c.Snapshotter == "stargz" {
 | 
						|
			snPath, snCl, err := runStargzSnapshotter(cfg)
 | 
						|
			if err != nil {
 | 
						|
				return nil, nil, err
 | 
						|
			}
 | 
						|
			deferF.append(snCl)
 | 
						|
			config = fmt.Sprintf(`%s
 | 
						|
 | 
						|
[proxy_plugins]
 | 
						|
  [proxy_plugins.stargz]
 | 
						|
    type = "snapshot"
 | 
						|
    address = %q
 | 
						|
`, config, snPath)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	configFile := filepath.Join(tmpdir, "config.toml")
 | 
						|
	if err := os.WriteFile(configFile, []byte(config), 0644); err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	containerdArgs := []string{c.Containerd, "--config", configFile}
 | 
						|
	rootlessKitState := filepath.Join(tmpdir, "rootlesskit-containerd")
 | 
						|
	if rootless {
 | 
						|
		containerdArgs = append(append([]string{"sudo", "-u", fmt.Sprintf("#%d", c.UID), "-i",
 | 
						|
			fmt.Sprintf("CONTAINERD_ROOTLESS_ROOTLESSKIT_STATE_DIR=%s", rootlessKitState),
 | 
						|
			// Integration test requires the access to localhost of the host network namespace.
 | 
						|
			// TODO: remove these configurations
 | 
						|
			"CONTAINERD_ROOTLESS_ROOTLESSKIT_NET=host",
 | 
						|
			"CONTAINERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=none",
 | 
						|
			"CONTAINERD_ROOTLESS_ROOTLESSKIT_FLAGS=--mtu=0",
 | 
						|
		}, c.ExtraEnv...), "containerd-rootless.sh", "-c", configFile)
 | 
						|
	}
 | 
						|
 | 
						|
	cmd := exec.Command(containerdArgs[0], containerdArgs[1:]...) //nolint:gosec // test utility
 | 
						|
	cmd.Env = append(os.Environ(), c.ExtraEnv...)
 | 
						|
 | 
						|
	ctdStop, err := startCmd(cmd, cfg.Logs)
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
	if err := waitUnix(address, 10*time.Second, cmd); err != nil {
 | 
						|
		ctdStop()
 | 
						|
		return nil, nil, errors.Wrapf(err, "containerd did not start up: %s", formatLogs(cfg.Logs))
 | 
						|
	}
 | 
						|
	deferF.append(ctdStop)
 | 
						|
 | 
						|
	buildkitdArgs := append([]string{"buildkitd",
 | 
						|
		"--oci-worker=false",
 | 
						|
		"--containerd-worker-gc=false",
 | 
						|
		"--containerd-worker=true",
 | 
						|
		"--containerd-worker-addr", address,
 | 
						|
		"--containerd-worker-labels=org.mobyproject.buildkit.worker.sandbox=true", // Include use of --containerd-worker-labels to trigger https://github.com/moby/buildkit/pull/603
 | 
						|
	}, snBuildkitdArgs...)
 | 
						|
 | 
						|
	if runtime.GOOS != "windows" && c.Snapshotter != "native" {
 | 
						|
		c.ExtraEnv = append(c.ExtraEnv, "BUILDKIT_DEBUG_FORCE_OVERLAY_DIFF=true")
 | 
						|
	}
 | 
						|
	if rootless {
 | 
						|
		pidStr, err := os.ReadFile(filepath.Join(rootlessKitState, "child_pid"))
 | 
						|
		if err != nil {
 | 
						|
			return nil, nil, err
 | 
						|
		}
 | 
						|
		pid, err := strconv.ParseInt(string(pidStr), 10, 64)
 | 
						|
		if err != nil {
 | 
						|
			return nil, nil, err
 | 
						|
		}
 | 
						|
		buildkitdArgs = append([]string{"sudo", "-u", fmt.Sprintf("#%d", c.UID), "-i", "--", "exec",
 | 
						|
			"nsenter", "-U", "--preserve-credentials", "-m", "-t", fmt.Sprintf("%d", pid)},
 | 
						|
			append(buildkitdArgs, "--containerd-worker-snapshotter=native")...)
 | 
						|
	}
 | 
						|
	buildkitdSock, stop, err := runBuildkitd(ctx, cfg, buildkitdArgs, cfg.Logs, c.UID, c.GID, c.ExtraEnv)
 | 
						|
	if err != nil {
 | 
						|
		printLogs(cfg.Logs, log.Println)
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
	deferF.append(stop)
 | 
						|
 | 
						|
	return backend{
 | 
						|
		address:           buildkitdSock,
 | 
						|
		containerdAddress: address,
 | 
						|
		rootless:          rootless,
 | 
						|
		snapshotter:       c.Snapshotter,
 | 
						|
	}, cl, nil
 | 
						|
}
 | 
						|
 | 
						|
func formatLogs(m map[string]*bytes.Buffer) string {
 | 
						|
	var ss []string
 | 
						|
	for k, b := range m {
 | 
						|
		if b != nil {
 | 
						|
			ss = append(ss, fmt.Sprintf("%q:%q", k, b.String()))
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return strings.Join(ss, ",")
 | 
						|
}
 |