mirror of https://github.com/containers/podman.git
Honor custom DNS in play|generate kube
when creating kubernetes yaml from containers and pods, we should honor any custom dns settings the user provided. in the case of generate kube, these would be provided by --dns, --dns-search, and --dns-opt. if multiple containers are involved in the generate, the options will be cumulative and unique with the exception of dns-opt. when replaying a kube file that has kubernetes dns information, we now also add that information to the pod creation. the options for dnspolicy is not enabled as there seemed to be no direct correlation between kubernetes and podman. Fixes: #9132 Signed-off-by: baude <bbaude@redhat.com>
This commit is contained in:
parent
2ee034c1e6
commit
ca0dd76bf3
112
libpod/kube.go
112
libpod/kube.go
|
@ -171,9 +171,10 @@ func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPor
|
||||||
deDupPodVolumes := make(map[string]*v1.Volume)
|
deDupPodVolumes := make(map[string]*v1.Volume)
|
||||||
first := true
|
first := true
|
||||||
podContainers := make([]v1.Container, 0, len(containers))
|
podContainers := make([]v1.Container, 0, len(containers))
|
||||||
|
dnsInfo := v1.PodDNSConfig{}
|
||||||
for _, ctr := range containers {
|
for _, ctr := range containers {
|
||||||
if !ctr.IsInfra() {
|
if !ctr.IsInfra() {
|
||||||
ctr, volumes, err := containerToV1Container(ctr)
|
ctr, volumes, _, err := containerToV1Container(ctr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -196,6 +197,22 @@ func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPor
|
||||||
vol := vol
|
vol := vol
|
||||||
deDupPodVolumes[vol.Name] = &vol
|
deDupPodVolumes[vol.Name] = &vol
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
_, _, infraDNS, err := containerToV1Container(ctr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if infraDNS != nil {
|
||||||
|
if servers := infraDNS.Nameservers; len(servers) > 0 {
|
||||||
|
dnsInfo.Nameservers = servers
|
||||||
|
}
|
||||||
|
if searches := infraDNS.Searches; len(searches) > 0 {
|
||||||
|
dnsInfo.Searches = searches
|
||||||
|
}
|
||||||
|
if options := infraDNS.Options; len(options) > 0 {
|
||||||
|
dnsInfo.Options = options
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
podVolumes := make([]v1.Volume, 0, len(deDupPodVolumes))
|
podVolumes := make([]v1.Volume, 0, len(deDupPodVolumes))
|
||||||
|
@ -203,10 +220,10 @@ func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPor
|
||||||
podVolumes = append(podVolumes, *vol)
|
podVolumes = append(podVolumes, *vol)
|
||||||
}
|
}
|
||||||
|
|
||||||
return addContainersAndVolumesToPodObject(podContainers, podVolumes, p.Name()), nil
|
return addContainersAndVolumesToPodObject(podContainers, podVolumes, p.Name(), &dnsInfo), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addContainersAndVolumesToPodObject(containers []v1.Container, volumes []v1.Volume, podName string) *v1.Pod {
|
func addContainersAndVolumesToPodObject(containers []v1.Container, volumes []v1.Volume, podName string, dnsOptions *v1.PodDNSConfig) *v1.Pod {
|
||||||
tm := v12.TypeMeta{
|
tm := v12.TypeMeta{
|
||||||
Kind: "Pod",
|
Kind: "Pod",
|
||||||
APIVersion: "v1",
|
APIVersion: "v1",
|
||||||
|
@ -228,6 +245,9 @@ func addContainersAndVolumesToPodObject(containers []v1.Container, volumes []v1.
|
||||||
Containers: containers,
|
Containers: containers,
|
||||||
Volumes: volumes,
|
Volumes: volumes,
|
||||||
}
|
}
|
||||||
|
if dnsOptions != nil {
|
||||||
|
ps.DNSConfig = dnsOptions
|
||||||
|
}
|
||||||
p := v1.Pod{
|
p := v1.Pod{
|
||||||
TypeMeta: tm,
|
TypeMeta: tm,
|
||||||
ObjectMeta: om,
|
ObjectMeta: om,
|
||||||
|
@ -241,32 +261,65 @@ func addContainersAndVolumesToPodObject(containers []v1.Container, volumes []v1.
|
||||||
func simplePodWithV1Containers(ctrs []*Container) (*v1.Pod, error) {
|
func simplePodWithV1Containers(ctrs []*Container) (*v1.Pod, error) {
|
||||||
kubeCtrs := make([]v1.Container, 0, len(ctrs))
|
kubeCtrs := make([]v1.Container, 0, len(ctrs))
|
||||||
kubeVolumes := make([]v1.Volume, 0)
|
kubeVolumes := make([]v1.Volume, 0)
|
||||||
|
podDNS := v1.PodDNSConfig{}
|
||||||
for _, ctr := range ctrs {
|
for _, ctr := range ctrs {
|
||||||
kubeCtr, kubeVols, err := containerToV1Container(ctr)
|
kubeCtr, kubeVols, ctrDNS, err := containerToV1Container(ctr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
kubeCtrs = append(kubeCtrs, kubeCtr)
|
kubeCtrs = append(kubeCtrs, kubeCtr)
|
||||||
kubeVolumes = append(kubeVolumes, kubeVols...)
|
kubeVolumes = append(kubeVolumes, kubeVols...)
|
||||||
}
|
|
||||||
return addContainersAndVolumesToPodObject(kubeCtrs, kubeVolumes, strings.ReplaceAll(ctrs[0].Name(), "_", "")), nil
|
|
||||||
|
|
||||||
|
// Combine DNS information in sum'd structure
|
||||||
|
if ctrDNS != nil {
|
||||||
|
// nameservers
|
||||||
|
if servers := ctrDNS.Nameservers; servers != nil {
|
||||||
|
if podDNS.Nameservers == nil {
|
||||||
|
podDNS.Nameservers = make([]string, 0)
|
||||||
|
}
|
||||||
|
for _, s := range servers {
|
||||||
|
if !util.StringInSlice(s, podDNS.Nameservers) { // only append if it does not exist
|
||||||
|
podDNS.Nameservers = append(podDNS.Nameservers, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// search domains
|
||||||
|
if domains := ctrDNS.Searches; domains != nil {
|
||||||
|
if podDNS.Searches == nil {
|
||||||
|
podDNS.Searches = make([]string, 0)
|
||||||
|
}
|
||||||
|
for _, d := range domains {
|
||||||
|
if !util.StringInSlice(d, podDNS.Searches) { // only append if it does not exist
|
||||||
|
podDNS.Searches = append(podDNS.Searches, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// dns options
|
||||||
|
if options := ctrDNS.Options; options != nil {
|
||||||
|
if podDNS.Options == nil {
|
||||||
|
podDNS.Options = make([]v1.PodDNSConfigOption, 0)
|
||||||
|
}
|
||||||
|
podDNS.Options = append(podDNS.Options, options...)
|
||||||
|
}
|
||||||
|
} // end if ctrDNS
|
||||||
|
}
|
||||||
|
return addContainersAndVolumesToPodObject(kubeCtrs, kubeVolumes, strings.ReplaceAll(ctrs[0].Name(), "_", ""), &podDNS), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// containerToV1Container converts information we know about a libpod container
|
// containerToV1Container converts information we know about a libpod container
|
||||||
// to a V1.Container specification.
|
// to a V1.Container specification.
|
||||||
func containerToV1Container(c *Container) (v1.Container, []v1.Volume, error) {
|
func containerToV1Container(c *Container) (v1.Container, []v1.Volume, *v1.PodDNSConfig, error) {
|
||||||
kubeContainer := v1.Container{}
|
kubeContainer := v1.Container{}
|
||||||
kubeVolumes := []v1.Volume{}
|
kubeVolumes := []v1.Volume{}
|
||||||
kubeSec, err := generateKubeSecurityContext(c)
|
kubeSec, err := generateKubeSecurityContext(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return kubeContainer, kubeVolumes, err
|
return kubeContainer, kubeVolumes, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.config.Spec.Linux.Devices) > 0 {
|
if len(c.config.Spec.Linux.Devices) > 0 {
|
||||||
// TODO Enable when we can support devices and their names
|
// TODO Enable when we can support devices and their names
|
||||||
kubeContainer.VolumeDevices = generateKubeVolumeDeviceFromLinuxDevice(c.Spec().Linux.Devices)
|
kubeContainer.VolumeDevices = generateKubeVolumeDeviceFromLinuxDevice(c.Spec().Linux.Devices)
|
||||||
return kubeContainer, kubeVolumes, errors.Wrapf(define.ErrNotImplemented, "linux devices")
|
return kubeContainer, kubeVolumes, nil, errors.Wrapf(define.ErrNotImplemented, "linux devices")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.config.UserVolumes) > 0 {
|
if len(c.config.UserVolumes) > 0 {
|
||||||
|
@ -274,7 +327,7 @@ func containerToV1Container(c *Container) (v1.Container, []v1.Volume, error) {
|
||||||
// Volume names need to be coordinated "globally" in the kube files.
|
// Volume names need to be coordinated "globally" in the kube files.
|
||||||
volumeMounts, volumes, err := libpodMountsToKubeVolumeMounts(c)
|
volumeMounts, volumes, err := libpodMountsToKubeVolumeMounts(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return kubeContainer, kubeVolumes, err
|
return kubeContainer, kubeVolumes, nil, err
|
||||||
}
|
}
|
||||||
kubeContainer.VolumeMounts = volumeMounts
|
kubeContainer.VolumeMounts = volumeMounts
|
||||||
kubeVolumes = append(kubeVolumes, volumes...)
|
kubeVolumes = append(kubeVolumes, volumes...)
|
||||||
|
@ -282,16 +335,16 @@ func containerToV1Container(c *Container) (v1.Container, []v1.Volume, error) {
|
||||||
|
|
||||||
envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env)
|
envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return kubeContainer, kubeVolumes, err
|
return kubeContainer, kubeVolumes, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
portmappings, err := c.PortMappings()
|
portmappings, err := c.PortMappings()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return kubeContainer, kubeVolumes, err
|
return kubeContainer, kubeVolumes, nil, err
|
||||||
}
|
}
|
||||||
ports, err := ocicniPortMappingToContainerPort(portmappings)
|
ports, err := ocicniPortMappingToContainerPort(portmappings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return kubeContainer, kubeVolumes, err
|
return kubeContainer, kubeVolumes, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
containerCommands := c.Command()
|
containerCommands := c.Command()
|
||||||
|
@ -355,7 +408,38 @@ func containerToV1Container(c *Container) (v1.Container, []v1.Volume, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return kubeContainer, kubeVolumes, nil
|
// Obtain the DNS entries from the container
|
||||||
|
dns := v1.PodDNSConfig{}
|
||||||
|
|
||||||
|
// DNS servers
|
||||||
|
if servers := c.config.DNSServer; len(servers) > 0 {
|
||||||
|
dnsServers := make([]string, 0)
|
||||||
|
for _, server := range servers {
|
||||||
|
dnsServers = append(dnsServers, server.String())
|
||||||
|
}
|
||||||
|
dns.Nameservers = dnsServers
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNS search domains
|
||||||
|
if searches := c.config.DNSSearch; len(searches) > 0 {
|
||||||
|
dns.Searches = searches
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNS options
|
||||||
|
if options := c.config.DNSOption; len(options) > 0 {
|
||||||
|
dnsOptions := make([]v1.PodDNSConfigOption, 0)
|
||||||
|
for _, option := range options {
|
||||||
|
// the option can be "k:v" or just "k", no delimiter is required
|
||||||
|
opts := strings.SplitN(option, ":", 2)
|
||||||
|
dnsOpt := v1.PodDNSConfigOption{
|
||||||
|
Name: opts[0],
|
||||||
|
Value: &opts[1],
|
||||||
|
}
|
||||||
|
dnsOptions = append(dnsOptions, dnsOpt)
|
||||||
|
}
|
||||||
|
dns.Options = dnsOptions
|
||||||
|
}
|
||||||
|
return kubeContainer, kubeVolumes, &dns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ocicniPortMappingToContainerPort takes an ocicni portmapping and converts
|
// ocicniPortMappingToContainerPort takes an ocicni portmapping and converts
|
||||||
|
|
|
@ -3,6 +3,7 @@ package kube
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/parse"
|
"github.com/containers/common/pkg/parse"
|
||||||
|
@ -44,6 +45,31 @@ func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec)
|
||||||
podPorts := getPodPorts(podYAML.Spec.Containers)
|
podPorts := getPodPorts(podYAML.Spec.Containers)
|
||||||
p.PortMappings = podPorts
|
p.PortMappings = podPorts
|
||||||
|
|
||||||
|
if dnsConfig := podYAML.Spec.DNSConfig; dnsConfig != nil {
|
||||||
|
// name servers
|
||||||
|
if dnsServers := dnsConfig.Nameservers; len(dnsServers) > 0 {
|
||||||
|
servers := make([]net.IP, 0)
|
||||||
|
for _, server := range dnsServers {
|
||||||
|
servers = append(servers, net.ParseIP(server))
|
||||||
|
}
|
||||||
|
p.DNSServer = servers
|
||||||
|
}
|
||||||
|
// search domans
|
||||||
|
if domains := dnsConfig.Searches; len(domains) > 0 {
|
||||||
|
p.DNSSearch = domains
|
||||||
|
}
|
||||||
|
// dns options
|
||||||
|
if options := dnsConfig.Options; len(options) > 0 {
|
||||||
|
dnsOptions := make([]string, 0)
|
||||||
|
for _, opts := range options {
|
||||||
|
d := opts.Name
|
||||||
|
if opts.Value != nil {
|
||||||
|
d += ":" + *opts.Value
|
||||||
|
}
|
||||||
|
dnsOptions = append(dnsOptions, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -540,4 +540,67 @@ var _ = Describe("Podman generate kube", func() {
|
||||||
kube.WaitWithDefaultTimeout()
|
kube.WaitWithDefaultTimeout()
|
||||||
Expect(kube.ExitCode()).ToNot(Equal(0))
|
Expect(kube.ExitCode()).ToNot(Equal(0))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman generate kube on a container with dns options", func() {
|
||||||
|
top := podmanTest.Podman([]string{"run", "-dt", "--name", "top", "--dns", "8.8.8.8", "--dns-search", "foobar.com", "--dns-opt", "color:blue", ALPINE, "top"})
|
||||||
|
top.WaitWithDefaultTimeout()
|
||||||
|
Expect(top.ExitCode()).To(BeZero())
|
||||||
|
|
||||||
|
kube := podmanTest.Podman([]string{"generate", "kube", "top"})
|
||||||
|
kube.WaitWithDefaultTimeout()
|
||||||
|
Expect(kube.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
pod := new(v1.Pod)
|
||||||
|
err := yaml.Unmarshal(kube.Out.Contents(), pod)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
|
Expect(StringInSlice("8.8.8.8", pod.Spec.DNSConfig.Nameservers)).To(BeTrue())
|
||||||
|
Expect(StringInSlice("foobar.com", pod.Spec.DNSConfig.Searches)).To(BeTrue())
|
||||||
|
Expect(len(pod.Spec.DNSConfig.Options)).To(BeNumerically(">", 0))
|
||||||
|
Expect(pod.Spec.DNSConfig.Options[0].Name).To(Equal("color"))
|
||||||
|
Expect(*pod.Spec.DNSConfig.Options[0].Value).To(Equal("blue"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman generate kube multiple contianer dns servers and options are cumulative", func() {
|
||||||
|
top1 := podmanTest.Podman([]string{"run", "-dt", "--name", "top1", "--dns", "8.8.8.8", "--dns-search", "foobar.com", ALPINE, "top"})
|
||||||
|
top1.WaitWithDefaultTimeout()
|
||||||
|
Expect(top1.ExitCode()).To(BeZero())
|
||||||
|
|
||||||
|
top2 := podmanTest.Podman([]string{"run", "-dt", "--name", "top2", "--dns", "8.7.7.7", "--dns-search", "homer.com", ALPINE, "top"})
|
||||||
|
top2.WaitWithDefaultTimeout()
|
||||||
|
Expect(top2.ExitCode()).To(BeZero())
|
||||||
|
|
||||||
|
kube := podmanTest.Podman([]string{"generate", "kube", "top1", "top2"})
|
||||||
|
kube.WaitWithDefaultTimeout()
|
||||||
|
Expect(kube.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
pod := new(v1.Pod)
|
||||||
|
err := yaml.Unmarshal(kube.Out.Contents(), pod)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
|
Expect(StringInSlice("8.8.8.8", pod.Spec.DNSConfig.Nameservers)).To(BeTrue())
|
||||||
|
Expect(StringInSlice("8.7.7.7", pod.Spec.DNSConfig.Nameservers)).To(BeTrue())
|
||||||
|
Expect(StringInSlice("foobar.com", pod.Spec.DNSConfig.Searches)).To(BeTrue())
|
||||||
|
Expect(StringInSlice("homer.com", pod.Spec.DNSConfig.Searches)).To(BeTrue())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman generate kube on a pod with dns options", func() {
|
||||||
|
top := podmanTest.Podman([]string{"run", "--pod", "new:pod1", "-dt", "--name", "top", "--dns", "8.8.8.8", "--dns-search", "foobar.com", "--dns-opt", "color:blue", ALPINE, "top"})
|
||||||
|
top.WaitWithDefaultTimeout()
|
||||||
|
Expect(top.ExitCode()).To(BeZero())
|
||||||
|
|
||||||
|
kube := podmanTest.Podman([]string{"generate", "kube", "pod1"})
|
||||||
|
kube.WaitWithDefaultTimeout()
|
||||||
|
Expect(kube.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
pod := new(v1.Pod)
|
||||||
|
err := yaml.Unmarshal(kube.Out.Contents(), pod)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
|
Expect(StringInSlice("8.8.8.8", pod.Spec.DNSConfig.Nameservers)).To(BeTrue())
|
||||||
|
Expect(StringInSlice("foobar.com", pod.Spec.DNSConfig.Searches)).To(BeTrue())
|
||||||
|
Expect(len(pod.Spec.DNSConfig.Options)).To(BeNumerically(">", 0))
|
||||||
|
Expect(pod.Spec.DNSConfig.Options[0].Name).To(Equal("color"))
|
||||||
|
Expect(*pod.Spec.DNSConfig.Options[0].Value).To(Equal("blue"))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue