From d19f69bd7b6cf2c0c8bf406a8313bdf458a66222 Mon Sep 17 00:00:00 2001 From: tianya Date: Fri, 24 Feb 2023 19:44:48 +0800 Subject: [PATCH] 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 | 48 ++++++++++++++++++++++++++++++++---- 5 files changed, 76 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..35df099a9 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 errors.New("could not connect to conatiner. Docker or podman or containerd may not be installed or running") } // 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..be90f6ad8 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,44 @@ 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 supportRuntime = func(containerRuntime string) bool { + cacheOnce.Do(func() { + 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) || supportRuntime(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 supportRuntime(containerRuntime) { + return "nerdctl" + } if IsValidContainerRuntime(containerRuntime) { return strings.TrimSpace(containerRuntime) } @@ -188,6 +209,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()