Browse Source

Merge 44d98e7a6472d993cf7696142721f677c944d7f5 into ee8b788538ea2c6d46d65f17be156de65bc21bb9

Olli Janatuinen 1 year ago
parent
commit
ba6b2cd9df

+ 13 - 4
.github/workflows/.windows.yml

@@ -337,7 +337,7 @@ jobs:
           }
           }
       -
       -
         name: Starting containerd
         name: Starting containerd
-        if: matrix.runtime == 'containerd'
+        if: matrix.runtime == 'containerd' && matrix.os == 'windows-2019'
         run: |
         run: |
           Write-Host "Generating config"
           Write-Host "Generating config"
           & "${{ env.BIN_OUT }}\containerd.exe" config default | Out-File "$env:TEMP\ctn.toml" -Encoding ascii
           & "${{ env.BIN_OUT }}\containerd.exe" config default | Out-File "$env:TEMP\ctn.toml" -Encoding ascii
@@ -360,10 +360,14 @@ jobs:
         name: Starting test daemon
         name: Starting test daemon
         run: |
         run: |
           Write-Host "Creating service"
           Write-Host "Creating service"
-          If ("${{ matrix.runtime }}" -eq "containerd") {
+          If ("${{ matrix.runtime }}" -eq "containerd" -and "${{ matrix.os }}" -eq "windows-2019") {
             $runtimeArg="--containerd=\\.\pipe\containerd-containerd"
             $runtimeArg="--containerd=\\.\pipe\containerd-containerd"
             echo "DOCKER_WINDOWS_CONTAINERD_RUNTIME=1" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
             echo "DOCKER_WINDOWS_CONTAINERD_RUNTIME=1" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
           }
           }
+          If ("${{ matrix.runtime }}" -eq "containerd" -and "${{ matrix.os }}" -eq "windows-2022") {
+            $runtimeArg="--default-runtime=io.containerd.runhcs.v1"
+            echo "DOCKER_WINDOWS_CONTAINERD_RUNTIME=1" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
+          }
           New-Item -ItemType Directory "$env:TEMP\moby-root" -ErrorAction SilentlyContinue | Out-Null
           New-Item -ItemType Directory "$env:TEMP\moby-root" -ErrorAction SilentlyContinue | Out-Null
           New-Item -ItemType Directory "$env:TEMP\moby-exec" -ErrorAction SilentlyContinue | Out-Null
           New-Item -ItemType Directory "$env:TEMP\moby-exec" -ErrorAction SilentlyContinue | Out-Null
           Start-Process -Wait -NoNewWindow "${{ env.BIN_OUT }}\dockerd" `
           Start-Process -Wait -NoNewWindow "${{ env.BIN_OUT }}\dockerd" `
@@ -401,6 +405,11 @@ jobs:
             Start-Sleep -Seconds 1
             Start-Sleep -Seconds 1
           }
           }
           Write-Host "Test daemon started and replied!"
           Write-Host "Test daemon started and replied!"
+          If ("${{ matrix.runtime }}" -eq "containerd") {
+            If (-not (Get-Process -Name containerd -ErrorAction:SilentlyContinue)) {
+              Throw "containerd process is not running"
+            }
+          }
         env:
         env:
           DOCKER_HOST: npipe:////./pipe/docker_engine
           DOCKER_HOST: npipe:////./pipe/docker_engine
       -
       -
@@ -466,14 +475,14 @@ jobs:
           DOCKER_HOST: npipe:////./pipe/docker_engine
           DOCKER_HOST: npipe:////./pipe/docker_engine
       -
       -
         name: Stop containerd
         name: Stop containerd
-        if: always() && matrix.runtime == 'containerd'
+        if: always() && matrix.runtime == 'containerd' && matrix.os == 'windows-2019'
         run: |
         run: |
           $ErrorActionPreference = "SilentlyContinue"
           $ErrorActionPreference = "SilentlyContinue"
           Stop-Service -Force -Name containerd
           Stop-Service -Force -Name containerd
           $ErrorActionPreference = "Stop"
           $ErrorActionPreference = "Stop"
       -
       -
         name: Containerd logs
         name: Containerd logs
-        if: always() && matrix.runtime == 'containerd'
+        if: always() && matrix.runtime == 'containerd' && matrix.os == 'windows-2019'
         run: |
         run: |
           Copy-Item "$env:TEMP\ctn.log" -Destination ".\bundles\containerd.log"
           Copy-Item "$env:TEMP\ctn.log" -Destination ".\bundles\containerd.log"
           Get-Content "$env:TEMP\ctn.log" | Out-Host
           Get-Content "$env:TEMP\ctn.log" | Out-Host

+ 41 - 3
cmd/dockerd/daemon_windows.go

@@ -4,11 +4,15 @@ import (
 	"context"
 	"context"
 	"fmt"
 	"fmt"
 	"os"
 	"os"
+	"path/filepath"
 	"time"
 	"time"
 
 
 	"github.com/containerd/log"
 	"github.com/containerd/log"
 	"github.com/docker/docker/daemon/config"
 	"github.com/docker/docker/daemon/config"
+	"github.com/docker/docker/libcontainerd/supervisor"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/pkg/system"
+	"github.com/pkg/errors"
+	"github.com/sirupsen/logrus"
 	"golang.org/x/sys/windows"
 	"golang.org/x/sys/windows"
 )
 )
 
 
@@ -57,6 +61,17 @@ func notifyShutdown(err error) {
 	}
 	}
 }
 }
 
 
+func (cli *DaemonCli) getPlatformContainerdDaemonOpts() ([]supervisor.DaemonOpt, error) {
+	opts := []supervisor.DaemonOpt{
+		// On Windows, it first checks if a containerd binary is found in the same
+		// directory as the dockerd binary. If found, this binary takes precedence
+		// over containerd binaries installed in $PATH.
+		supervisor.WithDetectLocalBinary(),
+	}
+
+	return opts, nil
+}
+
 // setupConfigReloadTrap configures a Win32 event to reload the configuration.
 // setupConfigReloadTrap configures a Win32 event to reload the configuration.
 func (cli *DaemonCli) setupConfigReloadTrap() {
 func (cli *DaemonCli) setupConfigReloadTrap() {
 	go func() {
 	go func() {
@@ -89,9 +104,32 @@ func newCgroupParent(config *config.Config) string {
 	return ""
 	return ""
 }
 }
 
 
-func (cli *DaemonCli) initContainerd(_ context.Context) (func(time.Duration) error, error) {
-	system.InitContainerdRuntime(cli.ContainerdAddr)
-	return nil, nil
+func (cli *DaemonCli) initContainerd(ctx context.Context) (func(time.Duration) error, error) {
+	if cli.ContainerdAddr != "" {
+		// use system containerd at the given address.
+		system.InitContainerdRuntime(cli.ContainerdAddr)
+		return nil, nil
+	}
+
+	if cli.DefaultRuntime != config.WindowsV2RuntimeName {
+		return nil, nil
+	}
+
+	logrus.Info("containerd not running, starting managed containerd")
+	opts, err := cli.getContainerdDaemonOpts()
+	if err != nil {
+		return nil, errors.Wrap(err, "failed to generate containerd options")
+	}
+
+	r, err := supervisor.Start(ctx, filepath.Join(cli.Root, "containerd"), filepath.Join(cli.ExecRoot, "containerd"), opts...)
+	if err != nil {
+		return nil, errors.Wrap(err, "failed to start containerd")
+	}
+	cli.ContainerdAddr = r.Address()
+	system.InitContainerdRuntime(r.Address())
+
+	// Try to wait for containerd to shutdown
+	return r.WaitTimeout, nil
 }
 }
 
 
 func validateCPURealtimeOptions(_ *config.Config) error {
 func validateCPURealtimeOptions(_ *config.Config) error {

+ 5 - 0
daemon/config/config_linux.go

@@ -38,6 +38,11 @@ const (
 	userlandProxyBinary = "docker-proxy"
 	userlandProxyBinary = "docker-proxy"
 )
 )
 
 
+var builtinRuntimes = map[string]bool{
+	StockRuntimeName:   true,
+	LinuxV2RuntimeName: true,
+}
+
 // BridgeConfig stores all the parameters for both the bridge driver and the default bridge network.
 // BridgeConfig stores all the parameters for both the bridge driver and the default bridge network.
 type BridgeConfig struct {
 type BridgeConfig struct {
 	DefaultBridgeConfig
 	DefaultBridgeConfig

+ 8 - 0
daemon/config/config_windows.go

@@ -13,8 +13,16 @@ const (
 	// default value. On Windows keep this empty so the value is auto-detected
 	// default value. On Windows keep this empty so the value is auto-detected
 	// based on other options.
 	// based on other options.
 	StockRuntimeName = ""
 	StockRuntimeName = ""
+
+	WindowsV1RuntimeName = "com.docker.hcsshim.v1"
+	WindowsV2RuntimeName = "io.containerd.runhcs.v1"
 )
 )
 
 
+var builtinRuntimes = map[string]bool{
+	WindowsV1RuntimeName: true,
+	WindowsV2RuntimeName: true,
+}
+
 // BridgeConfig is meant to store all the parameters for both the bridge driver and the default bridge network. On
 // BridgeConfig is meant to store all the parameters for both the bridge driver and the default bridge network. On
 // Windows: 1. "bridge" in this context reference the nat driver and the default nat network; 2. the nat driver has no
 // Windows: 1. "bridge" in this context reference the nat driver and the default nat network; 2. the nat driver has no
 // specific parameters, so this struct effectively just stores parameters for the default nat network.
 // specific parameters, so this struct effectively just stores parameters for the default nat network.

+ 4 - 7
daemon/daemon_windows.go

@@ -40,9 +40,6 @@ const (
 	windowsMaxCPUShares  = 10000
 	windowsMaxCPUShares  = 10000
 	windowsMinCPUPercent = 1
 	windowsMinCPUPercent = 1
 	windowsMaxCPUPercent = 100
 	windowsMaxCPUPercent = 100
-
-	windowsV1RuntimeName = "com.docker.hcsshim.v1"
-	windowsV2RuntimeName = "io.containerd.runhcs.v1"
 )
 )
 
 
 // Windows containers are much larger than Linux containers and each of them
 // Windows containers are much larger than Linux containers and each of them
@@ -567,14 +564,14 @@ func (daemon *Daemon) initLibcontainerd(ctx context.Context, cfg *config.Config)
 	rt := cfg.DefaultRuntime
 	rt := cfg.DefaultRuntime
 	if rt == "" {
 	if rt == "" {
 		if cfg.ContainerdAddr == "" {
 		if cfg.ContainerdAddr == "" {
-			rt = windowsV1RuntimeName
+			rt = config.WindowsV1RuntimeName
 		} else {
 		} else {
-			rt = windowsV2RuntimeName
+			rt = config.WindowsV2RuntimeName
 		}
 		}
 	}
 	}
 
 
 	switch rt {
 	switch rt {
-	case windowsV1RuntimeName:
+	case config.WindowsV1RuntimeName:
 		daemon.containerd, err = local.NewClient(
 		daemon.containerd, err = local.NewClient(
 			ctx,
 			ctx,
 			daemon.containerdClient,
 			daemon.containerdClient,
@@ -582,7 +579,7 @@ func (daemon *Daemon) initLibcontainerd(ctx context.Context, cfg *config.Config)
 			cfg.ContainerdNamespace,
 			cfg.ContainerdNamespace,
 			daemon,
 			daemon,
 		)
 		)
-	case windowsV2RuntimeName:
+	case config.WindowsV2RuntimeName:
 		if cfg.ContainerdAddr == "" {
 		if cfg.ContainerdAddr == "" {
 			return fmt.Errorf("cannot use the specified runtime %q without containerd", rt)
 			return fmt.Errorf("cannot use the specified runtime %q without containerd", rt)
 		}
 		}

+ 2 - 1
daemon/start_windows.go

@@ -3,13 +3,14 @@ package daemon // import "github.com/docker/docker/daemon"
 import (
 import (
 	"github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options"
 	"github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options"
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/container"
+	"github.com/docker/docker/daemon/config"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/pkg/system"
 )
 )
 
 
 func (daemon *Daemon) getLibcontainerdCreateOptions(*configStore, *container.Container) (string, interface{}, error) {
 func (daemon *Daemon) getLibcontainerdCreateOptions(*configStore, *container.Container) (string, interface{}, error) {
 	if system.ContainerdRuntimeSupported() {
 	if system.ContainerdRuntimeSupported() {
 		opts := &options.Options{}
 		opts := &options.Options{}
-		return "io.containerd.runhcs.v1", opts, nil
+		return config.WindowsV2RuntimeName, opts, nil
 	}
 	}
 	return "", nil, nil
 	return "", nil, nil
 }
 }

+ 10 - 5
libcontainerd/supervisor/remote_daemon.go

@@ -30,7 +30,6 @@ const (
 	shutdownTimeout         = 15 * time.Second
 	shutdownTimeout         = 15 * time.Second
 	startupTimeout          = 15 * time.Second
 	startupTimeout          = 15 * time.Second
 	configFile              = "containerd.toml"
 	configFile              = "containerd.toml"
-	binaryName              = "containerd"
 	pidFile                 = "containerd.pid"
 	pidFile                 = "containerd.pid"
 )
 )
 
 
@@ -41,9 +40,13 @@ type remote struct {
 	// file is saved.
 	// file is saved.
 	configFile string
 	configFile string
 
 
-	daemonPid int
-	pidFile   string
-	logger    *log.Entry
+	// daemonPath is the binary to execute, and can be either a basename (to use
+	// a binary installed in the system's $PATH), or the full path to the binary
+	// to use.
+	daemonPath string
+	daemonPid  int
+	pidFile    string
+	logger     *log.Entry
 
 
 	daemonWaitCh  chan struct{}
 	daemonWaitCh  chan struct{}
 	daemonStartCh chan error
 	daemonStartCh chan error
@@ -78,6 +81,7 @@ func Start(ctx context.Context, rootDir, stateDir string, opts ...DaemonOpt) (Da
 			State:   filepath.Join(stateDir, "daemon"),
 			State:   filepath.Join(stateDir, "daemon"),
 		},
 		},
 		configFile:    filepath.Join(stateDir, configFile),
 		configFile:    filepath.Join(stateDir, configFile),
+		daemonPath:    binaryName,
 		daemonPid:     -1,
 		daemonPid:     -1,
 		pidFile:       filepath.Join(stateDir, pidFile),
 		pidFile:       filepath.Join(stateDir, pidFile),
 		logger:        log.G(ctx).WithField("module", "libcontainerd"),
 		logger:        log.G(ctx).WithField("module", "libcontainerd"),
@@ -165,7 +169,8 @@ func (r *remote) startContainerd() error {
 		args = append(args, "--log-level", r.logLevel)
 		args = append(args, "--log-level", r.logLevel)
 	}
 	}
 
 
-	cmd := exec.Command(binaryName, args...)
+	r.logger.WithField("binary", r.daemonPath).Debug("starting containerd binary")
+	cmd := exec.Command(r.daemonPath, args...)
 	// redirect containerd logs to docker logs
 	// redirect containerd logs to docker logs
 	cmd.Stdout = os.Stdout
 	cmd.Stdout = os.Stdout
 	cmd.Stderr = os.Stderr
 	cmd.Stderr = os.Stderr

+ 1 - 0
libcontainerd/supervisor/remote_daemon_linux.go

@@ -11,6 +11,7 @@ import (
 )
 )
 
 
 const (
 const (
+	binaryName    = "containerd"
 	sockFile      = "containerd.sock"
 	sockFile      = "containerd.sock"
 	debugSockFile = "containerd-debug.sock"
 	debugSockFile = "containerd-debug.sock"
 )
 )

+ 33 - 0
libcontainerd/supervisor/remote_daemon_options.go

@@ -1,4 +1,10 @@
 package supervisor // import "github.com/docker/docker/libcontainerd/supervisor"
 package supervisor // import "github.com/docker/docker/libcontainerd/supervisor"
+import (
+	"os"
+	"path/filepath"
+
+	"github.com/pkg/errors"
+)
 
 
 import (
 import (
 	"github.com/containerd/log"
 	"github.com/containerd/log"
@@ -33,3 +39,30 @@ func WithCRIDisabled() DaemonOpt {
 		return nil
 		return nil
 	}
 	}
 }
 }
+
+// WithDetectLocalBinary checks if a containerd binary is present in the same
+// directory as the dockerd binary, and overrides the path of the containerd
+// binary to start if found. If no binary is found, no changes are made.
+func WithDetectLocalBinary() DaemonOpt {
+	return func(r *remote) error {
+		dockerdPath, err := os.Executable()
+		if err != nil {
+			return errors.Wrap(err, "looking up binary path")
+		}
+
+		localBinary := filepath.Join(filepath.Dir(dockerdPath), binaryName)
+		fi, err := os.Stat(localBinary)
+		if err != nil {
+			if !errors.Is(err, os.ErrNotExist) {
+				return err
+			}
+			return nil
+		}
+		if fi.IsDir() {
+			return errors.Errorf("local containerd path found (%s), but is a directory", localBinary)
+		}
+		r.daemonPath = localBinary
+		r.logger.WithError(err).WithField("binary", localBinary).Debug("failed to look up local containerd binary; using default binary")
+		return nil
+	}
+}

+ 3 - 2
libcontainerd/supervisor/remote_daemon_windows.go

@@ -7,8 +7,9 @@ import (
 )
 )
 
 
 const (
 const (
-	grpcPipeName  = `\\.\pipe\containerd-containerd`
-	debugPipeName = `\\.\pipe\containerd-debug`
+	binaryName    = "containerd.exe"
+	grpcPipeName  = `\\.\pipe\docker-containerd`
+	debugPipeName = `\\.\pipe\docker-containerd-debug`
 )
 )
 
 
 func (r *remote) setDefaults() {
 func (r *remote) setDefaults() {