From 49433fe1879bc14ece790c708be9d05a7dad5354 Mon Sep 17 00:00:00 2001 From: tianya Date: Fri, 24 Feb 2023 19:44:48 +0800 Subject: [PATCH 01/13] support nerdctl+containerd runtime (#1232) Signed-off-by: tianya --- cmd/init.go | 8 +++--- cmd/uninstall.go | 8 +++--- pkg/standalone/standalone.go | 37 ++++++++++++++++----------- pkg/standalone/uninstall.go | 8 +++--- utils/utils.go | 49 ++++++++++++++++++++++++++++++++---- 5 files changed, 77 insertions(+), 33 deletions(-) diff --git a/cmd/init.go b/cmd/init.go index 4653708d5..6afa40324 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -48,7 +48,7 @@ var ( var InitCmd = &cobra.Command{ Use: "init", Short: "Install Dapr on supported hosting platforms. Supported platforms: Kubernetes and self-hosted", - PreRun: func(cmd *cobra.Command, args []string) { + PreRun: func(cmd *cobra.Command, _ []string) { viper.BindPFlag("network", cmd.Flags().Lookup("network")) viper.BindPFlag("image-registry", cmd.Flags().Lookup("image-registry")) }, @@ -87,7 +87,7 @@ dapr init --runtime-path # See more at: https://docs.dapr.io/getting-started/ `, - Run: func(cmd *cobra.Command, args []string) { + Run: func(*cobra.Command, []string) { print.PendingStatusEvent(os.Stdout, "Making the jump to hyperspace...") imageRegistryFlag := strings.TrimSpace(viper.GetString("image-registry")) @@ -148,7 +148,7 @@ dapr init --runtime-path } if !utils.IsValidContainerRuntime(containerRuntime) { - print.FailureStatusEvent(os.Stdout, "Invalid container runtime. Supported values are docker and podman.") + print.FailureStatusEvent(os.Stdout, "Invalid container runtime. Supported values are docker and podman and containerd.") os.Exit(1) } err := standalone.Init(runtimeVersion, dashboardVersion, dockerNetwork, slimMode, imageRegistryURI, fromDir, containerRuntime, imageVariant, daprRuntimePath) @@ -194,7 +194,7 @@ func init() { InitCmd.Flags().BoolP("help", "h", false, "Print this help message") InitCmd.Flags().StringArrayVar(&values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") InitCmd.Flags().String("image-registry", "", "Custom/private docker image repository URL") - InitCmd.Flags().StringVarP(&containerRuntime, "container-runtime", "", "docker", "The container runtime to use. Supported values are docker (default) and podman") + InitCmd.Flags().StringVarP(&containerRuntime, "container-runtime", "", "docker", "The container runtime to use. Supported values are docker (default) and podman and containerd") RootCmd.AddCommand(InitCmd) } diff --git a/cmd/uninstall.go b/cmd/uninstall.go index a4885c935..37e74177a 100644 --- a/cmd/uninstall.go +++ b/cmd/uninstall.go @@ -52,11 +52,11 @@ dapr uninstall -k # This will remove the .dapr directory present in the path dapr uninstall --runtime-path `, - PreRun: func(cmd *cobra.Command, args []string) { + PreRun: func(cmd *cobra.Command, _ []string) { viper.BindPFlag("network", cmd.Flags().Lookup("network")) viper.BindPFlag("install-path", cmd.Flags().Lookup("install-path")) }, - Run: func(cmd *cobra.Command, args []string) { + Run: func(*cobra.Command, []string) { var err error if uninstallKubernetes { @@ -69,7 +69,7 @@ dapr uninstall --runtime-path err = kubernetes.Uninstall(uninstallNamespace, uninstallAll, timeout) } else { if !utils.IsValidContainerRuntime(uninstallContainerRuntime) { - print.FailureStatusEvent(os.Stdout, "Invalid container runtime. Supported values are docker and podman.") + print.FailureStatusEvent(os.Stdout, "Invalid container runtime. Supported values are docker and podman and containerd.") os.Exit(1) } print.InfoStatusEvent(os.Stdout, "Removing Dapr from your machine...") @@ -92,6 +92,6 @@ func init() { UninstallCmd.Flags().String("network", "", "The Docker network from which to remove the Dapr runtime") UninstallCmd.Flags().StringVarP(&uninstallNamespace, "namespace", "n", "dapr-system", "The Kubernetes namespace to uninstall Dapr from") UninstallCmd.Flags().BoolP("help", "h", false, "Print this help message") - UninstallCmd.Flags().StringVarP(&uninstallContainerRuntime, "container-runtime", "", "docker", "The container runtime to use. Supported values are docker (default) and podman") + UninstallCmd.Flags().StringVarP(&uninstallContainerRuntime, "container-runtime", "", "docker", "The container runtime to use. Supported values are docker (default) and podman and containerd") RootCmd.AddCommand(UninstallCmd) } diff --git a/pkg/standalone/standalone.go b/pkg/standalone/standalone.go index 3f063a7af..5594378fe 100644 --- a/pkg/standalone/standalone.go +++ b/pkg/standalone/standalone.go @@ -161,10 +161,9 @@ func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMod fromDir = strings.TrimSpace(fromDir) setAirGapInit(fromDir) if !slimMode { - // If --slim installation is not requested, check if docker is installed. - conatinerRuntimeAvailable := utils.IsDockerInstalled() || utils.IsPodmanInstalled() - if !conatinerRuntimeAvailable { - return errors.New("could not connect to Docker. Docker may not be installed or running") + // If --slim installation is not requested, check if docker or podman or containerd is installed. + if !utils.ContainerRuntimeAvailable() { + return fmt.Errorf("could not connect to container. %v may not be installed or running", containerRuntime) } // Initialize default registry only if any of --slim or --image-registry or --from-dir are not given. @@ -363,10 +362,8 @@ func runZipkin(wg *sync.WaitGroup, errorChan chan<- error, info initInfo) { ) if info.dockerNetwork != "" { - args = append( - args, - "--network", info.dockerNetwork, - "--network-alias", DaprZipkinContainerName) + networks := withContainerNetwork(info.containerRuntime, info.dockerNetwork, DaprZipkinContainerName) + args = append(args, networks...) } else { args = append( args, @@ -430,10 +427,8 @@ func runRedis(wg *sync.WaitGroup, errorChan chan<- error, info initInfo) { ) if info.dockerNetwork != "" { - args = append( - args, - "--network", info.dockerNetwork, - "--network-alias", DaprRedisContainerName) + networks := withContainerNetwork(info.containerRuntime, info.dockerNetwork, DaprRedisContainerName) + args = append(args, networks...) } else { args = append( args, @@ -510,9 +505,8 @@ func runPlacementService(wg *sync.WaitGroup, errorChan chan<- error, info initIn } if info.dockerNetwork != "" { - args = append(args, - "--network", info.dockerNetwork, - "--network-alias", DaprPlacementContainerName) + networks := withContainerNetwork(info.containerRuntime, info.dockerNetwork, DaprPlacementContainerName) + args = append(args, networks...) } else { osPort := 50005 if runtime.GOOS == daprWindowsOS { @@ -1011,6 +1005,19 @@ func createDefaultConfiguration(zipkinHost, filePath string) error { return err } +// withContainerNetwork connect a container to a network. +// Network alias is now only parsed by docker, +// `podman` is only compatible with docker commands +// and does not really implement this feature. +// `containerd` does not support network alias. +func withContainerNetwork(containerCmd, network, containerName string) []string { + networks := []string{"--network", network} + if utils.GetContainerRuntimeCmd(containerCmd) == string(utils.DOCKER) { + networks = append(networks, "--network-alias", containerName) + } + return networks +} + func checkAndOverWriteFile(filePath string, b []byte) error { _, err := os.Stat(filePath) if os.IsNotExist(err) { diff --git a/pkg/standalone/uninstall.go b/pkg/standalone/uninstall.go index 21ce3272a..b228810eb 100644 --- a/pkg/standalone/uninstall.go +++ b/pkg/standalone/uninstall.go @@ -90,11 +90,9 @@ func Uninstall(uninstallAll bool, dockerNetwork string, containerRuntime string, print.WarningStatusEvent(os.Stdout, "WARNING: could not delete dapr bin dir: %s", daprBinDir) } - containerRuntime = strings.TrimSpace(containerRuntime) - runtimeCmd := utils.GetContainerRuntimeCmd(containerRuntime) - conatinerRuntimeAvailable := false - conatinerRuntimeAvailable = utils.IsDockerInstalled() || utils.IsPodmanInstalled() - if conatinerRuntimeAvailable { + if utils.ContainerRuntimeAvailable() { + containerRuntime = strings.TrimSpace(containerRuntime) + runtimeCmd := utils.GetContainerRuntimeCmd(containerRuntime) containerErrs = removeContainers(uninstallPlacementContainer, uninstallAll, dockerNetwork, runtimeCmd) } diff --git a/utils/utils.go b/utils/utils.go index 8d612629e..599f192ab 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -24,7 +24,9 @@ import ( "os" "os/exec" "path/filepath" + "runtime" "strings" + "sync" "time" "github.com/dapr/cli/pkg/print" @@ -38,25 +40,45 @@ import ( type ContainerRuntime string const ( - DOCKER ContainerRuntime = "docker" - PODMAN ContainerRuntime = "podman" + DOCKER ContainerRuntime = "docker" + PODMAN ContainerRuntime = "podman" + CONTAINERD ContainerRuntime = "containerd" + + MACOS = runtime.GOOS == "darwin" marinerImageVariantName = "mariner" socketFormat = "%s/dapr-%s-%s.socket" ) +var ( + cacheOnce sync.Once + supportMacos bool +) + +var IsValidRuntimeOnMacos = func(containerRuntime string) bool { + cacheOnce.Do(func() { + containerRuntime = strings.TrimSpace(containerRuntime) + supportMacos = containerRuntime == string(CONTAINERD) && !MACOS + }) + return supportMacos +} + // IsValidContainerRuntime checks if the input is a valid container runtime. -// Valid container runtimes are docker and podman. +// Valid container runtimes are docker and podman and containerd. func IsValidContainerRuntime(containerRuntime string) bool { containerRuntime = strings.TrimSpace(containerRuntime) - return containerRuntime == string(DOCKER) || containerRuntime == string(PODMAN) + return containerRuntime == string(DOCKER) || containerRuntime == string(PODMAN) || IsValidRuntimeOnMacos(containerRuntime) } // GetContainerRuntimeCmd returns a valid container runtime to be used by CLI operations. -// If the input is a valid container runtime, it is returned as is. +// If the input is a valid container runtime, it is returned client tool. // Otherwise the default container runtime, docker, is returned. func GetContainerRuntimeCmd(containerRuntime string) string { + // containerd runtime use nerdctl tool. + if IsValidRuntimeOnMacos(containerRuntime) { + return "nerdctl" + } if IsValidContainerRuntime(containerRuntime) { return strings.TrimSpace(containerRuntime) } @@ -188,6 +210,23 @@ func IsPodmanInstalled() bool { return true } +// IsContainerdInstalled checks whether nerdctl and containerd is installed/running. +func IsContainerdInstalled() bool { + if MACOS { + print.FailureStatusEvent(os.Stderr, "containerd is not supported on macos") + return false + } + if _, err := RunCmdAndWait("nerdctl", "info"); err != nil { + print.FailureStatusEvent(os.Stderr, err.Error()) + return false + } + return true +} + +func ContainerRuntimeAvailable() bool { + return IsDockerInstalled() || IsPodmanInstalled() || IsContainerdInstalled() +} + // IsDaprListeningOnPort checks if Dapr is litening to a given port. func IsDaprListeningOnPort(port int, timeout time.Duration) error { start := time.Now() From 33e17ee49b6d81eeb5c8cba36dcc02c8a21f4cd3 Mon Sep 17 00:00:00 2001 From: tianya Date: Sat, 25 Feb 2023 22:46:11 +0800 Subject: [PATCH 02/13] add containerd runtime validity check and fix test errors Signed-off-by: tianya --- utils/utils.go | 13 ++----------- utils/utils_test.go | 20 ++++++++++++++++++-- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/utils/utils.go b/utils/utils.go index 599f192ab..5632f78da 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -26,7 +26,6 @@ import ( "path/filepath" "runtime" "strings" - "sync" "time" "github.com/dapr/cli/pkg/print" @@ -51,17 +50,9 @@ const ( socketFormat = "%s/dapr-%s-%s.socket" ) -var ( - cacheOnce sync.Once - supportMacos bool -) - var IsValidRuntimeOnMacos = func(containerRuntime string) bool { - cacheOnce.Do(func() { - containerRuntime = strings.TrimSpace(containerRuntime) - supportMacos = containerRuntime == string(CONTAINERD) && !MACOS - }) - return supportMacos + containerRuntime = strings.TrimSpace(containerRuntime) + return containerRuntime == string(CONTAINERD) && !MACOS } // IsValidContainerRuntime checks if the input is a valid container runtime. diff --git a/utils/utils_test.go b/utils/utils_test.go index b9b8639dc..809211191 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -30,6 +30,18 @@ func TestContainerRuntimeUtils(t *testing.T) { expected string valid bool }{ + { + name: "containerd runtime is valid, and nerdctl is returned", + input: "containerd", + expected: "nerdctl", + valid: !MACOS, + }, + { + name: "containerd runtime with extra spaces is valid, and nerdctl is returned", + input: " containerd ", + expected: "nerdctl", + valid: !MACOS, + }, { name: "podman runtime is valid, and is returned as is", input: "podman", @@ -176,7 +188,9 @@ func TestGetVersionAndImageVariant(t *testing.T) { func TestValidateFilePaths(t *testing.T) { dirName := createTempDir(t, "test_validate_paths") - defer cleanupTempDir(t, dirName) + t.Cleanup(func() { + cleanupTempDir(t, dirName) + }) validFile := createTempFile(t, dirName, "valid_test_file.yaml") testcases := []struct { name string @@ -254,7 +268,9 @@ func TestGetAbsPath(t *testing.T) { func TestReadFile(t *testing.T) { fileName := createTempFile(t, "", "test_read_file") - defer cleanupTempDir(t, fileName) + t.Cleanup(func() { + cleanupTempDir(t, fileName) + }) testcases := []struct { name string input string From cbcb2afa3e54cf87d65961562c97e94536848f16 Mon Sep 17 00:00:00 2001 From: tianya Date: Mon, 27 Feb 2023 10:48:26 +0800 Subject: [PATCH 03/13] reduce unnecessary container runtime availability checks Signed-off-by: tianya --- pkg/standalone/standalone.go | 2 +- pkg/standalone/uninstall.go | 2 +- utils/utils.go | 12 ++++++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/pkg/standalone/standalone.go b/pkg/standalone/standalone.go index 5594378fe..9f607796c 100644 --- a/pkg/standalone/standalone.go +++ b/pkg/standalone/standalone.go @@ -162,7 +162,7 @@ func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMod setAirGapInit(fromDir) if !slimMode { // If --slim installation is not requested, check if docker or podman or containerd is installed. - if !utils.ContainerRuntimeAvailable() { + if !utils.ContainerRuntimeAvailable(containerRuntime) { return fmt.Errorf("could not connect to container. %v may not be installed or running", containerRuntime) } diff --git a/pkg/standalone/uninstall.go b/pkg/standalone/uninstall.go index b228810eb..5b8631cf3 100644 --- a/pkg/standalone/uninstall.go +++ b/pkg/standalone/uninstall.go @@ -90,7 +90,7 @@ func Uninstall(uninstallAll bool, dockerNetwork string, containerRuntime string, print.WarningStatusEvent(os.Stdout, "WARNING: could not delete dapr bin dir: %s", daprBinDir) } - if utils.ContainerRuntimeAvailable() { + if utils.ContainerRuntimeAvailable(containerRuntime) { containerRuntime = strings.TrimSpace(containerRuntime) runtimeCmd := utils.GetContainerRuntimeCmd(containerRuntime) containerErrs = removeContainers(uninstallPlacementContainer, uninstallAll, dockerNetwork, runtimeCmd) diff --git a/utils/utils.go b/utils/utils.go index 5632f78da..c2d76bec5 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -214,8 +214,16 @@ func IsContainerdInstalled() bool { return true } -func ContainerRuntimeAvailable() bool { - return IsDockerInstalled() || IsPodmanInstalled() || IsContainerdInstalled() +func ContainerRuntimeAvailable(containerRuntime string) bool { + containerRuntime = strings.TrimSpace(containerRuntime) + switch ContainerRuntime(containerRuntime) { + case PODMAN: + return IsPodmanInstalled() + case CONTAINERD: + return IsContainerdInstalled() + default: + return IsDockerInstalled() + } } // IsDaprListeningOnPort checks if Dapr is litening to a given port. From 9200b3d6c7b0b0922f10589a56676f7bb1a27d05 Mon Sep 17 00:00:00 2001 From: tianya Date: Mon, 27 Feb 2023 11:53:35 +0800 Subject: [PATCH 04/13] fixed test failed on macos Signed-off-by: tianya --- utils/utils_test.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/utils/utils_test.go b/utils/utils_test.go index 809211191..d3eb37bdf 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -24,6 +24,12 @@ import ( ) func TestContainerRuntimeUtils(t *testing.T) { + containerCmd := func() string { + if !MACOS { + return "nerdctl" + } + return "docker" + }() testcases := []struct { name string input string @@ -33,13 +39,13 @@ func TestContainerRuntimeUtils(t *testing.T) { { name: "containerd runtime is valid, and nerdctl is returned", input: "containerd", - expected: "nerdctl", + expected: containerCmd, valid: !MACOS, }, { name: "containerd runtime with extra spaces is valid, and nerdctl is returned", input: " containerd ", - expected: "nerdctl", + expected: containerCmd, valid: !MACOS, }, { From a3341a677af5e98ee971dd6cdcd208f4f27ffdf8 Mon Sep 17 00:00:00 2001 From: tianya <12004412+tianyax@users.noreply.github.com> Date: Mon, 27 Feb 2023 17:39:03 +0800 Subject: [PATCH 05/13] update help message Co-authored-by: Pravin Pushkar Signed-off-by: tianya <12004412+tianyax@users.noreply.github.com> --- cmd/init.go | 4 ++-- cmd/uninstall.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/init.go b/cmd/init.go index 6afa40324..e2c219714 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -148,7 +148,7 @@ dapr init --runtime-path } if !utils.IsValidContainerRuntime(containerRuntime) { - print.FailureStatusEvent(os.Stdout, "Invalid container runtime. Supported values are docker and podman and containerd.") + print.FailureStatusEvent(os.Stdout, "Invalid container runtime. Supported values are docker, podman and containerd.") os.Exit(1) } err := standalone.Init(runtimeVersion, dashboardVersion, dockerNetwork, slimMode, imageRegistryURI, fromDir, containerRuntime, imageVariant, daprRuntimePath) @@ -194,7 +194,7 @@ func init() { InitCmd.Flags().BoolP("help", "h", false, "Print this help message") InitCmd.Flags().StringArrayVar(&values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") InitCmd.Flags().String("image-registry", "", "Custom/private docker image repository URL") - InitCmd.Flags().StringVarP(&containerRuntime, "container-runtime", "", "docker", "The container runtime to use. Supported values are docker (default) and podman and containerd") + InitCmd.Flags().StringVarP(&containerRuntime, "container-runtime", "", "docker", "The container runtime to use. Supported values are docker (default), podman and containerd") RootCmd.AddCommand(InitCmd) } diff --git a/cmd/uninstall.go b/cmd/uninstall.go index 37e74177a..c68ee61b4 100644 --- a/cmd/uninstall.go +++ b/cmd/uninstall.go @@ -69,7 +69,7 @@ dapr uninstall --runtime-path err = kubernetes.Uninstall(uninstallNamespace, uninstallAll, timeout) } else { if !utils.IsValidContainerRuntime(uninstallContainerRuntime) { - print.FailureStatusEvent(os.Stdout, "Invalid container runtime. Supported values are docker and podman and containerd.") + print.FailureStatusEvent(os.Stdout, "Invalid container runtime. Supported values are docker, podman and containerd.") os.Exit(1) } print.InfoStatusEvent(os.Stdout, "Removing Dapr from your machine...") @@ -92,6 +92,6 @@ func init() { UninstallCmd.Flags().String("network", "", "The Docker network from which to remove the Dapr runtime") UninstallCmd.Flags().StringVarP(&uninstallNamespace, "namespace", "n", "dapr-system", "The Kubernetes namespace to uninstall Dapr from") UninstallCmd.Flags().BoolP("help", "h", false, "Print this help message") - UninstallCmd.Flags().StringVarP(&uninstallContainerRuntime, "container-runtime", "", "docker", "The container runtime to use. Supported values are docker (default) and podman and containerd") + UninstallCmd.Flags().StringVarP(&uninstallContainerRuntime, "container-runtime", "", "docker", "The container runtime to use. Supported values are docker (default), podman and containerd") RootCmd.AddCommand(UninstallCmd) } From a3fdee0e4d2b32eecba5880d2c299c9aa3c1ac75 Mon Sep 17 00:00:00 2001 From: tianya Date: Mon, 27 Feb 2023 17:46:40 +0800 Subject: [PATCH 06/13] use the string nerdctl as a constant Signed-off-by: tianya --- utils/utils.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/utils.go b/utils/utils.go index c2d76bec5..468ed420b 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -43,7 +43,8 @@ const ( PODMAN ContainerRuntime = "podman" CONTAINERD ContainerRuntime = "containerd" - MACOS = runtime.GOOS == "darwin" + NERDCTL = "nerdctl" + MACOS = runtime.GOOS == "darwin" marinerImageVariantName = "mariner" @@ -68,7 +69,7 @@ func IsValidContainerRuntime(containerRuntime string) bool { func GetContainerRuntimeCmd(containerRuntime string) string { // containerd runtime use nerdctl tool. if IsValidRuntimeOnMacos(containerRuntime) { - return "nerdctl" + return NERDCTL } if IsValidContainerRuntime(containerRuntime) { return strings.TrimSpace(containerRuntime) From 003646ec915736e8aad1fab172c3b7a6e2c3e051 Mon Sep 17 00:00:00 2001 From: tianya Date: Tue, 28 Feb 2023 20:32:36 +0800 Subject: [PATCH 07/13] revert containerd support on macos Signed-off-by: tianya --- utils/utils.go | 28 +++++++++------------------- utils/utils_test.go | 14 ++++---------- 2 files changed, 13 insertions(+), 29 deletions(-) diff --git a/utils/utils.go b/utils/utils.go index 468ed420b..70047358b 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -24,7 +24,6 @@ import ( "os" "os/exec" "path/filepath" - "runtime" "strings" "time" @@ -44,38 +43,33 @@ const ( CONTAINERD ContainerRuntime = "containerd" NERDCTL = "nerdctl" - MACOS = runtime.GOOS == "darwin" marinerImageVariantName = "mariner" socketFormat = "%s/dapr-%s-%s.socket" ) -var IsValidRuntimeOnMacos = func(containerRuntime string) bool { - containerRuntime = strings.TrimSpace(containerRuntime) - return containerRuntime == string(CONTAINERD) && !MACOS -} - // IsValidContainerRuntime checks if the input is a valid container runtime. // Valid container runtimes are docker and podman and containerd. func IsValidContainerRuntime(containerRuntime string) bool { containerRuntime = strings.TrimSpace(containerRuntime) - return containerRuntime == string(DOCKER) || containerRuntime == string(PODMAN) || IsValidRuntimeOnMacos(containerRuntime) + return containerRuntime == string(DOCKER) || containerRuntime == string(PODMAN) || containerRuntime == string(CONTAINERD) } // GetContainerRuntimeCmd returns a valid container runtime to be used by CLI operations. // If the input is a valid container runtime, it is returned client tool. // Otherwise the default container runtime, docker, is returned. func GetContainerRuntimeCmd(containerRuntime string) string { - // containerd runtime use nerdctl tool. - if IsValidRuntimeOnMacos(containerRuntime) { + switch strings.TrimSpace(containerRuntime) { + case string(CONTAINERD): + // containerd runtime use nerdctl tool. return NERDCTL + case string(PODMAN): + return string(PODMAN) + default: + // Default to docker. + return string(DOCKER) } - if IsValidContainerRuntime(containerRuntime) { - return strings.TrimSpace(containerRuntime) - } - // Default to docker. - return string(DOCKER) } // Contains returns true if vs contains x. @@ -204,10 +198,6 @@ func IsPodmanInstalled() bool { // IsContainerdInstalled checks whether nerdctl and containerd is installed/running. func IsContainerdInstalled() bool { - if MACOS { - print.FailureStatusEvent(os.Stderr, "containerd is not supported on macos") - return false - } if _, err := RunCmdAndWait("nerdctl", "info"); err != nil { print.FailureStatusEvent(os.Stderr, err.Error()) return false diff --git a/utils/utils_test.go b/utils/utils_test.go index d3eb37bdf..d64a00471 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -24,12 +24,6 @@ import ( ) func TestContainerRuntimeUtils(t *testing.T) { - containerCmd := func() string { - if !MACOS { - return "nerdctl" - } - return "docker" - }() testcases := []struct { name string input string @@ -39,14 +33,14 @@ func TestContainerRuntimeUtils(t *testing.T) { { name: "containerd runtime is valid, and nerdctl is returned", input: "containerd", - expected: containerCmd, - valid: !MACOS, + expected: "nerdctl", + valid: true, }, { name: "containerd runtime with extra spaces is valid, and nerdctl is returned", input: " containerd ", - expected: containerCmd, - valid: !MACOS, + expected: "nerdctl", + valid: true, }, { name: "podman runtime is valid, and is returned as is", From ed910641c3b23be99b699d5f40fa5280f8bb2027 Mon Sep 17 00:00:00 2001 From: tianya Date: Tue, 28 Feb 2023 22:00:40 +0800 Subject: [PATCH 08/13] update README Signed-off-by: tianya --- README.md | 47 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 07985f858..fa7bd83af 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,49 @@ The Dapr CLI allows you to setup Dapr on your local dev machine or on a Kubernet ### Prerequisites -On default, during initialization the Dapr CLI will install the Dapr binaries as well as setup a developer environment to help you get started easily with Dapr. This environment uses Docker containers, therefore Docker needs to be installed. If you prefer to run Dapr without this environment and no dependency on Docker, after installation of the CLI make sure to follow the instructions to initialize Dapr using [slim init](#slim-init). +On default, during initialization the Dapr CLI will install the Dapr binaries as well as setup a developer environment to help you get started easily with Dapr. This environment uses `Docker`, `Podman` or `Containerd` containers, therefore container runtime needs to be installed. If you prefer to run Dapr without this environment and without any container dependencies, after installation of the CLI make sure to follow the instructions to initialize Dapr using [slim init](#slim-init). -Note, if you are a new user, it is strongly recommended to install Docker and use the regular init command. +#### Note, if you are a new user, it is strongly recommended to install Docker and use the regular init command. * Install [Docker](https://docs.docker.com/install/) >__Note: On Windows, Docker must be running in Linux Containers mode__ +#### If you want to use podman as a runtime, then please refer to the installation. + +* Install [Podman](https://podman-desktop.io/docs/Installation) + +#### If you want to use containerd as a runtime, then please refer to the installation. + +**Windows and Linux** + +* Step 1: Install [Containerd](https://github.com/containerd/containerd/blob/main/docs/getting-started.md). + +* Step 2: Install [nerdctl](https://github.com/containerd/nerdctl/blob/main/docs/installation.md). + +__MacOS__ + +> containerd and nerdctl are not supported on macOS. Instead, you can use `lima`, `colima`, or `rancher-desktop` to get containerd support on macOS. The steps below show how to install these tools using brew. +> + +* [Lima](https://github.com/lima-vm/lima): + + ``` + brew install lima + limactl start + ln -s $(which nerdctl.lima) /usr/local/bin/nerdctl + ``` + +* [Colima](https://github.com/abiosoft/colima): + + ``` + brew install colima + colima start --runtime containerd + colima nerdctl install + ``` + +* [Rancher-desktop](https://docs.rancherdesktop.io/getting-started/installation#installing-rancher-desktop-on-macos) + ### Installing Dapr CLI #### Using script to install the latest release @@ -139,7 +174,7 @@ Runtime version: v1.0.0 #### Install with mariner images -You can install Dapr Runtime using mariner images using the `--image-variant` flag. +You can install Dapr Runtime using mariner images using the `--image-variant` flag. ```bash # Installing Dapr with Mariner images @@ -178,7 +213,7 @@ docker run --name "dapr_zipkin" --restart always -d -p 9411:9411 openzipkin/zipk docker run --name "dapr_redis" --restart always -d -p 6379:6379 redis ``` -Alternatively to the above, you can also have slim installation as well to install dapr without running any Docker containers in airgap mode. +Alternatively to the above, you can also have slim installation as well to install dapr without running any Docker containers in airgap mode. ```bash ./dapr init --slim --from-dir . @@ -278,7 +313,7 @@ Output should look like as follows: All available [Helm Chart values](https://github.com/dapr/dapr/tree/master/charts/dapr#configuration) can be set by using the `--set` flag: ```bash -dapr init -k --set global.tag=1.0.0 --set dapr_operator.logLevel=error +dapr init -k --set global.tag=1.0.0 --set dapr_operator.logLevel=error ``` #### Installing to a custom namespace @@ -342,7 +377,7 @@ The example above shows how to upgrade from your current version to version `1.0 All available [Helm Chart values](https://github.com/dapr/dapr/tree/master/charts/dapr#configuration) can be set by using the `--set` flag: ```bash -dapr upgrade -k --runtime-version=1.0.0 --set global.tag=my-tag --set dapr_operator.logLevel=error +dapr upgrade -k --runtime-version=1.0.0 --set global.tag=my-tag --set dapr_operator.logLevel=error ``` *Note: do not use the `dapr upgrade` command if you're upgrading from 0.x versions of Dapr* From 6c4c6f8b02b3788ee08c57b2a978839f149e24e1 Mon Sep 17 00:00:00 2001 From: tianya Date: Thu, 2 Mar 2023 16:31:04 +0800 Subject: [PATCH 09/13] fixed args missing Signed-off-by: tianya --- cmd/init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/init.go b/cmd/init.go index 85c00bd9d..230d8106d 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -88,7 +88,7 @@ dapr init --runtime-path # See more at: https://docs.dapr.io/getting-started/ `, - Run: func(*cobra.Command, []string) { + Run: func(cmd *cobra.Command, _ []string) { print.PendingStatusEvent(os.Stdout, "Making the jump to hyperspace...") imageRegistryFlag := strings.TrimSpace(viper.GetString("image-registry")) From 5abfe55ea36bda0f0acaf38c74358cddd987cf60 Mon Sep 17 00:00:00 2001 From: tianya Date: Wed, 22 Mar 2023 17:13:31 +0800 Subject: [PATCH 10/13] Apply suggestions from code review Co-authored-by: Shubham Sharma Signed-off-by: tianya --- README.md | 2 +- pkg/standalone/standalone.go | 2 +- utils/utils.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 653dcf961..2d53896fb 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ The Dapr CLI allows you to setup Dapr on your local dev machine or on a Kubernet On default, during initialization the Dapr CLI will install the Dapr binaries as well as setup a developer environment to help you get started easily with Dapr. This environment uses `Docker`, `Podman` or `Containerd` containers, therefore container runtime needs to be installed. If you prefer to run Dapr without this environment and without any container dependencies, after installation of the CLI make sure to follow the instructions to initialize Dapr using [slim init](#slim-init). -#### Note, if you are a new user, it is strongly recommended to install Docker and use the regular init command. +>__Note, if you are a new user, it is strongly recommended to install Docker and use the regular init command.__ * Install [Docker](https://docs.docker.com/install/) diff --git a/pkg/standalone/standalone.go b/pkg/standalone/standalone.go index 4346b8511..70eec87a7 100644 --- a/pkg/standalone/standalone.go +++ b/pkg/standalone/standalone.go @@ -161,7 +161,7 @@ func Init(runtimeVersion, dashboardVersion string, dockerNetwork string, slimMod fromDir = strings.TrimSpace(fromDir) setAirGapInit(fromDir) if !slimMode { - // If --slim installation is not requested, check if docker, podman or containerd is installed. + // If --slim installation is not requested, check if the container runtime is installed. if !utils.ContainerRuntimeAvailable(containerRuntime) { return fmt.Errorf("could not connect to %s. %s may not be installed or running", containerRuntime, containerRuntime) } diff --git a/utils/utils.go b/utils/utils.go index 70047358b..8b4e9c7dd 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -57,7 +57,7 @@ func IsValidContainerRuntime(containerRuntime string) bool { } // GetContainerRuntimeCmd returns a valid container runtime to be used by CLI operations. -// If the input is a valid container runtime, it is returned client tool. +// If the input is a valid container runtime, the client tool is returned. // Otherwise the default container runtime, docker, is returned. func GetContainerRuntimeCmd(containerRuntime string) string { switch strings.TrimSpace(containerRuntime) { From 093dbc591ca25a0d2215fefa14bcf844ac745228 Mon Sep 17 00:00:00 2001 From: tianya Date: Wed, 22 Mar 2023 18:48:00 +0800 Subject: [PATCH 11/13] update runtime installation in README Signed-off-by: tianya --- README.md | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 2d53896fb..ab8e446d3 100644 --- a/README.md +++ b/README.md @@ -15,44 +15,42 @@ On default, during initialization the Dapr CLI will install the Dapr binaries as >__Note, if you are a new user, it is strongly recommended to install Docker and use the regular init command.__ -* Install [Docker](https://docs.docker.com/install/) +### Choosing a container runtime ->__Note: On Windows, Docker must be running in Linux Containers mode__ +* [Docker](https://docs.docker.com/install/) (recommended for new users) -#### If you want to use podman as a runtime, then please refer to the installation. + >__Note: On Windows, Docker must be running in Linux Containers mode__ -* Install [Podman](https://podman-desktop.io/docs/Installation) +* [Podman](https://podman-desktop.io/docs/Installation) -#### If you want to use containerd as a runtime, then please refer to the installation. +* `Containerd` -**Windows and Linux** + >__Windows and Linux__ -* Step 1: Install [Containerd](https://github.com/containerd/containerd/blob/main/docs/getting-started.md). + * Step 1: Install [Containerd](https://github.com/containerd/containerd/blob/main/docs/getting-started.md). -* Step 2: Install [nerdctl](https://github.com/containerd/nerdctl/blob/main/docs/installation.md). + * Step 2: Install [nerdctl](https://github.com/containerd/nerdctl/blob/main/docs/installation.md). -__MacOS__ + >__MacOS__ + >> `containerd` and `nerdctl` are not directly supported on macOS. Instead, you need to choose `lima`, `colima`, or `rancher-desktop` to get this feature. -> containerd and nerdctl are not supported on macOS. Instead, you can use `lima`, `colima`, or `rancher-desktop` to get containerd support on macOS. The steps below show how to install these tools using brew. -> + * [Lima](https://github.com/lima-vm/lima) -* [Lima](https://github.com/lima-vm/lima): - - ``` + ```bash brew install lima limactl start ln -s $(which nerdctl.lima) /usr/local/bin/nerdctl ``` -* [Colima](https://github.com/abiosoft/colima): + * [Colima](https://github.com/abiosoft/colima) - ``` + ```bash brew install colima colima start --runtime containerd colima nerdctl install ``` -* [Rancher-desktop](https://docs.rancherdesktop.io/getting-started/installation#installing-rancher-desktop-on-macos) + * [Rancher-desktop](https://docs.rancherdesktop.io/getting-started/installation#installing-rancher-desktop-on-macos) ### Installing Dapr CLI From db2a515c3e7f1932051f171aeab11e6c2503a4b6 Mon Sep 17 00:00:00 2001 From: tianya Date: Sun, 26 Mar 2023 16:20:48 +0800 Subject: [PATCH 12/13] add e2e tests with containerd Signed-off-by: tianya --- .github/workflows/self_hosted_e2e.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/self_hosted_e2e.yaml b/.github/workflows/self_hosted_e2e.yaml index 799b5683f..9beb75cfa 100644 --- a/.github/workflows/self_hosted_e2e.yaml +++ b/.github/workflows/self_hosted_e2e.yaml @@ -55,6 +55,10 @@ jobs: target_os: darwin - os: windows-latest target_os: windows + - os: macos-latest + target_os: darwin + target_arch: amd64 + dapr_install_mode: complete_containerd exclude: - os: windows-latest dapr_install_mode: complete @@ -108,6 +112,12 @@ jobs: podman machine init podman machine start echo "CONTAINER_RUNTIME=podman" >> $GITHUB_ENV + - name: Install containerd - MacOS + if: matrix.os == 'macos-latest' && matrix.dapr_install_mode == 'complete_containerd' + run: | + colima start --runtime containerd + colima nerdctl install + echo "CONTAINER_RUNTIME=containerd" >> $GITHUB_ENV - name: Determine latest Dapr Runtime version including Pre-releases if: github.base_ref == 'master' run: | From 8164923909835e1116e978f3b37f405b380f9a92 Mon Sep 17 00:00:00 2001 From: tianya Date: Thu, 13 Apr 2023 18:33:07 +0800 Subject: [PATCH 13/13] fixed the issue in e2e tests Signed-off-by: tianya --- .github/workflows/self_hosted_e2e.yaml | 39 ++++++++-- tests/e2e/standalone/init_test.go | 98 ++++++++++++++++++-------- tests/e2e/standalone/uninstall_test.go | 27 ++++++- utils/utils.go | 8 +-- 4 files changed, 132 insertions(+), 40 deletions(-) diff --git a/.github/workflows/self_hosted_e2e.yaml b/.github/workflows/self_hosted_e2e.yaml index 9beb75cfa..b29db0517 100644 --- a/.github/workflows/self_hosted_e2e.yaml +++ b/.github/workflows/self_hosted_e2e.yaml @@ -47,7 +47,7 @@ jobs: matrix: os: [macos-latest, ubuntu-latest, windows-latest] target_arch: [amd64] - dapr_install_mode: [slim, complete] + dapr_install_mode: [slim, complete, complete_containerd] include: - os: ubuntu-latest target_os: linux @@ -55,13 +55,11 @@ jobs: target_os: darwin - os: windows-latest target_os: windows - - os: macos-latest - target_os: darwin - target_arch: amd64 - dapr_install_mode: complete_containerd exclude: - os: windows-latest dapr_install_mode: complete + - os: windows-latest + dapr_install_mode: complete_containerd steps: - name: Check out code into the Go module directory uses: actions/checkout@v3 @@ -118,6 +116,37 @@ jobs: colima start --runtime containerd colima nerdctl install echo "CONTAINER_RUNTIME=containerd" >> $GITHUB_ENV + - name: Install containerd - Linux + if: matrix.os == 'ubuntu-latest' && matrix.dapr_install_mode == 'complete_containerd' + run: | + # remove moby-runc, version not match + sudo apt remove moby-runc + # install containerd and rootlesskit, testing requires rootless mode + sudo apt install -y containerd rootlesskit + wget -q https://github.com/containerd/nerdctl/releases/download/v1.3.0/nerdctl-1.3.0-linux-amd64.tar.gz -O nerdctl-linux-amd64.tar.gz + # install nerdctl + tar xvf ./nerdctl-linux-amd64.tar.gz -C /usr/local/bin/ + containerd-rootless-setuptool.sh install + # update cni to new version + wget -q https://github.com/containernetworking/plugins/releases/download/v1.2.0/cni-plugins-linux-amd64-v1.2.0.tgz -O cni-plugins-linux-amd64.tgz + sudo tar xvf ./cni-plugins-linux-amd64.tgz -C /usr/lib/cni/ + echo "CONTAINER_RUNTIME=containerd" >> $GITHUB_ENV + - name: Install contianerd - Windows + if: matrix.os == 'windows-latest' && matrix.dapr_install_mode == 'complete_containerd' + run: | + # install nerdctl + $NVersion="1.3.0" + curl.exe -L https://github.com/containerd/nerdctl/releases/download/v$NVersion/nerdctl-$NVersion-windows-amd64.tar.gz -o nerdctl-windows-amd64.tar.gz + tar.exe xvf .\nerdctl-windows-amd64.tar.gz -C "$(go env GOPATH)\bin" + # Download and extract desired containerd Windows binaries + $Version="1.7.0" + curl.exe -L https://github.com/containerd/containerd/releases/download/v$Version/containerd-$Version-windows-amd64.tar.gz -o containerd-windows-amd64.tar.gz + tar.exe xvf .\containerd-windows-amd64.tar.gz && cd .\bin\ + .\containerd.exe config default | Out-File config.toml -Encoding ascii + # Register and start service + .\containerd.exe --register-service + Start-Service containerd + echo "CONTAINER_RUNTIME=containerd" >> $GITHUB_ENV - name: Determine latest Dapr Runtime version including Pre-releases if: github.base_ref == 'master' run: | diff --git a/tests/e2e/standalone/init_test.go b/tests/e2e/standalone/init_test.go index 14a688bc2..3221206e4 100644 --- a/tests/e2e/standalone/init_test.go +++ b/tests/e2e/standalone/init_test.go @@ -188,47 +188,87 @@ func TestStandaloneInit(t *testing.T) { // this test is automatically skipped. func verifyContainers(t *testing.T, daprRuntimeVersion string) { t.Run("verifyContainers", func(t *testing.T) { - if isSlimMode() { + switch { + case isSlimMode(): t.Log("Skipping container verification because of slim installation") - return + case containerRuntime() == "containerd": + verifyContainerdRuntime(t, daprRuntimeVersion) + default: + verifyDockerRuntime(t, daprRuntimeVersion) } + }) +} - cli, err := dockerClient.NewClientWithOpts(dockerClient.FromEnv) - require.NoError(t, err) +func verifyContainerdRuntime(t *testing.T, daprRuntimeVersion string) { + ret, err := spawn.Command("nerdctl", "ps", "--filter", "name=dapr", "--format", "{{.Names}} {{.Image}}") + require.NoError(t, err) - containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{}) - require.NoError(t, err) + daprContainers := map[string]string{ + "dapr_placement": daprRuntimeVersion, + "dapr_zipkin": "", + "dapr_redis": "", + } - daprContainers := map[string]string{ - "dapr_placement": daprRuntimeVersion, - "dapr_zipkin": "", - "dapr_redis": "", + // convert to map + containers := map[string]string{} + for _, item := range strings.Split(ret, "\n") { + if split := strings.Split(item, " "); len(split) > 1 { + containers[split[0]] = split[1] } + } - for _, container := range containers { - t.Logf("Found container: %v %s %s\n", container.Names, container.Image, container.State) - if container.State != "running" { - continue - } - name := strings.TrimPrefix(container.Names[0], "/") - if expectedVersion, ok := daprContainers[name]; ok { - if expectedVersion != "" { - versionIndex := strings.LastIndex(container.Image, ":") - if versionIndex == -1 { - continue - } - version := container.Image[versionIndex+1:] - if version != expectedVersion { - continue - } + for name, image := range containers { + t.Logf("Found container: %v %s\n", name, image) + if expectedVersion, ok := daprContainers[name]; ok { + if expectedVersion != "" { + versionIndex := strings.LastIndex(image, ":") + if versionIndex == -1 || image[versionIndex+1:] != expectedVersion { + continue } + } + delete(daprContainers, name) + } + } + + assert.Empty(t, daprContainers, "Missing containers: %v", daprContainers) +} - delete(daprContainers, name) +func verifyDockerRuntime(t *testing.T, daprRuntimeVersion string) { + cli, err := dockerClient.NewClientWithOpts(dockerClient.FromEnv) + require.NoError(t, err) + + containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{}) + require.NoError(t, err) + + daprContainers := map[string]string{ + "dapr_placement": daprRuntimeVersion, + "dapr_zipkin": "", + "dapr_redis": "", + } + + for _, container := range containers { + t.Logf("Found container: %v %s %s\n", container.Names, container.Image, container.State) + if container.State != "running" { + continue + } + name := strings.TrimPrefix(container.Names[0], "/") + if expectedVersion, ok := daprContainers[name]; ok { + if expectedVersion != "" { + versionIndex := strings.LastIndex(container.Image, ":") + if versionIndex == -1 { + continue + } + version := container.Image[versionIndex+1:] + if version != expectedVersion { + continue + } } + + delete(daprContainers, name) } + } - assert.Empty(t, daprContainers, "Missing containers: %v", daprContainers) - }) + assert.Empty(t, daprContainers, "Missing containers: %v", daprContainers) } // verifyBinaries ensures that the correct binaries are present in the correct path. diff --git a/tests/e2e/standalone/uninstall_test.go b/tests/e2e/standalone/uninstall_test.go index ae1545a99..5ad5c6ea2 100644 --- a/tests/e2e/standalone/uninstall_test.go +++ b/tests/e2e/standalone/uninstall_test.go @@ -23,6 +23,7 @@ import ( "strings" "testing" + "github.com/dapr/cli/tests/e2e/spawn" "github.com/docker/docker/api/types" dockerClient "github.com/docker/docker/client" "github.com/stretchr/testify/assert" @@ -57,11 +58,17 @@ func TestStandaloneUninstall(t *testing.T) { // verifyNoContainers verifies that no Dapr containers are running. func verifyNoContainers(t *testing.T) { - if isSlimMode() { + switch { + case isSlimMode(): t.Log("Skipping verifyNoContainers test in slim mode") - return + case containerRuntime() == "containerd": + verifyNoContainerdRuntime(t) + default: + verifyNoDockerRuntime(t) } +} +func verifyNoDockerRuntime(t *testing.T) { cli, err := dockerClient.NewClientWithOpts(dockerClient.FromEnv) require.NoError(t, err) @@ -85,3 +92,19 @@ func verifyNoContainers(t *testing.T) { // If any Dapr containers are still running after uninstall, this assertion will fail. assert.Equal(t, 3, len(daprContainers), "Found Dapr containers still running") } + +func verifyNoContainerdRuntime(t *testing.T) { + ret, err := spawn.Command("nerdctl", "ps", "--filter", "name=dapr", "--format", "{{.Names}}") + require.NoError(t, err) + + daprContainers := []string{ + "dapr_placement", + "dapr_zipkin", + "dapr_redis", + } + + containers := strings.Split(ret, "\n") + for _, container := range containers { + assert.NotContains(t, daprContainers, container, "Found Dapr containers still running") + } +} diff --git a/utils/utils.go b/utils/utils.go index 1344c3fdf..e85cf6bc2 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -144,15 +144,15 @@ func RunCmdAndWait(name string, args ...string) (string, error) { return "", err } - resp, err := io.ReadAll(stdout) - if err != nil { - return "", err - } errB, err := io.ReadAll(stderr) if err != nil { //nolint return "", nil } + resp, err := io.ReadAll(stdout) + if err != nil { + return "", err + } err = cmd.Wait() if err != nil {