Merge pull request #35449 from MrHohn/kubedns-readysignal

Automatic merge from submit-queue

kubedns: use initial resource listing as ready signal

Fix #35140.

Set up the ready signal after the first resource listing finished for both endpoints and services instead of listen on kubernetes service.

@bprashanth @bowei @thockin

**Release note**:
```
```
This commit is contained in:
Kubernetes Submit Queue 2016-12-08 11:35:44 -08:00 committed by GitHub
commit 8820922997
4 changed files with 45 additions and 47 deletions

View File

@ -23,6 +23,7 @@ import (
"net/url" "net/url"
"os" "os"
"strings" "strings"
"time"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
@ -31,9 +32,10 @@ import (
) )
type KubeDNSConfig struct { type KubeDNSConfig struct {
ClusterDomain string ClusterDomain string
KubeConfigFile string KubeConfigFile string
KubeMasterURL string KubeMasterURL string
InitialSyncTimeout time.Duration
HealthzPort int HealthzPort int
DNSBindAddress string DNSBindAddress string
@ -47,10 +49,11 @@ type KubeDNSConfig struct {
func NewKubeDNSConfig() *KubeDNSConfig { func NewKubeDNSConfig() *KubeDNSConfig {
return &KubeDNSConfig{ return &KubeDNSConfig{
ClusterDomain: "cluster.local.", ClusterDomain: "cluster.local.",
HealthzPort: 8081, HealthzPort: 8081,
DNSBindAddress: "0.0.0.0", DNSBindAddress: "0.0.0.0",
DNSPort: 53, DNSPort: 53,
InitialSyncTimeout: 60 * time.Second,
Federations: make(map[string]string), Federations: make(map[string]string),
@ -160,4 +163,6 @@ func (s *KubeDNSConfig) AddFlags(fs *pflag.FlagSet) {
"config-map name. If empty, then the config-map will not used. Cannot be "+ "config-map name. If empty, then the config-map will not used. Cannot be "+
" used in conjunction with federations flag. config-map contains "+ " used in conjunction with federations flag. config-map contains "+
"dynamically adjustable configuration.") "dynamically adjustable configuration.")
fs.DurationVar(&s.InitialSyncTimeout, "initial-sync-timeout", s.InitialSyncTimeout,
"Timeout for initial resource sync.")
} }

View File

@ -47,17 +47,11 @@ type KubeDNSServer struct {
} }
func NewKubeDNSServerDefault(config *options.KubeDNSConfig) *KubeDNSServer { func NewKubeDNSServerDefault(config *options.KubeDNSConfig) *KubeDNSServer {
ks := KubeDNSServer{domain: config.ClusterDomain}
kubeClient, err := newKubeClient(config) kubeClient, err := newKubeClient(config)
if err != nil { if err != nil {
glog.Fatalf("Failed to create a kubernetes client: %v", err) glog.Fatalf("Failed to create a kubernetes client: %v", err)
} }
ks.healthzPort = config.HealthzPort
ks.dnsBindAddress = config.DNSBindAddress
ks.dnsPort = config.DNSPort
var configSync dnsconfig.Sync var configSync dnsconfig.Sync
if config.ConfigMap == "" { if config.ConfigMap == "" {
glog.V(0).Infof("ConfigMap not configured, using values from command line flags") glog.V(0).Infof("ConfigMap not configured, using values from command line flags")
@ -70,9 +64,13 @@ func NewKubeDNSServerDefault(config *options.KubeDNSConfig) *KubeDNSServer {
kubeClient, config.ConfigMapNs, config.ConfigMap) kubeClient, config.ConfigMapNs, config.ConfigMap)
} }
ks.kd = kdns.NewKubeDNS(kubeClient, config.ClusterDomain, configSync) return &KubeDNSServer{
domain: config.ClusterDomain,
return &ks healthzPort: config.HealthzPort,
dnsBindAddress: config.DNSBindAddress,
dnsPort: config.DNSPort,
kd: kdns.NewKubeDNS(kubeClient, config.ClusterDomain, config.InitialSyncTimeout, configSync),
}
} }
// TODO: evaluate using pkg/client/clientcmd // TODO: evaluate using pkg/client/clientcmd

View File

@ -276,6 +276,7 @@ image-service-endpoint
include-extended-apis include-extended-apis
include-extended-apis include-extended-apis
included-types-overrides included-types-overrides
initial-sync-timeout
input-base input-base
input-dirs input-dirs
insecure-allow-any-token insecure-allow-any-token

View File

@ -24,9 +24,6 @@ import (
"sync" "sync"
"time" "time"
etcd "github.com/coreos/etcd/client"
"github.com/miekg/dns"
skymsg "github.com/skynetservices/skydns/msg"
"k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/api/v1/endpoints" "k8s.io/kubernetes/pkg/api/v1/endpoints"
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1" metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
@ -40,7 +37,10 @@ import (
"k8s.io/kubernetes/pkg/util/wait" "k8s.io/kubernetes/pkg/util/wait"
"k8s.io/kubernetes/pkg/watch" "k8s.io/kubernetes/pkg/watch"
etcd "github.com/coreos/etcd/client"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/miekg/dns"
skymsg "github.com/skynetservices/skydns/msg"
) )
const ( const (
@ -117,9 +117,12 @@ type KubeDNS struct {
configLock sync.RWMutex configLock sync.RWMutex
// configSync manages synchronization of the config map // configSync manages synchronization of the config map
configSync config.Sync configSync config.Sync
// Initial timeout for endpoints and services to be synced from APIServer
initialSyncTimeout time.Duration
} }
func NewKubeDNS(client clientset.Interface, clusterDomain string, configSync config.Sync) *KubeDNS { func NewKubeDNS(client clientset.Interface, clusterDomain string, timeout time.Duration, configSync config.Sync) *KubeDNS {
kd := &KubeDNS{ kd := &KubeDNS{
kubeClient: client, kubeClient: client,
domain: clusterDomain, domain: clusterDomain,
@ -129,6 +132,7 @@ func NewKubeDNS(client clientset.Interface, clusterDomain string, configSync con
reverseRecordMap: make(map[string]*skymsg.Service), reverseRecordMap: make(map[string]*skymsg.Service),
clusterIPServiceMap: make(map[string]*v1.Service), clusterIPServiceMap: make(map[string]*v1.Service),
domainPath: util.ReverseArray(strings.Split(strings.TrimRight(clusterDomain, "."), ".")), domainPath: util.ReverseArray(strings.Split(strings.TrimRight(clusterDomain, "."), ".")),
initialSyncTimeout: timeout,
configLock: sync.RWMutex{}, configLock: sync.RWMutex{},
configSync: configSync, configSync: configSync,
@ -149,38 +153,28 @@ func (kd *KubeDNS) Start() {
kd.startConfigMapSync() kd.startConfigMapSync()
// Wait synchronously for the Kubernetes service. This ensures that // Wait synchronously for the initial list operations to be
// the Start function returns only after having received Service // complete of endpoints and services from APIServer.
// objects from APIServer. kd.waitForResourceSyncedOrDie()
//
// TODO: we might not have to wait for kubernetes service
// specifically. We should just wait for a list operation to be
// complete from APIServer.
kd.waitForKubernetesService()
} }
func (kd *KubeDNS) waitForKubernetesService() { func (kd *KubeDNS) waitForResourceSyncedOrDie() {
glog.V(2).Infof("Waiting for Kubernetes service") // Wait for both controllers have completed an initial resource listing
timeout := time.After(kd.initialSyncTimeout)
const kubernetesSvcName = "kubernetes" ticker := time.NewTicker(500 * time.Millisecond)
const servicePollInterval = 1 * time.Second defer ticker.Stop()
name := fmt.Sprintf("%v/%v", v1.NamespaceDefault, kubernetesSvcName)
glog.V(2).Infof("Waiting for service: %v", name)
for { for {
svc, err := kd.kubeClient.Core().Services(v1.NamespaceDefault).Get(kubernetesSvcName) select {
if err != nil || svc == nil { case <-timeout:
glog.V(3).Infof( glog.Fatalf("Timeout waiting for initialization")
"Ignoring error while waiting for service %v: %v. Sleeping %v before retrying.", case <-ticker.C:
name, err, servicePollInterval) if kd.endpointsController.HasSynced() && kd.serviceController.HasSynced() {
time.Sleep(servicePollInterval) glog.V(0).Infof("Initialized services and endpoints from apiserver")
continue return
}
glog.V(0).Infof("DNS server not ready, retry in 500 milliseconds")
} }
break
} }
return
} }
func (kd *KubeDNS) startConfigMapSync() { func (kd *KubeDNS) startConfigMapSync() {