2016-02-22 00:13:08 +00:00
|
|
|
/*
|
|
|
|
Copyright 2015 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 (
|
2016-04-12 01:28:27 +00:00
|
|
|
"flag"
|
2016-03-19 23:29:29 +00:00
|
|
|
"fmt"
|
2016-03-22 16:51:50 +00:00
|
|
|
"net/http"
|
|
|
|
"net/http/pprof"
|
2016-02-22 00:13:08 +00:00
|
|
|
"os"
|
2016-03-30 23:12:37 +00:00
|
|
|
"os/signal"
|
|
|
|
"syscall"
|
2016-02-22 00:13:08 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/golang/glog"
|
|
|
|
"github.com/spf13/pflag"
|
|
|
|
|
2016-03-28 01:12:15 +00:00
|
|
|
"k8s.io/contrib/ingress/controllers/nginx/nginx"
|
2016-03-19 23:29:29 +00:00
|
|
|
|
2016-02-22 00:13:08 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api"
|
|
|
|
"k8s.io/kubernetes/pkg/client/unversioned"
|
2016-03-22 16:51:50 +00:00
|
|
|
"k8s.io/kubernetes/pkg/healthz"
|
2016-04-10 23:02:41 +00:00
|
|
|
kubectl_util "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
2016-02-22 00:13:08 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
healthPort = 10249
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2016-04-06 14:46:06 +00:00
|
|
|
// value overwritten during build. This can be used to resolve issues.
|
2016-07-18 21:15:19 +00:00
|
|
|
version = "0.8.2"
|
2016-04-06 14:46:06 +00:00
|
|
|
gitRepo = "https://github.com/kubernetes/contrib"
|
|
|
|
|
2016-02-22 00:13:08 +00:00
|
|
|
flags = pflag.NewFlagSet("", pflag.ExitOnError)
|
|
|
|
|
|
|
|
defaultSvc = flags.String("default-backend-service", "",
|
|
|
|
`Service used to serve a 404 page for the default backend. Takes the form
|
|
|
|
namespace/name. The controller uses the first node port of this Service for
|
|
|
|
the default backend.`)
|
|
|
|
|
2016-03-19 23:29:29 +00:00
|
|
|
nxgConfigMap = flags.String("nginx-configmap", "",
|
|
|
|
`Name of the ConfigMap that containes the custom nginx configuration to use`)
|
|
|
|
|
2016-03-19 20:17:58 +00:00
|
|
|
tcpConfigMapName = flags.String("tcp-services-configmap", "",
|
|
|
|
`Name of the ConfigMap that containes the definition of the TCP services to expose.
|
2016-04-10 23:02:41 +00:00
|
|
|
The key in the map indicates the external port to be used. The value is the name of the
|
2016-03-19 20:17:58 +00:00
|
|
|
service with the format namespace/serviceName and the port of the service could be a number of the
|
|
|
|
name of the port.
|
|
|
|
The ports 80 and 443 are not allowed as external ports. This ports are reserved for nginx`)
|
2016-02-22 00:13:08 +00:00
|
|
|
|
2016-03-29 23:30:44 +00:00
|
|
|
udpConfigMapName = flags.String("udp-services-configmap", "",
|
|
|
|
`Name of the ConfigMap that containes the definition of the UDP services to expose.
|
2016-04-10 23:02:41 +00:00
|
|
|
The key in the map indicates the external port to be used. The value is the name of the
|
2016-03-29 23:30:44 +00:00
|
|
|
service with the format namespace/serviceName and the port of the service could be a number of the
|
|
|
|
name of the port.`)
|
|
|
|
|
2016-02-22 00:13:08 +00:00
|
|
|
resyncPeriod = flags.Duration("sync-period", 30*time.Second,
|
|
|
|
`Relist and confirm cloud resources this often.`)
|
|
|
|
|
|
|
|
watchNamespace = flags.String("watch-namespace", api.NamespaceAll,
|
|
|
|
`Namespace to watch for Ingress. Default is to watch all namespaces`)
|
|
|
|
|
|
|
|
healthzPort = flags.Int("healthz-port", healthPort, "port for healthz endpoint.")
|
2016-03-19 23:29:29 +00:00
|
|
|
|
2016-05-01 17:19:18 +00:00
|
|
|
buildCfg = flags.Bool("dump-nginx-configuration", false, `Returns a ConfigMap with the default nginx conguration.
|
2016-03-19 23:29:29 +00:00
|
|
|
This can be used as a guide to create a custom configuration.`)
|
2016-03-22 16:51:50 +00:00
|
|
|
|
|
|
|
profiling = flags.Bool("profiling", true, `Enable profiling via web interface host:port/debug/pprof/`)
|
2016-07-08 21:20:14 +00:00
|
|
|
|
|
|
|
defSSLCertificate = flags.String("default-ssl-certificate", "", `Name of the secret that contains a SSL
|
|
|
|
certificate to be used as default for a HTTPS catch-all server`)
|
2016-02-22 00:13:08 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
2016-04-12 01:28:27 +00:00
|
|
|
flags.AddGoFlagSet(flag.CommandLine)
|
2016-02-22 00:13:08 +00:00
|
|
|
flags.Parse(os.Args)
|
2016-04-10 23:02:41 +00:00
|
|
|
clientConfig := kubectl_util.DefaultClientConfig(flags)
|
2016-02-22 00:13:08 +00:00
|
|
|
|
2016-04-06 14:46:06 +00:00
|
|
|
glog.Infof("Using build: %v - %v", gitRepo, version)
|
|
|
|
|
2016-03-19 23:29:29 +00:00
|
|
|
if *buildCfg {
|
|
|
|
fmt.Printf("Example of ConfigMap to customize NGINX configuration:\n%v", nginx.ConfigMapAsString())
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
2016-02-22 00:13:08 +00:00
|
|
|
if *defaultSvc == "" {
|
2016-04-10 23:02:41 +00:00
|
|
|
glog.Fatalf("Please specify --default-backend-service")
|
2016-02-22 00:13:08 +00:00
|
|
|
}
|
|
|
|
|
2016-08-02 14:46:35 +00:00
|
|
|
config, err := clientConfig.ClientConfig()
|
|
|
|
if err != nil {
|
|
|
|
glog.Fatalf("error connecting to the client: %v", err)
|
2016-04-10 23:02:41 +00:00
|
|
|
}
|
2016-08-02 14:46:35 +00:00
|
|
|
kubeClient, err := unversioned.New(config)
|
|
|
|
|
2016-02-22 00:13:08 +00:00
|
|
|
if err != nil {
|
|
|
|
glog.Fatalf("failed to create client: %v", err)
|
|
|
|
}
|
|
|
|
|
2016-08-02 14:46:35 +00:00
|
|
|
runtimePodInfo, err := getPodDetails(kubeClient)
|
|
|
|
if err != nil {
|
|
|
|
runtimePodInfo = &podInfo{NodeIP: "127.0.0.1"}
|
|
|
|
glog.Warningf("unexpected error getting runtime information: %v", err)
|
2016-03-19 23:29:29 +00:00
|
|
|
}
|
2016-04-10 23:02:41 +00:00
|
|
|
if err := isValidService(kubeClient, *defaultSvc); err != nil {
|
2016-03-19 20:17:58 +00:00
|
|
|
glog.Fatalf("no service with name %v found: %v", *defaultSvc, err)
|
2016-02-25 17:54:12 +00:00
|
|
|
}
|
2016-04-10 23:02:41 +00:00
|
|
|
glog.Infof("Validated %v as the default backend", *defaultSvc)
|
2016-02-22 00:13:08 +00:00
|
|
|
|
2016-06-23 14:38:08 +00:00
|
|
|
if *nxgConfigMap != "" {
|
|
|
|
_, _, err := parseNsName(*nxgConfigMap)
|
|
|
|
if err != nil {
|
|
|
|
glog.Fatalf("configmap error: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-18 21:08:00 +00:00
|
|
|
lbc, err := newLoadBalancerController(kubeClient, *resyncPeriod,
|
|
|
|
*defaultSvc, *watchNamespace, *nxgConfigMap, *tcpConfigMapName,
|
|
|
|
*udpConfigMapName, *defSSLCertificate, runtimePodInfo)
|
2016-02-22 00:13:08 +00:00
|
|
|
if err != nil {
|
|
|
|
glog.Fatalf("%v", err)
|
|
|
|
}
|
|
|
|
|
2016-03-22 16:51:50 +00:00
|
|
|
go registerHandlers(lbc)
|
2016-03-30 23:12:37 +00:00
|
|
|
go handleSigterm(lbc)
|
2016-03-22 16:51:50 +00:00
|
|
|
|
2016-02-22 00:13:08 +00:00
|
|
|
lbc.Run()
|
|
|
|
|
|
|
|
for {
|
2016-03-15 02:29:13 +00:00
|
|
|
glog.Infof("Handled quit, awaiting pod deletion")
|
2016-02-22 00:13:08 +00:00
|
|
|
time.Sleep(30 * time.Second)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-06 14:46:06 +00:00
|
|
|
// podInfo contains runtime information about the pod
|
|
|
|
type podInfo struct {
|
|
|
|
PodName string
|
2016-02-22 00:13:08 +00:00
|
|
|
PodNamespace string
|
2016-04-06 14:46:06 +00:00
|
|
|
NodeIP string
|
2016-02-22 00:13:08 +00:00
|
|
|
}
|
2016-03-22 16:51:50 +00:00
|
|
|
|
|
|
|
func registerHandlers(lbc *loadBalancerController) {
|
|
|
|
mux := http.NewServeMux()
|
|
|
|
healthz.InstallHandler(mux, lbc.nginx)
|
|
|
|
|
2016-04-06 14:46:06 +00:00
|
|
|
http.HandleFunc("/build", func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
w.WriteHeader(http.StatusOK)
|
2016-05-31 20:49:20 +00:00
|
|
|
fmt.Fprintf(w, "build: %v - %v", gitRepo, version)
|
2016-04-06 14:46:06 +00:00
|
|
|
})
|
|
|
|
|
2016-03-22 16:51:50 +00:00
|
|
|
http.HandleFunc("/stop", func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
lbc.Stop()
|
|
|
|
})
|
|
|
|
|
|
|
|
if *profiling {
|
|
|
|
mux.HandleFunc("/debug/pprof/", pprof.Index)
|
|
|
|
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
|
|
|
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
|
|
|
}
|
|
|
|
|
|
|
|
server := &http.Server{
|
|
|
|
Addr: fmt.Sprintf(":%v", *healthzPort),
|
|
|
|
Handler: mux,
|
|
|
|
}
|
|
|
|
glog.Fatal(server.ListenAndServe())
|
|
|
|
}
|
2016-03-30 23:12:37 +00:00
|
|
|
|
|
|
|
func handleSigterm(lbc *loadBalancerController) {
|
|
|
|
signalChan := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(signalChan, syscall.SIGTERM)
|
|
|
|
<-signalChan
|
|
|
|
glog.Infof("Received SIGTERM, shutting down")
|
|
|
|
|
|
|
|
exitCode := 0
|
|
|
|
if err := lbc.Stop(); err != nil {
|
|
|
|
glog.Infof("Error during shutdown %v", err)
|
|
|
|
exitCode = 1
|
|
|
|
}
|
2016-05-24 17:27:37 +00:00
|
|
|
|
2016-03-30 23:12:37 +00:00
|
|
|
glog.Infof("Exiting with %v", exitCode)
|
|
|
|
os.Exit(exitCode)
|
|
|
|
}
|