mirror of
https://github.com/containers/podman.git
synced 2025-06-27 21:50:18 +08:00
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 <umohnani@redhat.com>
This commit is contained in:
@ -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,7 +386,10 @@ 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.
|
||||
// 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
|
||||
@ -389,6 +401,7 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po
|
||||
ctr.Ports = ports
|
||||
first = false
|
||||
}
|
||||
}
|
||||
if isInit {
|
||||
podInitCtrs = append(podInitCtrs, ctr)
|
||||
continue
|
||||
@ -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
|
||||
|
@ -51,6 +51,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.
|
||||
@ -76,6 +77,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
|
||||
}
|
||||
@ -95,6 +107,15 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
|
||||
return nil, errors.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)
|
||||
|
@ -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()
|
||||
|
Reference in New Issue
Block a user