diff --git a/cmd/podman/kube/play.go b/cmd/podman/kube/play.go index cfa6f39495..04cc7b73e0 100644 --- a/cmd/podman/kube/play.go +++ b/cmd/podman/kube/play.go @@ -205,6 +205,9 @@ func playFlags(cmd *cobra.Command) { exitFlagName := "service-exit-code-propagation" flags.StringVar(&playOptions.ExitCodePropagation, exitFlagName, "", "Exit-code propagation of the service container") _ = flags.MarkHidden(exitFlagName) + + replicas := "replicas" + flags.BoolVar(&playOptions.Replicas, replicas, false, "Replicas allows multiple Pods creation") } } diff --git a/docs/source/markdown/podman-kube-play.1.md.in b/docs/source/markdown/podman-kube-play.1.md.in index 0d4cbec4a6..3ef3f31243 100644 --- a/docs/source/markdown/podman-kube-play.1.md.in +++ b/docs/source/markdown/podman-kube-play.1.md.in @@ -267,6 +267,8 @@ Define or override a port definition in the YAML file. The lists of ports in the YAML file and the command line are merged. Matching is done by using the **containerPort** field. If **containerPort** exists in both the YAML file and the option, the latter takes precedence. +In case this options is used with **--replicas** option then number of published ports should be equal to the number of replicas in container spec, e.g. Deployment.spec.replicas is 3, then **--publish** is set to "8080:80,8081:80,8082:80" + #### **--publish-all** Setting this option to `true` will expose all ports to the host, @@ -285,6 +287,10 @@ Suppress output information when pulling images Tears down the pods created by a previous run of `kube play` and recreates the pods. This option is used to keep the existing pods up to date based upon the Kubernetes YAML. +#### **--replicas** + +Only one Pod replica is created by default, despite the desired number of Pods in the Kubernetes Deployment resource. This setting overrides the default behavior, allowing the desired number of Pods to be created. + #### **--seccomp-profile-root**=*path* Directory path for seccomp profiles (default: "/var/lib/kubelet/seccomp"). (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go index ae51bebd67..63b19aeba3 100644 --- a/pkg/domain/entities/play.go +++ b/pkg/domain/entities/play.go @@ -81,6 +81,8 @@ type PlayKubeOptions struct { Wait bool // SystemContext - used when building the image SystemContext *types.SystemContext + // Replicas allows multiple Pods creation + Replicas bool } // PlayKubePod represents a single pod and associated containers created by play kube diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 15d1a61aa4..ffd4507a91 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -276,6 +276,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options ipIndex := 0 var configMaps []v1.ConfigMap + var numReplicas int32 ranContainers := false // set the ranContainers bool to true if at least one container was successfully started. @@ -404,15 +405,46 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options return nil, fmt.Errorf("unable to read YAML as Kube Deployment: %w", err) } - r, proxies, err := ic.playKubeDeployment(ctx, &deploymentYAML, options, &ipIndex, configMaps, serviceContainer) - if err != nil { - return nil, err + numReplicas = 1 + if deploymentYAML.Spec.Replicas != nil { + numReplicas = *deploymentYAML.Spec.Replicas } - notifyProxies = append(notifyProxies, proxies...) - report.Pods = append(report.Pods, r.Pods...) + if numReplicas > 1 && options.Replicas { + if len(options.PublishPorts) > 0 && len(options.PublishPorts) != int(numReplicas) { + return nil, fmt.Errorf("number of Pod replics aren't equal to the number of published ports: %d replicas, %d published ports", numReplicas, len(options.PublishPorts)) + } + + var portToPublish = make([]string, numReplicas) + copy(portToPublish, options.PublishPorts) + options.PublishPorts = make([]string, 1) + for i := range numReplicas { + options.PublishPorts[0] = portToPublish[i] + podName := fmt.Sprintf("%s-pod-%d", deploymentYAML.ObjectMeta.Name, i) + r, proxies, err := ic.playKubeDeployment(ctx, &deploymentYAML, options, &ipIndex, configMaps, serviceContainer, podName) + if err != nil { + return nil, err + } + notifyProxies = append(notifyProxies, proxies...) + + report.Pods = append(report.Pods, r.Pods...) + setRanContainers(r) + } + } else { + if numReplicas > 1 { + logrus.Warnf("Limiting replica count to 1, use `--replicas` to enable more than one replica") + } + podName := fmt.Sprintf("%s-pod", deploymentYAML.ObjectMeta.Name) + r, proxies, err := ic.playKubeDeployment(ctx, &deploymentYAML, options, &ipIndex, configMaps, serviceContainer, podName) + if err != nil { + return nil, err + } + notifyProxies = append(notifyProxies, proxies...) + + report.Pods = append(report.Pods, r.Pods...) + setRanContainers(r) + } validKinds++ - setRanContainers(r) case "Job": var jobYAML v1.Job @@ -563,11 +595,10 @@ func (ic *ContainerEngine) playKubeDaemonSet(ctx context.Context, daemonSetYAML return &report, proxies, nil } -func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAML *v1apps.Deployment, options entities.PlayKubeOptions, ipIndex *int, configMaps []v1.ConfigMap, serviceContainer *libpod.Container) (*entities.PlayKubeReport, []*notifyproxy.NotifyProxy, error) { +func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAML *v1apps.Deployment, options entities.PlayKubeOptions, ipIndex *int, configMaps []v1.ConfigMap, serviceContainer *libpod.Container, podName string) (*entities.PlayKubeReport, []*notifyproxy.NotifyProxy, error) { var ( deploymentName string podSpec v1.PodTemplateSpec - numReplicas int32 report entities.PlayKubeReport ) @@ -575,16 +606,9 @@ func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAM if deploymentName == "" { return nil, nil, errors.New("deployment does not have a name") } - numReplicas = 1 - if deploymentYAML.Spec.Replicas != nil { - numReplicas = *deploymentYAML.Spec.Replicas - } - if numReplicas > 1 { - logrus.Warnf("Limiting replica count to 1, more than one replica is not supported by Podman") - } + podSpec = deploymentYAML.Spec.Template - podName := fmt.Sprintf("%s-pod", deploymentName) podReport, proxies, err := ic.playKubePod(ctx, podName, &podSpec, options, ipIndex, deploymentYAML.Annotations, configMaps, serviceContainer) if err != nil { return nil, nil, fmt.Errorf("encountered while bringing up pod %s: %w", podName, err)