Skip to content

Commit 81a19a5

Browse files
committed
Add ports and hostname correctly in kube yaml
If a pod is created without net sharing, allow adding separate ports for each container to the kube yaml and also set the pod level hostname correctly if the uts namespace is not being shared. Add a warning if the default namespace sharing options have been modified by the user. Signed-off-by: Urvashi Mohnani <[email protected]>
1 parent 49df3cc commit 81a19a5

File tree

3 files changed

+163
-14
lines changed

3 files changed

+163
-14
lines changed

libpod/kube.go

+39-14
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po
353353
podInitCtrs := []v1.Container{}
354354
podAnnotations := make(map[string]string)
355355
dnsInfo := v1.PodDNSConfig{}
356+
var hostname string
356357

357358
// Let's sort the containers in order of created time
358359
// 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
368369
podAnnotations[k] = TruncateKubeAnnotation(v)
369370
}
370371
isInit := ctr.IsInitCtr()
372+
// Since hostname is only set at pod level, set the hostname to the hostname of the first container we encounter
373+
if hostname == "" {
374+
// Only set the hostname if it is not set to the truncated container ID, which we do by default if no
375+
// hostname is specified for the container
376+
if !strings.Contains(ctr.ID(), ctr.Hostname()) {
377+
hostname = ctr.Hostname()
378+
}
379+
}
371380

372381
ctr, volumes, _, annotations, err := containerToV1Container(ctx, ctr)
373382
if err != nil {
@@ -377,17 +386,21 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po
377386
podAnnotations[define.BindMountPrefix+k] = TruncateKubeAnnotation(v)
378387
}
379388
// Since port bindings for the pod are handled by the
380-
// infra container, wipe them here.
381-
ctr.Ports = nil
382-
383-
// We add the original port declarations from the libpod infra container
384-
// to the first kubernetes container description because otherwise we loose
385-
// the original container/port bindings.
386-
// Add the port configuration to the first regular container or the first
387-
// init container if only init containers have been created in the pod.
388-
if first && len(ports) > 0 && (!isInit || len(containers) == 2) {
389-
ctr.Ports = ports
390-
first = false
389+
// infra container, wipe them here only if we are sharing the net namespace
390+
// If the network namespace is not being shared in the pod, then containers
391+
// can have their own network configurations
392+
if p.SharesNet() {
393+
ctr.Ports = nil
394+
395+
// We add the original port declarations from the libpod infra container
396+
// to the first kubernetes container description because otherwise we loose
397+
// the original container/port bindings.
398+
// Add the port configuration to the first regular container or the first
399+
// init container if only init containers have been created in the pod.
400+
if first && len(ports) > 0 && (!isInit || len(containers) == 2) {
401+
ctr.Ports = ports
402+
first = false
403+
}
391404
}
392405
if isInit {
393406
podInitCtrs = append(podInitCtrs, ctr)
@@ -430,10 +443,11 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po
430443
podContainers,
431444
podVolumes,
432445
&dnsInfo,
433-
hostNetwork), nil
446+
hostNetwork,
447+
hostname), nil
434448
}
435449

436-
func newPodObject(podName string, annotations map[string]string, initCtrs, containers []v1.Container, volumes []v1.Volume, dnsOptions *v1.PodDNSConfig, hostNetwork bool) *v1.Pod {
450+
func newPodObject(podName string, annotations map[string]string, initCtrs, containers []v1.Container, volumes []v1.Volume, dnsOptions *v1.PodDNSConfig, hostNetwork bool, hostname string) *v1.Pod {
437451
tm := v12.TypeMeta{
438452
Kind: "Pod",
439453
APIVersion: "v1",
@@ -454,6 +468,7 @@ func newPodObject(podName string, annotations map[string]string, initCtrs, conta
454468
}
455469
ps := v1.PodSpec{
456470
Containers: containers,
471+
Hostname: hostname,
457472
HostNetwork: hostNetwork,
458473
InitContainers: initCtrs,
459474
Volumes: volumes,
@@ -479,6 +494,7 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod,
479494
podDNS := v1.PodDNSConfig{}
480495
kubeAnnotations := make(map[string]string)
481496
ctrNames := make([]string, 0, len(ctrs))
497+
var hostname string
482498
for _, ctr := range ctrs {
483499
ctrNames = append(ctrNames, removeUnderscores(ctr.Name()))
484500
for k, v := range ctr.config.Spec.Annotations {
@@ -491,6 +507,14 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod,
491507
}
492508

493509
isInit := ctr.IsInitCtr()
510+
// Since hostname is only set at pod level, set the hostname to the hostname of the first container we encounter
511+
if hostname == "" {
512+
// Only set the hostname if it is not set to the truncated container ID, which we do by default if no
513+
// hostname is specified for the container
514+
if !strings.Contains(ctr.ID(), ctr.Hostname()) {
515+
hostname = ctr.Hostname()
516+
}
517+
}
494518

495519
if !ctr.HostNetwork() {
496520
hostNetwork = false
@@ -555,7 +579,8 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod,
555579
kubeCtrs,
556580
kubeVolumes,
557581
&podDNS,
558-
hostNetwork), nil
582+
hostNetwork,
583+
hostname), nil
559584
}
560585

561586
// containerToV1Container converts information we know about a libpod container

pkg/domain/infra/abi/generate.go

+21
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
5151
content [][]byte
5252
)
5353

54+
defaultKubeNS := true
5455
// Lookup for podman objects.
5556
for _, nameOrID := range nameOrIDs {
5657
// Let's assume it's a container, so get the container.
@@ -76,6 +77,17 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
7677
return nil, err
7778
}
7879
} else {
80+
// Get the pod config to see if the user has modified the default
81+
// namespace sharing values as this might affect the pods when run
82+
// in a k8s cluster
83+
podConfig, err := pod.Config()
84+
if err != nil {
85+
return nil, err
86+
}
87+
if !(podConfig.UsePodIPC && podConfig.UsePodNet && podConfig.UsePodUTS) {
88+
defaultKubeNS = false
89+
}
90+
7991
pods = append(pods, pod)
8092
continue
8193
}
@@ -95,6 +107,15 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
95107
return nil, errors.Errorf("Name or ID %q not found", nameOrID)
96108
}
97109

110+
if !defaultKubeNS {
111+
warning := `
112+
# NOTE: The namespace sharing for a pod has been modified by the user and is not the same as the
113+
# default settings for kubernetes. This can lead to unexpected behavior when running the generated
114+
# kube yaml in a kubernetes cluster.
115+
`
116+
content = append(content, []byte(warning))
117+
}
118+
98119
// Generate kube persistent volume claims from volumes.
99120
if len(vols) >= 1 {
100121
pvs, err := getKubePVCs(vols)

test/e2e/generate_kube_test.go

+103
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,109 @@ var _ = Describe("Podman generate kube", func() {
328328
Expect(pod.Spec.HostAliases[1]).To(HaveField("IP", testIP))
329329
})
330330

331+
It("podman generate kube with network sharing", func() {
332+
// Expect error with default sharing options as Net namespace is shared
333+
podName := "testPod"
334+
podSession := podmanTest.Podman([]string{"pod", "create", "--name", podName})
335+
podSession.WaitWithDefaultTimeout()
336+
Expect(podSession).Should(Exit(0))
337+
338+
ctrSession := podmanTest.Podman([]string{"create", "--name", "testCtr", "--pod", podName, "-p", "9000:8000", ALPINE, "top"})
339+
ctrSession.WaitWithDefaultTimeout()
340+
Expect(ctrSession).Should(Exit(125))
341+
342+
// Ports without Net sharing should work with ports being set for each container in the generated kube yaml
343+
podName = "testNet"
344+
podSession = podmanTest.Podman([]string{"pod", "create", "--name", podName, "--share", "ipc"})
345+
podSession.WaitWithDefaultTimeout()
346+
Expect(podSession).Should(Exit(0))
347+
348+
ctr1Name := "ctr1"
349+
ctr1Session := podmanTest.Podman([]string{"create", "--name", ctr1Name, "--pod", podName, "-p", "9000:8000", ALPINE, "top"})
350+
ctr1Session.WaitWithDefaultTimeout()
351+
Expect(ctr1Session).Should(Exit(0))
352+
353+
ctr2Name := "ctr2"
354+
ctr2Session := podmanTest.Podman([]string{"create", "--name", ctr2Name, "--pod", podName, "-p", "6000:5000", ALPINE, "top"})
355+
ctr2Session.WaitWithDefaultTimeout()
356+
Expect(ctr2Session).Should(Exit(0))
357+
358+
kube := podmanTest.Podman([]string{"generate", "kube", podName})
359+
kube.WaitWithDefaultTimeout()
360+
Expect(kube).Should(Exit(0))
361+
362+
pod := new(v1.Pod)
363+
err := yaml.Unmarshal(kube.Out.Contents(), pod)
364+
Expect(err).To(BeNil())
365+
Expect(pod.Spec.Containers).To(HaveLen(2))
366+
Expect(pod.Spec.Containers[0].Ports[0].ContainerPort).To(Equal(int32(8000)))
367+
Expect(pod.Spec.Containers[1].Ports[0].ContainerPort).To(Equal(int32(5000)))
368+
Expect(pod.Spec.Containers[0].Ports[0].HostPort).To(Equal(int32(9000)))
369+
Expect(pod.Spec.Containers[1].Ports[0].HostPort).To(Equal(int32(6000)))
370+
})
371+
372+
It("podman generate kube with and without hostname", func() {
373+
// Expect error with default sharing options as UTS namespace is shared
374+
podName := "testPod"
375+
podSession := podmanTest.Podman([]string{"pod", "create", "--name", podName})
376+
podSession.WaitWithDefaultTimeout()
377+
Expect(podSession).Should(Exit(0))
378+
379+
ctrSession := podmanTest.Podman([]string{"create", "--name", "testCtr", "--pod", podName, "--hostname", "test-hostname", ALPINE, "top"})
380+
ctrSession.WaitWithDefaultTimeout()
381+
Expect(ctrSession).Should(Exit(125))
382+
383+
// Hostname without uts sharing should work, but generated kube yaml will have pod hostname
384+
// set to the hostname of the first container
385+
podName = "testHostname"
386+
podSession = podmanTest.Podman([]string{"pod", "create", "--name", podName, "--share", "ipc"})
387+
podSession.WaitWithDefaultTimeout()
388+
Expect(podSession).Should(Exit(0))
389+
390+
ctr1Name := "ctr1"
391+
ctr1HostName := "ctr1-hostname"
392+
ctr1Session := podmanTest.Podman([]string{"create", "--name", ctr1Name, "--pod", podName, "--hostname", ctr1HostName, ALPINE, "top"})
393+
ctr1Session.WaitWithDefaultTimeout()
394+
Expect(ctr1Session).Should(Exit(0))
395+
396+
ctr2Name := "ctr2"
397+
ctr2Session := podmanTest.Podman([]string{"create", "--name", ctr2Name, "--pod", podName, ALPINE, "top"})
398+
ctr2Session.WaitWithDefaultTimeout()
399+
Expect(ctr2Session).Should(Exit(0))
400+
401+
kube := podmanTest.Podman([]string{"generate", "kube", podName})
402+
kube.WaitWithDefaultTimeout()
403+
Expect(kube).Should(Exit(0))
404+
405+
pod := new(v1.Pod)
406+
err := yaml.Unmarshal(kube.Out.Contents(), pod)
407+
Expect(err).To(BeNil())
408+
Expect(pod.Spec.Containers).To(HaveLen(2))
409+
Expect(pod.Spec.Hostname).To(Equal(ctr1HostName))
410+
411+
// No hostname
412+
413+
podName = "testNoHostname"
414+
podSession = podmanTest.Podman([]string{"pod", "create", "--name", podName, "--share", "ipc"})
415+
podSession.WaitWithDefaultTimeout()
416+
Expect(podSession).Should(Exit(0))
417+
418+
ctr3Name := "ctr3"
419+
ctr3Session := podmanTest.Podman([]string{"create", "--name", ctr3Name, "--pod", podName, ALPINE, "top"})
420+
ctr3Session.WaitWithDefaultTimeout()
421+
Expect(ctr3Session).Should(Exit(0))
422+
423+
kube = podmanTest.Podman([]string{"generate", "kube", podName})
424+
kube.WaitWithDefaultTimeout()
425+
Expect(kube).Should(Exit(0))
426+
427+
pod = new(v1.Pod)
428+
err = yaml.Unmarshal(kube.Out.Contents(), pod)
429+
Expect(err).To(BeNil())
430+
Expect(pod.Spec.Containers).To(HaveLen(1))
431+
Expect(pod.Spec.Hostname).To(BeEmpty())
432+
})
433+
331434
It("podman generate service kube on pod", func() {
332435
session := podmanTest.Podman([]string{"create", "--pod", "new:test-pod", "-p", "4000:4000/udp", ALPINE, "ls"})
333436
session.WaitWithDefaultTimeout()

0 commit comments

Comments
 (0)