Skip to content
Draft
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
49433fe
support nerdctl+containerd runtime (#1232)
tianyax Feb 24, 2023
33e17ee
add containerd runtime validity check and fix test errors
tianyax Feb 25, 2023
cbcb2af
reduce unnecessary container runtime availability checks
tianyax Feb 27, 2023
9200b3d
fixed test failed on macos
tianyax Feb 27, 2023
a3341a6
update help message
tianyax Feb 27, 2023
a3fdee0
use the string nerdctl as a constant
tianyax Feb 27, 2023
003646e
revert containerd support on macos
tianyax Feb 28, 2023
ed91064
update README
tianyax Feb 28, 2023
ebdb471
Merge branch 'master' into containerd-runtime
pravinpushkar Feb 28, 2023
4b9d430
Merge remote-tracking branch 'master' into containerd-runtime
tianyax Mar 2, 2023
70ca0d1
Merge branch 'master' into containerd-runtime
tianyax Mar 2, 2023
968654c
Merge branch 'master' into containerd-runtime
tianyax Mar 2, 2023
6c4c6f8
fixed args missing
tianyax Mar 2, 2023
12a5070
Merge branch 'master' into containerd-runtime
mukundansundar Mar 16, 2023
a76ba30
Merge branch 'master' into containerd-runtime
tianyax Mar 17, 2023
5abfe55
Apply suggestions from code review
tianyax Mar 22, 2023
093dbc5
update runtime installation in README
tianyax Mar 22, 2023
db2a515
add e2e tests with containerd
tianyax Mar 26, 2023
4c8afdf
Merge branch 'master' into containerd-runtime
shubham1172 Mar 26, 2023
3e193c8
Merge branch 'master' into containerd-runtime
pravinpushkar Apr 3, 2023
9525a1c
Merge branch 'master' into containerd-runtime
mukundansundar Apr 5, 2023
8164923
fixed the issue in e2e tests
tianyax Apr 13, 2023
c22aa11
Merge branch 'master' into containerd-runtime
pravinpushkar Apr 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 41 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simpler.

Choosing a container runtime

Docker (recommended for new users)

Docker instructions

Podman

Podman instructions

Containerd

Containerd instructions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, thanks very much!


**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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 .
Expand Down Expand Up @@ -292,7 +327,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
Expand Down Expand Up @@ -356,7 +391,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*
Expand Down
8 changes: 4 additions & 4 deletions cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,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"))

Expand Down Expand Up @@ -92,7 +92,7 @@ dapr init --runtime-path <path-to-install-directory>

# See more at: https://docs.dapr.io/getting-started/
`,
Run: func(cmd *cobra.Command, args []string) {
Run: func(cmd *cobra.Command, _ []string) {
print.PendingStatusEvent(os.Stdout, "Making the jump to hyperspace...")
imageRegistryFlag := strings.TrimSpace(viper.GetString("image-registry"))

Expand Down Expand Up @@ -161,7 +161,7 @@ dapr init --runtime-path <path-to-install-directory>
}

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, podman and containerd.")
os.Exit(1)
}
err := standalone.Init(runtimeVersion, dashboardVersion, dockerNetwork, slimMode, imageRegistryURI, fromDir, containerRuntime, imageVariant, daprRuntimePath)
Expand Down Expand Up @@ -215,7 +215,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", "", defaultContainerRuntime, "The container runtime to use. Supported values are docker (default) and podman")
InitCmd.Flags().StringVarP(&containerRuntime, "container-runtime", "", defaultContainerRuntime, "The container runtime to use. Supported values are docker (default), podman and containerd")
InitCmd.Flags().StringVarP(&caRootCertificateFile, "ca-root-certificate", "", "", "The root certificate file")
InitCmd.Flags().StringVarP(&issuerPrivateKeyFile, "issuer-private-key", "", "", "The issuer certificate private key")
InitCmd.Flags().StringVarP(&issuerPublicCertificateFile, "issuer-public-certificate", "", "", "The issuer certificate")
Expand Down
8 changes: 4 additions & 4 deletions cmd/uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ dapr uninstall -k
# This will remove the .dapr directory present in the path <path-to-install-directory>
dapr uninstall --runtime-path <path-to-install-directory>
`,
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 {
Expand All @@ -69,7 +69,7 @@ dapr uninstall --runtime-path <path-to-install-directory>
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, podman and containerd.")
os.Exit(1)
}
print.InfoStatusEvent(os.Stdout, "Removing Dapr from your machine...")
Expand All @@ -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), podman and containerd")
RootCmd.AddCommand(UninstallCmd)
}
35 changes: 21 additions & 14 deletions pkg/standalone/standalone.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,8 @@ 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 {
// If --slim installation is not requested, check if docker, podman or containerd is installed.
if !utils.ContainerRuntimeAvailable(containerRuntime) {
return fmt.Errorf("could not connect to %s. %s may not be installed or running", containerRuntime, containerRuntime)
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down
8 changes: 3 additions & 5 deletions pkg/standalone/uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
containerRuntime = strings.TrimSpace(containerRuntime)
runtimeCmd := utils.GetContainerRuntimeCmd(containerRuntime)
containerErrs = removeContainers(uninstallPlacementContainer, uninstallAll, dockerNetwork, runtimeCmd)
}

Expand Down
47 changes: 38 additions & 9 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,30 +38,38 @@ import (
type ContainerRuntime string

const (
DOCKER ContainerRuntime = "docker"
PODMAN ContainerRuntime = "podman"
DOCKER ContainerRuntime = "docker"
PODMAN ContainerRuntime = "podman"
CONTAINERD ContainerRuntime = "containerd"

NERDCTL = "nerdctl"

marinerImageVariantName = "mariner"

socketFormat = "%s/dapr-%s-%s.socket"
)

// 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) || 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 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 {
if IsValidContainerRuntime(containerRuntime) {
return strings.TrimSpace(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)
}
// Default to docker.
return string(DOCKER)
}

// Contains returns true if vs contains x.
Expand Down Expand Up @@ -188,6 +196,27 @@ func IsPodmanInstalled() bool {
return true
}

// IsContainerdInstalled checks whether nerdctl and containerd is installed/running.
func IsContainerdInstalled() bool {
if _, err := RunCmdAndWait("nerdctl", "info"); err != nil {
print.FailureStatusEvent(os.Stderr, err.Error())
return false
}
return true
}

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.
func IsDaprListeningOnPort(port int, timeout time.Duration) error {
start := time.Now()
Expand Down
20 changes: 18 additions & 2 deletions utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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: true,
},
{
name: "containerd runtime with extra spaces is valid, and nerdctl is returned",
input: " containerd ",
expected: "nerdctl",
valid: true,
},
{
name: "podman runtime is valid, and is returned as is",
input: "podman",
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down