summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2018-12-09 14:26:21 -0600
committerbaude <bbaude@redhat.com>2018-12-19 14:20:55 -0600
commit9b03cacc87c4d59fc301c21ef73ddc301ec753fb (patch)
treeec7318272db56a8a3ba11b5ac1b01d262b21742c
parenteddfe6ba628d17435559ba32a8ef748c386105aa (diff)
downloadpodman-9b03cacc87c4d59fc301c21ef73ddc301ec753fb.tar.gz
podman-9b03cacc87c4d59fc301c21ef73ddc301ec753fb.tar.bz2
podman-9b03cacc87c4d59fc301c21ef73ddc301ec753fb.zip
Add Play
podman play kube adds the ability for the user to recreate pods and containers from a Kubernetes YAML file in libpod. Signed-off-by: baude <bbaude@redhat.com>
-rwxr-xr-xAPI.md24
-rw-r--r--cmd/podman/create.go63
-rw-r--r--cmd/podman/generate_kube.go1
-rw-r--r--cmd/podman/main.go1
-rw-r--r--cmd/podman/play.go23
-rw-r--r--cmd/podman/play_kube.go245
-rw-r--r--cmd/podman/varlink/io.podman.varlink12
-rw-r--r--completions/bash/podman37
-rw-r--r--docs/podman-generate-kube.1.md2
-rw-r--r--docs/podman-play-kube.1.md78
-rw-r--r--docs/podman-play.1.md20
-rw-r--r--libpod/kube.go34
12 files changed, 499 insertions, 41 deletions
diff --git a/API.md b/API.md
index 7bc866d98..51787496c 100755
--- a/API.md
+++ b/API.md
@@ -31,6 +31,10 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func ExportImage(name: string, destination: string, compress: bool, tags: []string) string](#ExportImage)
+[func GenerateKube() NotImplemented](#GenerateKube)
+
+[func GenerateKubeService() NotImplemented](#GenerateKubeService)
+
[func GetAttachSockets(name: string) Sockets](#GetAttachSockets)
[func GetContainer(name: string) ListContainerData](#GetContainer)
@@ -99,6 +103,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func RenameContainer() NotImplemented](#RenameContainer)
+[func ReplayKube() NotImplemented](#ReplayKube)
+
[func ResizeContainerTty() NotImplemented](#ResizeContainerTty)
[func RestartContainer(name: string, timeout: int) string](#RestartContainer)
@@ -358,6 +364,18 @@ a booleon option to force compression. It also takes in a string array of tags
tags of the same image to a tarball (each tag should be of the form <image>:<tag>). Upon completion, the ID
of the image is returned. If the image cannot be found in local storage, an [ImageNotFound](#ImageNotFound)
error will be returned. See also [ImportImage](ImportImage).
+### <a name="GenerateKube"></a>func GenerateKube
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method GenerateKube() [NotImplemented](#NotImplemented)</div>
+GenerateKube generates a Kubernetes v1 Pod description of a Podman container or pod
+and its containers. The description is in YAML. See also [ReplayKube](ReplayKube).
+### <a name="GenerateKubeService"></a>func GenerateKubeService
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method GenerateKubeService() [NotImplemented](#NotImplemented)</div>
+GenerateKubeService generates a Kubernetes v1 Service description of a Podman container or pod
+and its containers. The description is in YAML. See also [GenerateKube](GenerateKube).
### <a name="GetAttachSockets"></a>func GetAttachSockets
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -808,6 +826,12 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.RemovePod '{"name": "62f4
method RenameContainer() [NotImplemented](#NotImplemented)</div>
This method has not be implemented yet.
+### <a name="ReplayKube"></a>func ReplayKube
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method ReplayKube() [NotImplemented](#NotImplemented)</div>
+ReplayKube recreates a pod and its containers based on a Kubernetes v1 Pod description (in YAML)
+like that created by GenerateKube. See also [GenerateKube](GenerateKube).
### <a name="ResizeContainerTty"></a>func ResizeContainerTty
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index 870eb28d6..2b31a6423 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -146,37 +146,10 @@ func createContainer(c *cli.Context, runtime *libpod.Runtime) (*libpod.Container
return nil, nil, err
}
- runtimeSpec, err := cc.CreateConfigToOCISpec(createConfig)
- if err != nil {
- return nil, nil, err
- }
-
- options, err := createConfig.GetContainerCreateOptions(runtime)
- if err != nil {
- return nil, nil, err
- }
-
- became, ret, err := joinOrCreateRootlessUserNamespace(createConfig, runtime)
+ ctr, err := createContainerFromCreateConfig(runtime, createConfig, ctx)
if err != nil {
return nil, nil, err
}
- if became {
- os.Exit(ret)
- }
-
- ctr, err := runtime.NewContainer(ctx, runtimeSpec, options...)
- if err != nil {
- return nil, nil, err
- }
-
- createConfigJSON, err := json.Marshal(createConfig)
- if err != nil {
- return nil, nil, err
- }
- if err := ctr.AddArtifact("create-config", createConfigJSON); err != nil {
- return nil, nil, err
- }
-
if cidFile != nil {
_, err = cidFile.WriteString(ctr.ID())
if err != nil {
@@ -913,3 +886,37 @@ func joinOrCreateRootlessUserNamespace(createConfig *cc.CreateConfig, runtime *l
}
return rootless.BecomeRootInUserNS()
}
+
+func createContainerFromCreateConfig(r *libpod.Runtime, createConfig *cc.CreateConfig, ctx context.Context) (*libpod.Container, error) {
+ runtimeSpec, err := cc.CreateConfigToOCISpec(createConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ options, err := createConfig.GetContainerCreateOptions(r)
+ if err != nil {
+ return nil, err
+ }
+
+ became, ret, err := joinOrCreateRootlessUserNamespace(createConfig, r)
+ if err != nil {
+ return nil, err
+ }
+ if became {
+ os.Exit(ret)
+ }
+
+ ctr, err := r.NewContainer(ctx, runtimeSpec, options...)
+ if err != nil {
+ return nil, err
+ }
+
+ createConfigJSON, err := json.Marshal(createConfig)
+ if err != nil {
+ return nil, err
+ }
+ if err := ctr.AddArtifact("create-config", createConfigJSON); err != nil {
+ return nil, err
+ }
+ return ctr, nil
+}
diff --git a/cmd/podman/generate_kube.go b/cmd/podman/generate_kube.go
index 8f2f0de32..f63bd431b 100644
--- a/cmd/podman/generate_kube.go
+++ b/cmd/podman/generate_kube.go
@@ -33,7 +33,6 @@ var (
}
)
-// generateKubeYAMLCmdgenerates or replays kube
func generateKubeYAMLCmd(c *cli.Context) error {
var (
podYAML *v1.Pod
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 2db6c5dec..f47a75761 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -90,6 +90,7 @@ func main() {
portCommand,
pullCommand,
pushCommand,
+ playCommand,
restartCommand,
rmCommand,
rmiCommand,
diff --git a/cmd/podman/play.go b/cmd/podman/play.go
new file mode 100644
index 000000000..adbab3480
--- /dev/null
+++ b/cmd/podman/play.go
@@ -0,0 +1,23 @@
+package main
+
+import (
+ "github.com/urfave/cli"
+)
+
+var (
+ playSubCommands = []cli.Command{
+ playKubeCommand,
+ }
+
+ playDescription = "Play a pod and its containers from a structured file."
+ playCommand = cli.Command{
+ Name: "play",
+ Usage: "play a container or pod",
+ Description: playDescription,
+ ArgsUsage: "",
+ Subcommands: playSubCommands,
+ UseShortOptionHandling: true,
+ OnUsageError: usageErrorHandler,
+ Hidden: true,
+ }
+)
diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go
new file mode 100644
index 000000000..f165c5f0f
--- /dev/null
+++ b/cmd/podman/play_kube.go
@@ -0,0 +1,245 @@
+package main
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "strings"
+
+ "github.com/containers/image/types"
+ "github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/cmd/podman/shared"
+ "github.com/containers/libpod/libpod"
+ image2 "github.com/containers/libpod/libpod/image"
+ ns "github.com/containers/libpod/pkg/namespaces"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/containers/libpod/pkg/spec"
+ "github.com/containers/storage"
+ "github.com/cri-o/ocicni/pkg/ocicni"
+ "github.com/ghodss/yaml"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "github.com/urfave/cli"
+ "k8s.io/api/core/v1"
+)
+
+var (
+ playKubeFlags = []cli.Flag{
+ cli.StringFlag{
+ Name: "authfile",
+ Usage: "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. Use REGISTRY_AUTH_FILE environment variable to override. ",
+ },
+ cli.StringFlag{
+ Name: "cert-dir",
+ Usage: "`pathname` of a directory containing TLS certificates and keys",
+ },
+ cli.StringFlag{
+ Name: "creds",
+ Usage: "`credentials` (USERNAME:PASSWORD) to use for authenticating to a registry",
+ },
+ cli.BoolFlag{
+ Name: "quiet, q",
+ Usage: "Suppress output information when pulling images",
+ },
+ cli.StringFlag{
+ Name: "signature-policy",
+ Usage: "`pathname` of signature policy file (not usually used)",
+ },
+ cli.BoolTFlag{
+ Name: "tls-verify",
+ Usage: "require HTTPS and verify certificates when contacting registries (default: true)",
+ },
+ }
+ playKubeDescription = "Play a Pod and its containers based on a Kubrernetes YAML"
+ playKubeCommand = cli.Command{
+ Name: "kube",
+ Usage: "Play a pod based on Kubernetes YAML",
+ Description: playKubeDescription,
+ Action: playKubeYAMLCmd,
+ Flags: sortFlags(playKubeFlags),
+ ArgsUsage: "kubernetes YAML file",
+ UseShortOptionHandling: true,
+ OnUsageError: usageErrorHandler,
+ }
+)
+
+func playKubeYAMLCmd(c *cli.Context) error {
+ var (
+ podOptions []libpod.PodCreateOption
+ podYAML v1.Pod
+ registryCreds *types.DockerAuthConfig
+ containers []*libpod.Container
+ writer io.Writer
+ )
+
+ ctx := getContext()
+ if rootless.IsRootless() {
+ return errors.Wrapf(libpod.ErrNotImplemented, "rootless users")
+ }
+ args := c.Args()
+ if len(args) > 1 {
+ return errors.New("you can only play one kubernetes file at a time")
+ }
+ if len(args) < 1 {
+ return errors.New("you must supply at least one file")
+ }
+
+ runtime, err := libpodruntime.GetRuntime(c)
+ if err != nil {
+ return errors.Wrapf(err, "could not get runtime")
+ }
+ defer runtime.Shutdown(false)
+
+ content, err := ioutil.ReadFile(args[0])
+ if err != nil {
+ return err
+ }
+
+ if err := yaml.Unmarshal(content, &podYAML); err != nil {
+ return errors.Wrapf(err, "unable to read %s as YAML", args[0])
+ }
+
+ podOptions = append(podOptions, libpod.WithInfraContainer())
+ podOptions = append(podOptions, libpod.WithPodName(podYAML.ObjectMeta.Name))
+ // TODO for now we just used the default kernel namespaces; we need to add/subtract this from yaml
+
+ nsOptions, err := shared.GetNamespaceOptions(strings.Split(DefaultKernelNamespaces, ","))
+ if err != nil {
+ return err
+ }
+ podOptions = append(podOptions, nsOptions...)
+ podPorts := getPodPorts(podYAML.Spec.Containers)
+ podOptions = append(podOptions, libpod.WithInfraContainerPorts(podPorts))
+
+ // Create the Pod
+ pod, err := runtime.NewPod(ctx, podOptions...)
+ if err != nil {
+ return err
+ }
+ // Print the Pod's ID
+ fmt.Println(pod.ID())
+
+ podInfraID, err := pod.InfraContainerID()
+ if err != nil {
+ return err
+ }
+
+ namespaces := map[string]string{
+ // Disabled during code review per mheon
+ //"pid": fmt.Sprintf("container:%s", podInfraID),
+ "net": fmt.Sprintf("container:%s", podInfraID),
+ "user": fmt.Sprintf("container:%s", podInfraID),
+ "ipc": fmt.Sprintf("container:%s", podInfraID),
+ "uts": fmt.Sprintf("container:%s", podInfraID),
+ }
+ if !c.Bool("quiet") {
+ writer = os.Stderr
+ }
+
+ dockerRegistryOptions := image2.DockerRegistryOptions{
+ DockerRegistryCreds: registryCreds,
+ DockerCertPath: c.String("cert-dir"),
+ }
+ if c.IsSet("tls-verify") {
+ dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!c.BoolT("tls-verify"))
+ }
+
+ for _, container := range podYAML.Spec.Containers {
+ newImage, err := runtime.ImageRuntime().New(ctx, container.Image, c.String("signature-policy"), c.String("authfile"), writer, &dockerRegistryOptions, image2.SigningOptions{}, false)
+ if err != nil {
+ return err
+ }
+ createConfig := kubeContainerToCreateConfig(container, runtime, newImage, namespaces)
+ if err != nil {
+ return err
+ }
+ ctr, err := createContainerFromCreateConfig(runtime, createConfig, ctx)
+ if err != nil {
+ return err
+ }
+ containers = append(containers, ctr)
+ }
+
+ // start the containers
+ for _, ctr := range containers {
+ if err := ctr.Start(ctx); err != nil {
+ // Making this a hard failure here to avoid a mess
+ // the other containers are in created status
+ return err
+ }
+ fmt.Println(ctr.ID())
+ }
+
+ return nil
+}
+
+// getPodPorts converts a slice of kube container descriptions to an
+// array of ocicni portmapping descriptions usable in libpod
+func getPodPorts(containers []v1.Container) []ocicni.PortMapping {
+ var infraPorts []ocicni.PortMapping
+ for _, container := range containers {
+ for _, p := range container.Ports {
+ portBinding := ocicni.PortMapping{
+ HostPort: p.HostPort,
+ ContainerPort: p.ContainerPort,
+ Protocol: strings.ToLower(string(p.Protocol)),
+ }
+ if p.HostIP != "" {
+ logrus.Debug("HostIP on port bindings is not supported")
+ }
+ infraPorts = append(infraPorts, portBinding)
+ }
+ }
+ return infraPorts
+}
+
+// kubeContainerToCreateConfig takes a v1.Container and returns a createconfig describing a container
+func kubeContainerToCreateConfig(containerYAML v1.Container, runtime *libpod.Runtime, newImage *image2.Image, namespaces map[string]string) *createconfig.CreateConfig {
+ var (
+ containerConfig createconfig.CreateConfig
+ envs map[string]string
+ )
+
+ containerConfig.Runtime = runtime
+ containerConfig.Image = containerYAML.Image
+ containerConfig.ImageID = newImage.ID()
+ containerConfig.Name = containerYAML.Name
+ containerConfig.Tty = containerYAML.TTY
+ containerConfig.WorkDir = containerYAML.WorkingDir
+ if containerYAML.SecurityContext.ReadOnlyRootFilesystem != nil {
+ containerConfig.ReadOnlyRootfs = *containerYAML.SecurityContext.ReadOnlyRootFilesystem
+ }
+ if containerYAML.SecurityContext.Privileged != nil {
+ containerConfig.Privileged = *containerYAML.SecurityContext.Privileged
+ }
+
+ if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil {
+ containerConfig.NoNewPrivs = !*containerYAML.SecurityContext.AllowPrivilegeEscalation
+ }
+
+ containerConfig.Command = containerYAML.Command
+ containerConfig.StopSignal = 15
+
+ // If the user does not pass in ID mappings, just set to basics
+ if containerConfig.IDMappings == nil {
+ containerConfig.IDMappings = &storage.IDMappingOptions{}
+ }
+
+ containerConfig.NetMode = ns.NetworkMode(namespaces["net"])
+ containerConfig.IpcMode = ns.IpcMode(namespaces["ipc"])
+ containerConfig.UtsMode = ns.UTSMode(namespaces["uts"])
+ // disabled in code review per mheon
+ //containerConfig.PidMode = ns.PidMode(namespaces["pid"])
+ containerConfig.UsernsMode = ns.UsernsMode(namespaces["user"])
+
+ if len(containerYAML.Env) > 0 {
+ envs = make(map[string]string)
+ }
+ // Environment Variables
+ for _, e := range containerYAML.Env {
+ envs[e.Name] = e.Value
+ }
+ containerConfig.Env = envs
+ return &containerConfig
+}
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index 376bbc950..c1b7c703a 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -1016,6 +1016,18 @@ method UnmountContainer(name: string, force: bool) -> ()
# This function is not implemented yet.
method ListContainerPorts(name: string) -> (notimplemented: NotImplemented)
+# GenerateKube generates a Kubernetes v1 Pod description of a Podman container or pod
+# and its containers. The description is in YAML. See also [ReplayKube](ReplayKube).
+method GenerateKube() -> (notimplemented: NotImplemented)
+
+# GenerateKubeService generates a Kubernetes v1 Service description of a Podman container or pod
+# and its containers. The description is in YAML. See also [GenerateKube](GenerateKube).
+method GenerateKubeService() -> (notimplemented: NotImplemented)
+
+# ReplayKube recreates a pod and its containers based on a Kubernetes v1 Pod description (in YAML)
+# like that created by GenerateKube. See also [GenerateKube](GenerateKube).
+method ReplayKube() -> (notimplemented: NotImplemented)
+
# ImageNotFound means the image could not be found by the provided name or ID in local storage.
error ImageNotFound (name: string)
diff --git a/completions/bash/podman b/completions/bash/podman
index 4702ae0e0..2ce70a1f5 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -895,6 +895,26 @@ _podman_generate() {
;;
esac
}
+
+_podman_play() {
+ local boolean_options="
+ --help
+ -h
+ "
+ subcommands="
+ kube
+ "
+ __podman_subcommands "$subcommands $aliases" && return
+
+ case "$cur" in
+ -*)
+ COMPREPLY=( $( compgen -W "--help" -- "$cur" ) )
+ ;;
+ *)
+ COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) )
+ ;;
+ esac
+}
_podman_container() {
local boolean_options="
--help
@@ -2247,6 +2267,22 @@ _podman_generate_kube() {
--service
"
+_podman_play_kube() {
+ local options_with_args="
+ --authfile
+ --cert-dir
+ --creds
+ --signature-policy
+ "
+
+ local boolean_options="
+ -h
+ --help
+ --quiet
+ -q
+ --tls-verify
+ "
+
_podman_container_runlabel() {
local options_with_args="
--authfile
@@ -2750,6 +2786,7 @@ _podman_podman() {
ps
pull
push
+ play
restart
rm
rmi
diff --git a/docs/podman-generate-kube.1.md b/docs/podman-generate-kube.1.md
index 396f69615..5236f23fe 100644
--- a/docs/podman-generate-kube.1.md
+++ b/docs/podman-generate-kube.1.md
@@ -145,7 +145,7 @@ status:
```
## SEE ALSO
-podman(1), podman-container, podman-pod
+podman(1), podman-container, podman-pod, podman-play
# HISTORY
Decemeber 2018, Originally compiled by Brent Baude (bbaude at redhat dot com)
diff --git a/docs/podman-play-kube.1.md b/docs/podman-play-kube.1.md
new file mode 100644
index 000000000..3fd9746a5
--- /dev/null
+++ b/docs/podman-play-kube.1.md
@@ -0,0 +1,78 @@
+% podman-play-kube Podman Man Pages
+% Brent Baude
+% December 2018
+# NAME
+podman-play-kube - Create pods and containers based on Kubernetes YAML
+
+# SYNOPSIS
+**podman play kube **
+[**-h**|**--help**]
+[**--authfile**]
+[**--cert-dir**]
+[**--creds**]
+[***-q** | **--quiet**]
+[**--signature-policy**]
+[**--tls-verify**]
+kubernetes_input.yml
+
+# DESCRIPTION
+**podman play kube** will read in a structured file of Kubernetes YAML. It will then recreate
+the pod and containers described in the YAML. The containers within the pod are then started and
+the ID of the new Pod is output.
+
+Ideally the input file would be one created by Podman. This would guarantee a smooth import and expected results.
+
+# OPTIONS:
+
+**--authfile**
+
+Path of the authentication file. Default is ${XDG_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
+If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`.
+
+Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE
+environment variable. `export REGISTRY_AUTH_FILE=path`
+
+**--cert-dir** *path*
+
+Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry.
+Default certificates directory is _/etc/containers/certs.d_.
+
+**--creds**
+
+The [username[:password]] to use to authenticate with the registry if required.
+If one or both values are not supplied, a command line prompt will appear and the
+value can be entered. The password is entered without echo.
+
+**--quiet, -q**
+
+Suppress output information when pulling images
+
+**--signature-policy="PATHNAME"**
+
+Pathname of a signature policy file to use. It is not recommended that this
+option be used, as the default behavior of using the system-wide default policy
+(frequently */etc/containers/policy.json*) is most often preferred.
+
+**--tls-verify**
+
+Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true,
+then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified,
+TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf.
+
+**--help**, **-h**
+
+Print usage statement
+
+## Examples ##
+
+Recreate the pod and containers as described in a file called `demo.yml`
+```
+$ podman play kube demo.yml
+52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6
+```
+
+## SEE ALSO
+podman(1), podman-container(1), podman-pod(1), podman-generate(1), podman-play(1)
+
+# HISTORY
+Decemeber 2018, Originally compiled by Brent Baude (bbaude at redhat dot com)
diff --git a/docs/podman-play.1.md b/docs/podman-play.1.md
new file mode 100644
index 000000000..c703c1455
--- /dev/null
+++ b/docs/podman-play.1.md
@@ -0,0 +1,20 @@
+% podman-play(1)
+
+## NAME
+podman\-container - play pods and containers based on a structured input file
+
+## SYNOPSIS
+**podman play** *subcommand*
+
+## DESCRIPTION
+The play command will recreate pods and containers based on the input from a structured (like YAML)
+file input. Containers will be automatically started.
+
+## COMMANDS
+
+| Command | Man Page | Description |
+| ------- | --------------------------------------------------- | ---------------------------------------------------------------------------- |
+| kube | [podman-play-kube(1)](podman-play-kube.1.md) | Recreate pods and containers based on Kubernetes YAML.
+
+## SEE ALSO
+podman, podman-pod(1), podman-container(1), podman-generate(1), podman-play(1), podman-play-kube(1)
diff --git a/libpod/kube.go b/libpod/kube.go
index c164ca0c5..f34805e39 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -30,7 +30,10 @@ func (c *Container) GenerateForKube() (*v1.Pod, error) {
// one v1.Pod description
func (p *Pod) GenerateForKube() (*v1.Pod, []v1.ServicePort, error) {
// Generate the v1.Pod yaml description
- var servicePorts []v1.ServicePort
+ var (
+ servicePorts []v1.ServicePort
+ ports []v1.ContainerPort
+ )
allContainers, err := p.allContainers()
if err != nil {
@@ -51,13 +54,13 @@ func (p *Pod) GenerateForKube() (*v1.Pod, []v1.ServicePort, error) {
return nil, servicePorts, err
}
- ports, err := ocicniPortMappingToContainerPort(infraContainer.config.PortMappings)
+ ports, err = ocicniPortMappingToContainerPort(infraContainer.config.PortMappings)
if err != nil {
return nil, servicePorts, err
}
servicePorts = containerPortsToServicePorts(ports)
}
- pod, err := p.podWithContainers(allContainers)
+ pod, err := p.podWithContainers(allContainers, ports)
return pod, servicePorts, err
}
@@ -124,18 +127,27 @@ func containersToServicePorts(containers []v1.Container) []v1.ServicePort {
return sps
}
-func (p *Pod) podWithContainers(containers []*Container) (*v1.Pod, error) {
- var podContainers []v1.Container
+func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPort) (*v1.Pod, error) {
+ var (
+ podContainers []v1.Container
+ )
+ first := true
for _, ctr := range containers {
- result, err := containerToV1Container(ctr)
- if err != nil {
- return nil, err
- }
if !ctr.IsInfra() {
+ result, err := containerToV1Container(ctr)
+ if err != nil {
+ return nil, err
+ }
+ // We add the original port declarations from the libpod infra container
+ // to the first kubernetes container description because otherwise we loose
+ // the original container/port bindings.
+ if first && len(ports) > 0 {
+ result.Ports = ports
+ first = false
+ }
podContainers = append(podContainers, result)
}
}
-
return addContainersToPodObject(podContainers, p.Name()), nil
}
@@ -150,7 +162,7 @@ func addContainersToPodObject(containers []v1.Container, podName string) *v1.Pod
labels["app"] = removeUnderscores(podName)
om := v12.ObjectMeta{
// The name of the pod is container_name-libpod
- Name: fmt.Sprintf("%s-libpod", removeUnderscores(podName)),
+ Name: fmt.Sprintf("%s", removeUnderscores(podName)),
Labels: labels,
// CreationTimestamp seems to be required, so adding it; in doing so, the timestamp
// will reflect time this is run (not container create time) because the conversion