From e5dd1c4c0a60136876853297bedd0e93d7e0c0d8 Mon Sep 17 00:00:00 2001 From: Abhishek Shah Date: Wed, 4 May 2016 16:24:43 -0700 Subject: [PATCH] added cmd/kube-dns --- cmd/kube-dns/app/options/options.go | 103 ++++++++++++++++++++++ cmd/kube-dns/app/server.go | 131 ++++++++++++++++++++++++++++ cmd/kube-dns/dns.go | 41 +++++++++ 3 files changed, 275 insertions(+) create mode 100644 cmd/kube-dns/app/options/options.go create mode 100644 cmd/kube-dns/app/server.go create mode 100644 cmd/kube-dns/dns.go diff --git a/cmd/kube-dns/app/options/options.go b/cmd/kube-dns/app/options/options.go new file mode 100644 index 00000000000..973a24901a9 --- /dev/null +++ b/cmd/kube-dns/app/options/options.go @@ -0,0 +1,103 @@ +/* +Copyright 2014 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package options contains flags for initializing a proxy. +package options + +import ( + "net/url" + "os" + + "fmt" + "github.com/spf13/pflag" + "k8s.io/kubernetes/pkg/util/validation" + _ "net/http/pprof" + "strings" +) + +type KubeDNSConfig struct { + ClusterDomain string + KubeConfigFile string + KubeMasterURL string + HealthzPort int +} + +func NewKubeDNSConfig() *KubeDNSConfig { + return &KubeDNSConfig{ + ClusterDomain: "cluster.local.", + KubeConfigFile: "", + KubeMasterURL: "", + HealthzPort: 8081, + } +} + +type clusterDomainVar struct { + val *string +} + +func (m clusterDomainVar) Set(v string) error { + v = strings.TrimSuffix(v, ".") + segments := strings.Split(v, ".") + for _, segment := range segments { + if !validation.IsDNS1123Label(segment) { + return fmt.Errorf("Not a valid DNS label") + } + } + if !strings.HasSuffix(v, ".") { + v = fmt.Sprintf("%s.", v) + } + *m.val = v + return nil +} + +func (m clusterDomainVar) String() string { + return *m.val +} + +func (m clusterDomainVar) Type() string { + return "string" +} + +type kubeMasterURLVar struct { + val *string +} + +func (m kubeMasterURLVar) Set(v string) error { + parsedURL, err := url.Parse(os.ExpandEnv(v)) + if err != nil { + return fmt.Errorf("failed to parse kube-master-url") + } + if parsedURL.Scheme == "" || parsedURL.Host == "" || parsedURL.Host == ":" { + return fmt.Errorf("invalid kube-master-url specified") + } + *m.val = v + return nil +} + +func (m kubeMasterURLVar) String() string { + return *m.val +} + +func (m kubeMasterURLVar) Type() string { + return "string" +} + +func (s *KubeDNSConfig) AddFlags(fs *pflag.FlagSet) { + fs.Var(clusterDomainVar{&s.ClusterDomain}, "domain", "domain under which to create names") + fs.StringVar(&s.KubeConfigFile, "kubecfg-file", s.KubeConfigFile, "Location of kubecfg file for access to kubernetes master service; --kube-master-url overrides the URL part of this; if neither this nor --kube-master-url are provided, defaults to service account tokens") + fs.Var(kubeMasterURLVar{&s.KubeMasterURL}, "kube-master-url", "URL to reach kubernetes master. Env variables in this flag will be expanded.") + fs.IntVar(&s.HealthzPort, "healthz-port", s.HealthzPort, "port on which to serve a kube-dns HTTP readiness probe.") +} diff --git a/cmd/kube-dns/app/server.go b/cmd/kube-dns/app/server.go new file mode 100644 index 00000000000..d7d3d20f1d8 --- /dev/null +++ b/cmd/kube-dns/app/server.go @@ -0,0 +1,131 @@ +/* +Copyright 2014 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package app + +import ( + "fmt" + "net/http" + "os" + "os/signal" + "syscall" + + "github.com/golang/glog" + + "github.com/skynetservices/skydns/metrics" + "github.com/skynetservices/skydns/server" + "k8s.io/kubernetes/cmd/kube-dns/app/options" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/client/restclient" + kclient "k8s.io/kubernetes/pkg/client/unversioned" + kclientcmd "k8s.io/kubernetes/pkg/client/unversioned/clientcmd" + kdns "k8s.io/kubernetes/pkg/dns" +) + +type KubeDNSServer struct { + // DNS domain name. + domain string + healthzPort int + kd *kdns.KubeDNS +} + +func NewKubeDNSServerDefault(config *options.KubeDNSConfig) *KubeDNSServer { + ks := KubeDNSServer{ + domain: config.ClusterDomain, + } + + kubeClient, err := newKubeClient(config) + if err != nil { + glog.Fatalf("Failed to create a kubernetes client: %v", err) + } + ks.healthzPort = config.HealthzPort + ks.kd = kdns.NewKubeDNS(kubeClient, config.ClusterDomain) + return &ks +} + +// TODO: evaluate using pkg/client/clientcmd +func newKubeClient(dnsConfig *options.KubeDNSConfig) (*kclient.Client, error) { + var ( + config *restclient.Config + err error + ) + + if dnsConfig.KubeMasterURL != "" && dnsConfig.KubeConfigFile == "" { + // Only --kube-master-url was provided. + config = &restclient.Config{ + Host: dnsConfig.KubeMasterURL, + ContentConfig: restclient.ContentConfig{GroupVersion: &unversioned.GroupVersion{Version: "v1"}}, + } + } else { + // We either have: + // 1) --kube-master-url and --kubecfg-file + // 2) just --kubecfg-file + // 3) neither flag + // In any case, the logic is the same. If (3), this will automatically + // fall back on the service account token. + overrides := &kclientcmd.ConfigOverrides{} + overrides.ClusterInfo.Server = dnsConfig.KubeMasterURL // might be "", but that is OK + rules := &kclientcmd.ClientConfigLoadingRules{ExplicitPath: dnsConfig.KubeConfigFile} // might be "", but that is OK + if config, err = kclientcmd.NewNonInteractiveDeferredLoadingClientConfig(rules, overrides).ClientConfig(); err != nil { + return nil, err + } + } + + glog.Infof("Using %s for kubernetes master", config.Host) + glog.Infof("Using kubernetes API %v", config.GroupVersion) + return kclient.New(config) +} + +func (server *KubeDNSServer) Run() { + setupSignalHandlers() + server.startSkyDNSServer() + server.kd.Start() + server.setupHealthzHandlers() + glog.Infof("Setting up Healthz Handler(/readiness, /cache) on port :%d", server.healthzPort) + glog.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", server.healthzPort), nil)) +} + +// setupHealthzHandlers sets up a readiness and liveness endpoint for kube2sky. +func (server *KubeDNSServer) setupHealthzHandlers() { + http.HandleFunc("/readiness", func(w http.ResponseWriter, req *http.Request) { + fmt.Fprintf(w, "ok\n") + }) + http.HandleFunc("/cache", func(w http.ResponseWriter, req *http.Request) { + fmt.Fprint(w, server.kd.GetCacheAsJSON()) + }) +} + +// setupSignalHandlers runs a goroutine that waits on SIGINT or SIGTERM and logs it +// before exiting. +func setupSignalHandlers() { + sigChan := make(chan os.Signal) + signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) + go func() { + glog.Fatalf("Received signal: %s", <-sigChan) + }() +} + +func (d *KubeDNSServer) startSkyDNSServer() { + skydnsConfig := &server.Config{Domain: d.domain, DnsAddr: "0.0.0.0:53"} + server.SetDefaults(skydnsConfig) + s := server.New(d.kd, skydnsConfig) + if err := metrics.Metrics(); err != nil { + glog.Fatalf("skydns: %s", err) + } else { + glog.Infof("skydns: metrics enabled on :%s%s", metrics.Port, metrics.Path) + } + go s.Run() +} diff --git a/cmd/kube-dns/dns.go b/cmd/kube-dns/dns.go new file mode 100644 index 00000000000..07d4661d855 --- /dev/null +++ b/cmd/kube-dns/dns.go @@ -0,0 +1,41 @@ +/* +Copyright 2014 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "github.com/spf13/pflag" + "k8s.io/kubernetes/cmd/kube-dns/app" + "k8s.io/kubernetes/cmd/kube-dns/app/options" + "k8s.io/kubernetes/pkg/util" + "k8s.io/kubernetes/pkg/util/flag" + "k8s.io/kubernetes/pkg/version/verflag" + "runtime" +) + +func main() { + runtime.GOMAXPROCS(runtime.NumCPU()) + config := options.NewKubeDNSConfig() + config.AddFlags(pflag.CommandLine) + + flag.InitFlags() + util.InitLogs() + defer util.FlushLogs() + + verflag.PrintAndExitIfRequested() + server := app.NewKubeDNSServerDefault(config) + server.Run() +}