summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libpod/kube.go53
-rw-r--r--pkg/domain/infra/abi/generate.go21
-rw-r--r--test/e2e/generate_kube_test.go103
3 files changed, 163 insertions, 14 deletions
diff --git a/libpod/kube.go b/libpod/kube.go
index 3cb0489b3..8c09a6bb5 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -353,6 +353,7 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po
podInitCtrs := []v1.Container{}
podAnnotations := make(map[string]string)
dnsInfo := v1.PodDNSConfig{}
+ var hostname string
// Let's sort the containers in order of created time
// This will ensure that the init containers are defined in the correct order in the kube yaml
@@ -368,6 +369,14 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po
podAnnotations[k] = TruncateKubeAnnotation(v)
}
isInit := ctr.IsInitCtr()
+ // Since hostname is only set at pod level, set the hostname to the hostname of the first container we encounter
+ if hostname == "" {
+ // Only set the hostname if it is not set to the truncated container ID, which we do by default if no
+ // hostname is specified for the container
+ if !strings.Contains(ctr.ID(), ctr.Hostname()) {
+ hostname = ctr.Hostname()
+ }
+ }
ctr, volumes, _, annotations, err := containerToV1Container(ctx, ctr)
if err != nil {
@@ -377,17 +386,21 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po
podAnnotations[define.BindMountPrefix+k] = TruncateKubeAnnotation(v)
}
// Since port bindings for the pod are handled by the
- // infra container, wipe them here.
- ctr.Ports = nil
-
- // 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.
- // Add the port configuration to the first regular container or the first
- // init container if only init containers have been created in the pod.
- if first && len(ports) > 0 && (!isInit || len(containers) == 2) {
- ctr.Ports = ports
- first = false
+ // infra container, wipe them here only if we are sharing the net namespace
+ // If the network namespace is not being shared in the pod, then containers
+ // can have their own network configurations
+ if p.SharesNet() {
+ ctr.Ports = nil
+
+ // 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.
+ // Add the port configuration to the first regular container or the first
+ // init container if only init containers have been created in the pod.
+ if first && len(ports) > 0 && (!isInit || len(containers) == 2) {
+ ctr.Ports = ports
+ first = false
+ }
}
if isInit {
podInitCtrs = append(podInitCtrs, ctr)
@@ -430,10 +443,11 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po
podContainers,
podVolumes,
&dnsInfo,
- hostNetwork), nil
+ hostNetwork,
+ hostname), nil
}
-func newPodObject(podName string, annotations map[string]string, initCtrs, containers []v1.Container, volumes []v1.Volume, dnsOptions *v1.PodDNSConfig, hostNetwork bool) *v1.Pod {
+func newPodObject(podName string, annotations map[string]string, initCtrs, containers []v1.Container, volumes []v1.Volume, dnsOptions *v1.PodDNSConfig, hostNetwork bool, hostname string) *v1.Pod {
tm := v12.TypeMeta{
Kind: "Pod",
APIVersion: "v1",
@@ -454,6 +468,7 @@ func newPodObject(podName string, annotations map[string]string, initCtrs, conta
}
ps := v1.PodSpec{
Containers: containers,
+ Hostname: hostname,
HostNetwork: hostNetwork,
InitContainers: initCtrs,
Volumes: volumes,
@@ -479,6 +494,7 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod,
podDNS := v1.PodDNSConfig{}
kubeAnnotations := make(map[string]string)
ctrNames := make([]string, 0, len(ctrs))
+ var hostname string
for _, ctr := range ctrs {
ctrNames = append(ctrNames, removeUnderscores(ctr.Name()))
for k, v := range ctr.config.Spec.Annotations {
@@ -491,6 +507,14 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod,
}
isInit := ctr.IsInitCtr()
+ // Since hostname is only set at pod level, set the hostname to the hostname of the first container we encounter
+ if hostname == "" {
+ // Only set the hostname if it is not set to the truncated container ID, which we do by default if no
+ // hostname is specified for the container
+ if !strings.Contains(ctr.ID(), ctr.Hostname()) {
+ hostname = ctr.Hostname()
+ }
+ }
if !ctr.HostNetwork() {
hostNetwork = false
@@ -555,7 +579,8 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod,
kubeCtrs,
kubeVolumes,
&podDNS,
- hostNetwork), nil
+ hostNetwork,
+ hostname), nil
}
// containerToV1Container converts information we know about a libpod container
diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go
index 5c1047b74..31885ce54 100644
--- a/pkg/domain/infra/abi/generate.go
+++ b/pkg/domain/infra/abi/generate.go
@@ -50,6 +50,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
content [][]byte
)
+ defaultKubeNS := true
// Lookup for podman objects.
for _, nameOrID := range nameOrIDs {
// Let's assume it's a container, so get the container.
@@ -75,6 +76,17 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
return nil, err
}
} else {
+ // Get the pod config to see if the user has modified the default
+ // namespace sharing values as this might affect the pods when run
+ // in a k8s cluster
+ podConfig, err := pod.Config()
+ if err != nil {
+ return nil, err
+ }
+ if !(podConfig.UsePodIPC && podConfig.UsePodNet && podConfig.UsePodUTS) {
+ defaultKubeNS = false
+ }
+
pods = append(pods, pod)
continue
}
@@ -94,6 +106,15 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
return nil, fmt.Errorf("name or ID %q not found", nameOrID)
}
+ if !defaultKubeNS {
+ warning := `
+# NOTE: The namespace sharing for a pod has been modified by the user and is not the same as the
+# default settings for kubernetes. This can lead to unexpected behavior when running the generated
+# kube yaml in a kubernetes cluster.
+`
+ content = append(content, []byte(warning))
+ }
+
// Generate kube persistent volume claims from volumes.
if len(vols) >= 1 {
pvs, err := getKubePVCs(vols)
diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go
index 2ca774a03..845aa60ce 100644
--- a/test/e2e/generate_kube_test.go
+++ b/test/e2e/generate_kube_test.go
@@ -328,6 +328,109 @@ var _ = Describe("Podman generate kube", func() {
Expect(pod.Spec.HostAliases[1]).To(HaveField("IP", testIP))
})
+ It("podman generate kube with network sharing", func() {
+ // Expect error with default sharing options as Net namespace is shared
+ podName := "testPod"
+ podSession := podmanTest.Podman([]string{"pod", "create", "--name", podName})
+ podSession.WaitWithDefaultTimeout()
+ Expect(podSession).Should(Exit(0))
+
+ ctrSession := podmanTest.Podman([]string{"create", "--name", "testCtr", "--pod", podName, "-p", "9000:8000", ALPINE, "top"})
+ ctrSession.WaitWithDefaultTimeout()
+ Expect(ctrSession).Should(Exit(125))
+
+ // Ports without Net sharing should work with ports being set for each container in the generated kube yaml
+ podName = "testNet"
+ podSession = podmanTest.Podman([]string{"pod", "create", "--name", podName, "--share", "ipc"})
+ podSession.WaitWithDefaultTimeout()
+ Expect(podSession).Should(Exit(0))
+
+ ctr1Name := "ctr1"
+ ctr1Session := podmanTest.Podman([]string{"create", "--name", ctr1Name, "--pod", podName, "-p", "9000:8000", ALPINE, "top"})
+ ctr1Session.WaitWithDefaultTimeout()
+ Expect(ctr1Session).Should(Exit(0))
+
+ ctr2Name := "ctr2"
+ ctr2Session := podmanTest.Podman([]string{"create", "--name", ctr2Name, "--pod", podName, "-p", "6000:5000", ALPINE, "top"})
+ ctr2Session.WaitWithDefaultTimeout()
+ Expect(ctr2Session).Should(Exit(0))
+
+ kube := podmanTest.Podman([]string{"generate", "kube", podName})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube).Should(Exit(0))
+
+ pod := new(v1.Pod)
+ err := yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+ Expect(pod.Spec.Containers).To(HaveLen(2))
+ Expect(pod.Spec.Containers[0].Ports[0].ContainerPort).To(Equal(int32(8000)))
+ Expect(pod.Spec.Containers[1].Ports[0].ContainerPort).To(Equal(int32(5000)))
+ Expect(pod.Spec.Containers[0].Ports[0].HostPort).To(Equal(int32(9000)))
+ Expect(pod.Spec.Containers[1].Ports[0].HostPort).To(Equal(int32(6000)))
+ })
+
+ It("podman generate kube with and without hostname", func() {
+ // Expect error with default sharing options as UTS namespace is shared
+ podName := "testPod"
+ podSession := podmanTest.Podman([]string{"pod", "create", "--name", podName})
+ podSession.WaitWithDefaultTimeout()
+ Expect(podSession).Should(Exit(0))
+
+ ctrSession := podmanTest.Podman([]string{"create", "--name", "testCtr", "--pod", podName, "--hostname", "test-hostname", ALPINE, "top"})
+ ctrSession.WaitWithDefaultTimeout()
+ Expect(ctrSession).Should(Exit(125))
+
+ // Hostname without uts sharing should work, but generated kube yaml will have pod hostname
+ // set to the hostname of the first container
+ podName = "testHostname"
+ podSession = podmanTest.Podman([]string{"pod", "create", "--name", podName, "--share", "ipc"})
+ podSession.WaitWithDefaultTimeout()
+ Expect(podSession).Should(Exit(0))
+
+ ctr1Name := "ctr1"
+ ctr1HostName := "ctr1-hostname"
+ ctr1Session := podmanTest.Podman([]string{"create", "--name", ctr1Name, "--pod", podName, "--hostname", ctr1HostName, ALPINE, "top"})
+ ctr1Session.WaitWithDefaultTimeout()
+ Expect(ctr1Session).Should(Exit(0))
+
+ ctr2Name := "ctr2"
+ ctr2Session := podmanTest.Podman([]string{"create", "--name", ctr2Name, "--pod", podName, ALPINE, "top"})
+ ctr2Session.WaitWithDefaultTimeout()
+ Expect(ctr2Session).Should(Exit(0))
+
+ kube := podmanTest.Podman([]string{"generate", "kube", podName})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube).Should(Exit(0))
+
+ pod := new(v1.Pod)
+ err := yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+ Expect(pod.Spec.Containers).To(HaveLen(2))
+ Expect(pod.Spec.Hostname).To(Equal(ctr1HostName))
+
+ // No hostname
+
+ podName = "testNoHostname"
+ podSession = podmanTest.Podman([]string{"pod", "create", "--name", podName, "--share", "ipc"})
+ podSession.WaitWithDefaultTimeout()
+ Expect(podSession).Should(Exit(0))
+
+ ctr3Name := "ctr3"
+ ctr3Session := podmanTest.Podman([]string{"create", "--name", ctr3Name, "--pod", podName, ALPINE, "top"})
+ ctr3Session.WaitWithDefaultTimeout()
+ Expect(ctr3Session).Should(Exit(0))
+
+ kube = podmanTest.Podman([]string{"generate", "kube", podName})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube).Should(Exit(0))
+
+ pod = new(v1.Pod)
+ err = yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+ Expect(pod.Spec.Containers).To(HaveLen(1))
+ Expect(pod.Spec.Hostname).To(BeEmpty())
+ })
+
It("podman generate service kube on pod", func() {
session := podmanTest.Podman([]string{"create", "--pod", "new:test-pod", "-p", "4000:4000/udp", ALPINE, "ls"})
session.WaitWithDefaultTimeout()