Merge pull request #11955 from pedro-r-marques/flag_resolv_conf

Auto commit by PR queue bot
This commit is contained in:
k8s-merge-robot 2015-08-30 21:03:54 -07:00
commit 4a7115d272
5 changed files with 111 additions and 16 deletions

View File

@ -123,6 +123,7 @@ type KubeletServer struct {
PodCIDR string PodCIDR string
MaxPods int MaxPods int
DockerExecHandlerName string DockerExecHandlerName string
ResolverConfig string
// Flags intended for testing // Flags intended for testing
@ -253,6 +254,7 @@ func (s *KubeletServer) AddFlags(fs *pflag.FlagSet) {
fs.IntVar(&s.MaxPods, "max-pods", 40, "Number of Pods that can run on this Kubelet.") fs.IntVar(&s.MaxPods, "max-pods", 40, "Number of Pods that can run on this Kubelet.")
fs.StringVar(&s.DockerExecHandlerName, "docker-exec-handler", s.DockerExecHandlerName, "Handler to use when executing a command in a container. Valid values are 'native' and 'nsenter'. Defaults to 'native'.") fs.StringVar(&s.DockerExecHandlerName, "docker-exec-handler", s.DockerExecHandlerName, "Handler to use when executing a command in a container. Valid values are 'native' and 'nsenter'. Defaults to 'native'.")
fs.StringVar(&s.PodCIDR, "pod-cidr", "", "The CIDR to use for pod IP addresses, only used in standalone mode. In cluster mode, this is obtained from the master.") fs.StringVar(&s.PodCIDR, "pod-cidr", "", "The CIDR to use for pod IP addresses, only used in standalone mode. In cluster mode, this is obtained from the master.")
fs.StringVar(&s.ResolverConfig, "resolv-conf", kubelet.ResolvConfDefault, "Resolver configuration file used as the basis for the container DNS resolution configuration.")
// Flags intended for testing, not recommended used in production environments. // Flags intended for testing, not recommended used in production environments.
fs.BoolVar(&s.ReallyCrashForTesting, "really-crash-for-testing", s.ReallyCrashForTesting, "If true, when panics occur crash. Intended for testing.") fs.BoolVar(&s.ReallyCrashForTesting, "really-crash-for-testing", s.ReallyCrashForTesting, "If true, when panics occur crash. Intended for testing.")
fs.Float64Var(&s.ChaosChance, "chaos-chance", s.ChaosChance, "If > 0.0, introduce random client errors and latency. Intended for testing. [default=0.0]") fs.Float64Var(&s.ChaosChance, "chaos-chance", s.ChaosChance, "If > 0.0, introduce random client errors and latency. Intended for testing. [default=0.0]")
@ -359,6 +361,7 @@ func (s *KubeletServer) KubeletConfig() (*KubeletConfig, error) {
PodCIDR: s.PodCIDR, PodCIDR: s.PodCIDR,
MaxPods: s.MaxPods, MaxPods: s.MaxPods,
DockerExecHandler: dockerExecHandler, DockerExecHandler: dockerExecHandler,
ResolverConfig: s.ResolverConfig,
}, nil }, nil
} }
@ -600,6 +603,7 @@ func SimpleKubelet(client *client.Client,
SystemContainer: "", SystemContainer: "",
MaxPods: 32, MaxPods: 32,
DockerExecHandler: &dockertools.NativeExecHandler{}, DockerExecHandler: &dockertools.NativeExecHandler{},
ResolverConfig: kubelet.ResolvConfDefault,
} }
return &kcfg return &kcfg
} }
@ -769,6 +773,7 @@ type KubeletConfig struct {
PodCIDR string PodCIDR string
MaxPods int MaxPods int
DockerExecHandler dockertools.ExecHandler DockerExecHandler dockertools.ExecHandler
ResolverConfig string
} }
func createAndInitKubelet(kc *KubeletConfig) (k KubeletBootstrap, pc *config.PodConfig, err error) { func createAndInitKubelet(kc *KubeletConfig) (k KubeletBootstrap, pc *config.PodConfig, err error) {
@ -827,7 +832,8 @@ func createAndInitKubelet(kc *KubeletConfig) (k KubeletBootstrap, pc *config.Pod
kc.ConfigureCBR0, kc.ConfigureCBR0,
kc.PodCIDR, kc.PodCIDR,
kc.MaxPods, kc.MaxPods,
kc.DockerExecHandler) kc.DockerExecHandler,
kc.ResolverConfig)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err

View File

@ -261,6 +261,7 @@ func (s *KubeletExecutorServer) Run(hks hyperkube.Interface, _ []string) error {
ConfigureCBR0: s.ConfigureCBR0, ConfigureCBR0: s.ConfigureCBR0,
MaxPods: s.MaxPods, MaxPods: s.MaxPods,
DockerExecHandler: dockerExecHandler, DockerExecHandler: dockerExecHandler,
ResolverConfig: s.ResolverConfig,
} }
kcfg.NodeName = kcfg.Hostname kcfg.NodeName = kcfg.Hostname
@ -362,6 +363,7 @@ func (ks *KubeletExecutorServer) createAndInitKubelet(
kc.PodCIDR, kc.PodCIDR,
kc.MaxPods, kc.MaxPods,
kc.DockerExecHandler, kc.DockerExecHandler,
kc.ResolverConfig,
) )
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err

View File

@ -206,6 +206,7 @@ reject-paths
repo-root repo-root
report-dir report-dir
required-contexts required-contexts
resolv-conf
resource-container resource-container
resource-quota-sync-period resource-quota-sync-period
resource-version resource-version

View File

@ -87,6 +87,9 @@ const (
// suffice because a goroutine is dedicated to check the channel and does // suffice because a goroutine is dedicated to check the channel and does
// not block on anything else. // not block on anything else.
podKillingChannelCapacity = 50 podKillingChannelCapacity = 50
// system default DNS resolver configuration
ResolvConfDefault = "/etc/resolv.conf"
) )
var ( var (
@ -159,7 +162,8 @@ func NewMainKubelet(
configureCBR0 bool, configureCBR0 bool,
podCIDR string, podCIDR string,
pods int, pods int,
dockerExecHandler dockertools.ExecHandler) (*Kubelet, error) { dockerExecHandler dockertools.ExecHandler,
resolverConfig string) (*Kubelet, error) {
if rootDirectory == "" { if rootDirectory == "" {
return nil, fmt.Errorf("invalid root directory %q", rootDirectory) return nil, fmt.Errorf("invalid root directory %q", rootDirectory)
} }
@ -275,6 +279,7 @@ func NewMainKubelet(
podCIDR: podCIDR, podCIDR: podCIDR,
pods: pods, pods: pods,
syncLoopMonitor: util.AtomicValue{}, syncLoopMonitor: util.AtomicValue{},
resolverConfig: resolverConfig,
} }
if plug, err := network.InitNetworkPlugin(networkPlugins, networkPluginName, &networkHost{klet}); err != nil { if plug, err := network.InitNetworkPlugin(networkPlugins, networkPluginName, &networkHost{klet}); err != nil {
@ -542,6 +547,11 @@ type Kubelet struct {
// Channel for sending pods to kill. // Channel for sending pods to kill.
podKillingCh chan *kubecontainer.Pod podKillingCh chan *kubecontainer.Pod
// The configuration file used as the base to generate the container's
// DNS resolver configuration file. This can be used in conjunction with
// clusterDomain and clusterDNS.
resolverConfig string
} }
// getRootDir returns the full path to the directory under which kubelet can // getRootDir returns the full path to the directory under which kubelet can
@ -948,12 +958,12 @@ func (kl *Kubelet) GenerateRunContainerOptions(pod *api.Pod, container *api.Cont
opts.PodContainerDir = p opts.PodContainerDir = p
} }
} }
if pod.Spec.DNSPolicy == api.DNSClusterFirst {
opts.DNS, opts.DNSSearch, err = kl.getClusterDNS(pod) opts.DNS, opts.DNSSearch, err = kl.getClusterDNS(pod)
if err != nil { if err != nil {
return nil, err return nil, err
}
} }
return opts, nil return opts, nil
} }
@ -1086,27 +1096,47 @@ func (kl *Kubelet) podFieldSelectorRuntimeValue(fs *api.ObjectFieldSelector, pod
// getClusterDNS returns a list of the DNS servers and a list of the DNS search // getClusterDNS returns a list of the DNS servers and a list of the DNS search
// domains of the cluster. // domains of the cluster.
func (kl *Kubelet) getClusterDNS(pod *api.Pod) ([]string, []string, error) { func (kl *Kubelet) getClusterDNS(pod *api.Pod) ([]string, []string, error) {
var hostDNS, hostSearch []string
// Get host DNS settings and append them to cluster DNS settings. // Get host DNS settings and append them to cluster DNS settings.
f, err := os.Open("/etc/resolv.conf") if kl.resolverConfig != "" {
if err != nil { f, err := os.Open(kl.resolverConfig)
return nil, nil, err if err != nil {
} return nil, nil, err
defer f.Close() }
defer f.Close()
hostDNS, hostSearch, err := parseResolvConf(f) hostDNS, hostSearch, err = parseResolvConf(f)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
}
}
if pod.Spec.DNSPolicy != api.DNSClusterFirst {
// When the kubelet --resolv-conf flag is set to the empty string, use
// DNS settings that override the docker default (which is to use
// /etc/resolv.conf) and effectivly disable DNS lookups. According to
// the bind documentation, the behavior of the DNS client library when
// "nameservers" are not specified is to "use the nameserver on the
// local machine". A nameserver setting of localhost is equivalent to
// this documented behavior.
if kl.resolverConfig == "" {
hostDNS = []string{"127.0.0.1"}
hostSearch = []string{"."}
}
return hostDNS, hostSearch, nil
} }
var dns, dnsSearch []string var dns, dnsSearch []string
if kl.clusterDNS != nil { if kl.clusterDNS != nil {
dns = append([]string{kl.clusterDNS.String()}, hostDNS...) dns = append([]string{kl.clusterDNS.String()}, hostDNS...)
} else {
dns = hostDNS
} }
if kl.clusterDomain != "" { if kl.clusterDomain != "" {
nsSvcDomain := fmt.Sprintf("%s.svc.%s", pod.Namespace, kl.clusterDomain) nsSvcDomain := fmt.Sprintf("%s.svc.%s", pod.Namespace, kl.clusterDomain)
svcDomain := fmt.Sprintf("svc.%s", kl.clusterDomain) svcDomain := fmt.Sprintf("svc.%s", kl.clusterDomain)
dnsSearch = append([]string{nsSvcDomain, svcDomain, kl.clusterDomain}, hostSearch...) dnsSearch = append([]string{nsSvcDomain, svcDomain, kl.clusterDomain}, hostSearch...)
} else {
dnsSearch = hostSearch
} }
return dns, dnsSearch, nil return dns, dnsSearch, nil
} }

View File

@ -22,6 +22,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net"
"net/http" "net/http"
"os" "os"
"path" "path"
@ -874,6 +875,61 @@ func TestParseResolvConf(t *testing.T) {
} }
} }
func TestDNSConfigurationParams(t *testing.T) {
testKubelet := newTestKubelet(t)
kubelet := testKubelet.kubelet
clusterNS := "203.0.113.1"
kubelet.clusterDomain = "kubernetes.io"
kubelet.clusterDNS = net.ParseIP(clusterNS)
pods := newTestPods(2)
pods[0].Spec.DNSPolicy = api.DNSClusterFirst
pods[1].Spec.DNSPolicy = api.DNSDefault
options := make([]*kubecontainer.RunContainerOptions, 2)
for i, pod := range pods {
var err error
kubelet.volumeManager.SetVolumes(pod.UID, make(kubecontainer.VolumeMap, 0))
options[i], err = kubelet.GenerateRunContainerOptions(pod, &api.Container{})
if err != nil {
t.Fatalf("failed to generate container options: %v", err)
}
}
if len(options[0].DNS) != 1 || options[0].DNS[0] != clusterNS {
t.Errorf("expected nameserver %s, got %+v", clusterNS, options[0].DNS)
}
if len(options[0].DNSSearch) == 0 || options[0].DNSSearch[0] != ".svc."+kubelet.clusterDomain {
t.Errorf("expected search %s, got %+v", ".svc."+kubelet.clusterDomain, options[0].DNSSearch)
}
if len(options[1].DNS) != 1 || options[1].DNS[0] != "127.0.0.1" {
t.Errorf("expected nameserver 127.0.0.1, got %+v", options[1].DNS)
}
if len(options[1].DNSSearch) != 1 || options[1].DNSSearch[0] != "." {
t.Errorf("expected search \".\", got %+v", options[1].DNSSearch)
}
kubelet.resolverConfig = "/etc/resolv.conf"
for i, pod := range pods {
var err error
options[i], err = kubelet.GenerateRunContainerOptions(pod, &api.Container{})
if err != nil {
t.Fatalf("failed to generate container options: %v", err)
}
}
t.Logf("nameservers %+v", options[1].DNS)
if len(options[0].DNS) != len(options[1].DNS)+1 {
t.Errorf("expected prepend of cluster nameserver, got %+v", options[0].DNS)
} else if options[0].DNS[0] != clusterNS {
t.Errorf("expected nameserver %s, got %v", clusterNS, options[0].DNS[0])
}
if len(options[0].DNSSearch) != len(options[1].DNSSearch)+3 {
t.Errorf("expected prepend of cluster domain, got %+v", options[0].DNSSearch)
} else if options[0].DNSSearch[0] != ".svc."+kubelet.clusterDomain {
t.Errorf("expected domain %s, got %s", ".svc."+kubelet.clusterDomain, options[0].DNSSearch)
}
}
type testServiceLister struct { type testServiceLister struct {
services []api.Service services []api.Service
} }