Skip to content

Commit

Permalink
Merge pull request #14181 from umohnani8/kube-hostname
Browse files Browse the repository at this point in the history
Add ports and hostname correctly in kube yaml
  • Loading branch information
openshift-ci[bot] authored Jul 11, 2022
2 parents ea2c31c + 81a19a5 commit 810cbf1
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 14 deletions.
53 changes: 39 additions & 14 deletions libpod/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand All @@ -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)
Expand Down Expand Up @@ -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",
Expand All @@ -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,
Expand All @@ -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 {
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions pkg/domain/infra/abi/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
}
Expand All @@ -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)
Expand Down
103 changes: 103 additions & 0 deletions test/e2e/generate_kube_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit 810cbf1

Please sign in to comment.