mirror of
https://github.com/containers/podman.git
synced 2025-06-20 00:51:16 +08:00
Merge pull request #9150 from baude/playkubedns
Honor custom DNS in play|generate kube
This commit is contained in:
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"))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user