Skip to content

Commit 810cbf1

Browse files
Merge pull request #14181 from umohnani8/kube-hostname
Add ports and hostname correctly in kube yaml
2 parents ea2c31c + 81a19a5 commit 810cbf1

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
@@ -50,6 +50,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
5050
content [][]byte
5151
)
5252

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

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