2016-05-04 08:18:00 +00:00
|
|
|
/*
|
|
|
|
Copyright 2016 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 localkube
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"os"
|
2016-05-09 20:37:46 +00:00
|
|
|
"time"
|
2016-05-04 08:18:00 +00:00
|
|
|
|
2016-05-05 13:38:23 +00:00
|
|
|
"k8s.io/minikube/pkg/localkube/kube2sky"
|
2016-05-04 08:18:00 +00:00
|
|
|
|
2016-06-10 16:41:53 +00:00
|
|
|
etcd "github.com/coreos/etcd/client"
|
2016-05-31 16:52:16 +00:00
|
|
|
"github.com/golang/glog"
|
2016-05-04 08:18:00 +00:00
|
|
|
backendetcd "github.com/skynetservices/skydns/backends/etcd"
|
2016-06-10 16:41:53 +00:00
|
|
|
"github.com/skynetservices/skydns/metrics"
|
2016-05-04 08:18:00 +00:00
|
|
|
skydns "github.com/skynetservices/skydns/server"
|
|
|
|
kube "k8s.io/kubernetes/pkg/api"
|
|
|
|
kubeclient "k8s.io/kubernetes/pkg/client/unversioned"
|
|
|
|
"k8s.io/kubernetes/pkg/util/intstr"
|
2016-05-09 20:35:57 +00:00
|
|
|
|
2016-06-10 16:41:53 +00:00
|
|
|
"golang.org/x/net/context"
|
2016-05-09 20:35:57 +00:00
|
|
|
"k8s.io/minikube/pkg/util"
|
2016-05-04 08:18:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
DNSName = "dns"
|
|
|
|
|
|
|
|
DNSServiceName = "kube-dns"
|
|
|
|
DNSServiceNamespace = "kube-system"
|
|
|
|
)
|
|
|
|
|
|
|
|
type DNSServer struct {
|
|
|
|
etcd *EtcdServer
|
|
|
|
sky runner
|
|
|
|
kube2sky func() error
|
|
|
|
dnsServerAddr *net.UDPAddr
|
|
|
|
clusterIP string
|
|
|
|
done chan struct{}
|
|
|
|
}
|
|
|
|
|
2016-05-09 20:35:57 +00:00
|
|
|
func (lk LocalkubeServer) NewDNSServer(rootDomain, clusterIP, kubeAPIServer string) (*DNSServer, error) {
|
2016-05-04 08:18:00 +00:00
|
|
|
// setup backing etcd store
|
|
|
|
peerURLs := []string{"http://localhost:9256"}
|
2016-07-25 21:59:34 +00:00
|
|
|
DNSEtcdURLs := []string{"http://localhost:49090"}
|
2016-05-09 20:35:57 +00:00
|
|
|
|
2016-05-10 14:49:09 +00:00
|
|
|
publicIP, err := lk.GetHostIP()
|
2016-05-09 20:35:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-05-10 14:49:09 +00:00
|
|
|
serverAddress := fmt.Sprintf("%s:%d", publicIP.String(), 53)
|
2016-05-09 20:35:57 +00:00
|
|
|
etcdServer, err := lk.NewEtcd(DNSEtcdURLs, peerURLs, DNSName, lk.GetDNSDataDirectory())
|
2016-05-04 08:18:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// setup skydns
|
2016-06-10 16:41:53 +00:00
|
|
|
cfg := etcd.Config{
|
|
|
|
Endpoints: DNSEtcdURLs,
|
|
|
|
Transport: etcd.DefaultTransport,
|
|
|
|
}
|
|
|
|
etcdClient, err := etcd.New(cfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
keysApi := etcd.NewKeysAPI(etcdClient)
|
|
|
|
|
2016-05-04 08:18:00 +00:00
|
|
|
skyConfig := &skydns.Config{
|
|
|
|
DnsAddr: serverAddress,
|
|
|
|
Domain: rootDomain,
|
|
|
|
}
|
|
|
|
|
|
|
|
dnsAddress, err := net.ResolveUDPAddr("udp", serverAddress)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
skydns.SetDefaults(skyConfig)
|
|
|
|
|
2016-06-10 16:41:53 +00:00
|
|
|
backend := backendetcd.NewBackend(
|
|
|
|
keysApi,
|
|
|
|
context.Background(),
|
|
|
|
&backendetcd.Config{
|
|
|
|
Ttl: skyConfig.Ttl,
|
|
|
|
Priority: skyConfig.Priority,
|
|
|
|
})
|
2016-05-04 08:18:00 +00:00
|
|
|
skyServer := skydns.New(backend, skyConfig)
|
|
|
|
|
|
|
|
// setup so prometheus doesn't run into nil
|
2016-06-10 16:41:53 +00:00
|
|
|
metrics.Metrics()
|
2016-05-04 08:18:00 +00:00
|
|
|
|
|
|
|
// setup kube2sky
|
|
|
|
k2s := kube2sky.NewKube2Sky(rootDomain, DNSEtcdURLs[0], "", kubeAPIServer, 10*time.Second, 8081)
|
|
|
|
|
|
|
|
return &DNSServer{
|
|
|
|
etcd: etcdServer,
|
|
|
|
sky: skyServer,
|
|
|
|
kube2sky: k2s,
|
|
|
|
dnsServerAddr: dnsAddress,
|
|
|
|
clusterIP: clusterIP,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (dns *DNSServer) Start() {
|
|
|
|
if dns.done != nil {
|
2016-05-09 20:35:57 +00:00
|
|
|
fmt.Fprint(os.Stderr, util.Pad("DNS server already started"))
|
2016-05-04 08:18:00 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
dns.done = make(chan struct{})
|
|
|
|
|
|
|
|
dns.etcd.Start()
|
2016-05-09 20:35:57 +00:00
|
|
|
go util.Until(dns.kube2sky, os.Stderr, "kube2sky", 2*time.Second, dns.done)
|
|
|
|
go util.Until(dns.sky.Run, os.Stderr, "skydns", 1*time.Second, dns.done)
|
2016-05-04 08:18:00 +00:00
|
|
|
|
|
|
|
go func() {
|
|
|
|
var err error
|
|
|
|
client := kubeClient()
|
|
|
|
|
|
|
|
meta := kube.ObjectMeta{
|
|
|
|
Name: DNSServiceName,
|
|
|
|
Namespace: DNSServiceNamespace,
|
|
|
|
Labels: map[string]string{
|
2016-05-31 21:28:32 +00:00
|
|
|
"k8s-app": "kube-dns",
|
|
|
|
"kubernetes.io/name": "KubeDNS",
|
2016-05-04 08:18:00 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
if err != nil {
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
}
|
|
|
|
|
2016-05-09 20:36:33 +00:00
|
|
|
if _, err = client.Namespaces().Get(DNSServiceNamespace); notFoundErr(err) {
|
|
|
|
err = createKubeSystemIfNotPresent(client)
|
|
|
|
if err != nil {
|
2016-05-31 16:52:16 +00:00
|
|
|
glog.Infof("Failed to create the kube-system namespace: %v\n", err)
|
2016-05-09 20:36:33 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
} else if err != nil {
|
2016-05-31 16:52:16 +00:00
|
|
|
glog.Infof("Failed to check for kube-system namespace existence: %v\n", err)
|
2016-05-09 20:36:33 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2016-05-04 08:18:00 +00:00
|
|
|
// setup service
|
|
|
|
if _, err = client.Services(meta.Namespace).Get(meta.Name); notFoundErr(err) {
|
|
|
|
// create service if doesn't exist
|
|
|
|
err = createService(client, meta, dns.clusterIP, dns.dnsServerAddr.Port)
|
|
|
|
if err != nil {
|
2016-05-31 16:52:16 +00:00
|
|
|
glog.Infof("Failed to create Service for DNS: %v\n", err)
|
2016-05-04 08:18:00 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
} else if err != nil {
|
|
|
|
// error if cannot check for Service
|
2016-05-31 16:52:16 +00:00
|
|
|
glog.Infof("Failed to check for DNS Service existence: %v\n", err)
|
2016-05-04 08:18:00 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// setup endpoint
|
|
|
|
if _, err = client.Endpoints(meta.Namespace).Get(meta.Name); notFoundErr(err) {
|
|
|
|
// create endpoint if doesn't exist
|
2016-05-13 21:55:15 +00:00
|
|
|
err = createEndpoint(client, meta, dns.dnsServerAddr.IP.String(), int32(dns.dnsServerAddr.Port))
|
2016-05-09 20:35:57 +00:00
|
|
|
if err != nil {
|
2016-05-31 16:52:16 +00:00
|
|
|
glog.Infof("Failed to create Endpoint for DNS: %v\n", err)
|
2016-05-04 08:18:00 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
} else if err != nil {
|
|
|
|
// error if cannot check for Endpoint
|
2016-05-31 16:52:16 +00:00
|
|
|
glog.Infof("Failed to check for DNS Endpoint existence: %v\n", err)
|
2016-05-04 08:18:00 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// setup successful
|
2016-05-31 16:52:16 +00:00
|
|
|
glog.Infof("DNS started succesfully.")
|
2016-05-04 08:18:00 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (dns *DNSServer) Stop() {
|
|
|
|
teardownService()
|
|
|
|
|
|
|
|
// closing chan will prevent servers from restarting but will not kill running server
|
|
|
|
close(dns.done)
|
|
|
|
|
|
|
|
dns.etcd.Stop()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Name returns the servers unique name
|
|
|
|
func (DNSServer) Name() string {
|
|
|
|
return DNSName
|
|
|
|
}
|
|
|
|
|
|
|
|
// runner starts a server returning an error if it stops.
|
|
|
|
type runner interface {
|
|
|
|
Run() error
|
|
|
|
}
|
|
|
|
|
|
|
|
func createService(client *kubeclient.Client, meta kube.ObjectMeta, clusterIP string, dnsPort int) error {
|
|
|
|
service := &kube.Service{
|
|
|
|
ObjectMeta: meta,
|
|
|
|
Spec: kube.ServiceSpec{
|
|
|
|
ClusterIP: clusterIP,
|
|
|
|
Ports: []kube.ServicePort{
|
|
|
|
{
|
|
|
|
Name: "dns",
|
|
|
|
Port: 53,
|
|
|
|
TargetPort: intstr.FromInt(dnsPort),
|
|
|
|
Protocol: kube.ProtocolUDP,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "dns-tcp",
|
|
|
|
Port: 53,
|
|
|
|
TargetPort: intstr.FromInt(dnsPort),
|
|
|
|
Protocol: kube.ProtocolTCP,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := client.Services(meta.Namespace).Create(service)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-05-13 21:55:15 +00:00
|
|
|
func createEndpoint(client *kubeclient.Client, meta kube.ObjectMeta, dnsIP string, dnsPort int32) error {
|
2016-05-04 08:18:00 +00:00
|
|
|
endpoints := &kube.Endpoints{
|
|
|
|
ObjectMeta: meta,
|
|
|
|
Subsets: []kube.EndpointSubset{
|
|
|
|
{
|
|
|
|
Addresses: []kube.EndpointAddress{
|
|
|
|
{IP: dnsIP},
|
|
|
|
},
|
|
|
|
Ports: []kube.EndpointPort{
|
|
|
|
{
|
|
|
|
Name: "dns",
|
|
|
|
Port: dnsPort,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "dns-tcp",
|
|
|
|
Port: dnsPort,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := client.Endpoints(meta.Namespace).Create(endpoints)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-05-09 20:36:33 +00:00
|
|
|
func createKubeSystemIfNotPresent(client *kubeclient.Client) error {
|
|
|
|
|
|
|
|
var ns = &kube.Namespace{
|
|
|
|
ObjectMeta: kube.ObjectMeta{
|
|
|
|
Name: DNSServiceNamespace,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
_, err := client.Namespaces().Create(ns)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-05-04 08:18:00 +00:00
|
|
|
func teardownService() {
|
|
|
|
client := kubeClient()
|
|
|
|
client.Services(DNSServiceNamespace).Delete(DNSServiceName)
|
|
|
|
client.Endpoints(DNSServiceNamespace).Delete(DNSServiceName)
|
|
|
|
}
|