2015-02-02 21:54:52 +00:00
/ *
2015-05-01 16:19:44 +00:00
Copyright 2014 The Kubernetes Authors All rights reserved .
2015-02-02 21:54:52 +00:00
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 .
* /
2015-02-07 21:55:35 +00:00
// Package app does all of the work necessary to configure and run a
// Kubernetes app process.
package app
2015-02-02 21:54:52 +00:00
import (
2015-08-20 17:01:37 +00:00
"errors"
2015-02-02 21:54:52 +00:00
"net"
"net/http"
2015-03-30 19:00:21 +00:00
_ "net/http/pprof"
2015-02-02 21:54:52 +00:00
"strconv"
"time"
2015-08-09 18:07:36 +00:00
"k8s.io/kubernetes/pkg/api"
2015-09-03 21:43:19 +00:00
"k8s.io/kubernetes/pkg/client/record"
2015-08-13 19:01:50 +00:00
client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
2015-08-04 00:28:33 +00:00
"k8s.io/kubernetes/pkg/kubelet/qos"
2015-08-11 02:47:13 +00:00
"k8s.io/kubernetes/pkg/proxy"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/proxy/config"
2015-08-11 02:47:13 +00:00
"k8s.io/kubernetes/pkg/proxy/iptables"
2015-08-08 00:07:15 +00:00
"k8s.io/kubernetes/pkg/proxy/userspace"
2015-08-09 18:07:36 +00:00
"k8s.io/kubernetes/pkg/types"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/util"
2015-08-14 16:36:15 +00:00
utildbus "k8s.io/kubernetes/pkg/util/dbus"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/util/exec"
2015-08-11 02:47:13 +00:00
utiliptables "k8s.io/kubernetes/pkg/util/iptables"
2015-08-09 18:07:36 +00:00
nodeutil "k8s.io/kubernetes/pkg/util/node"
2015-08-04 00:28:33 +00:00
"k8s.io/kubernetes/pkg/util/oom"
2015-02-02 21:54:52 +00:00
"github.com/golang/glog"
"github.com/spf13/pflag"
)
// ProxyServer contains configures and runs a Kubernetes proxy server
type ProxyServer struct {
2015-08-11 02:47:13 +00:00
BindAddress net . IP
HealthzPort int
HealthzBindAddress net . IP
OOMScoreAdj int
ResourceContainer string
Master string
Kubeconfig string
PortRange util . PortRange
Recorder record . EventRecorder
HostnameOverride string
ForceUserspaceProxy bool
2015-08-13 00:33:05 +00:00
SyncPeriod time . Duration
nodeRef * api . ObjectReference // Reference to this node.
2015-08-20 18:39:01 +00:00
MasqueradeAll bool
2015-08-20 17:01:37 +00:00
CleanupAndExit bool
2015-02-02 21:54:52 +00:00
}
// NewProxyServer creates a new ProxyServer object with default parameters
func NewProxyServer ( ) * ProxyServer {
return & ProxyServer {
2015-08-05 19:42:13 +00:00
BindAddress : net . ParseIP ( "0.0.0.0" ) ,
2015-03-26 06:49:20 +00:00
HealthzPort : 10249 ,
2015-08-05 19:42:13 +00:00
HealthzBindAddress : net . ParseIP ( "127.0.0.1" ) ,
2015-08-04 00:28:33 +00:00
OOMScoreAdj : qos . KubeProxyOomScoreAdj ,
2015-04-14 16:49:13 +00:00
ResourceContainer : "/kube-proxy" ,
2015-08-13 00:33:05 +00:00
SyncPeriod : 5 * time . Second ,
2015-02-02 21:54:52 +00:00
}
}
// AddFlags adds flags for a specific ProxyServer to the specified FlagSet
func ( s * ProxyServer ) AddFlags ( fs * pflag . FlagSet ) {
2015-08-05 19:42:13 +00:00
fs . IPVar ( & s . BindAddress , "bind-address" , s . BindAddress , "The IP address for the proxy server to serve on (set to 0.0.0.0 for all interfaces)" )
2015-04-17 07:18:07 +00:00
fs . StringVar ( & s . Master , "master" , s . Master , "The address of the Kubernetes API server (overrides any value in kubeconfig)" )
2015-04-24 06:10:33 +00:00
fs . IntVar ( & s . HealthzPort , "healthz-port" , s . HealthzPort , "The port to bind the health check server. Use 0 to disable." )
2015-08-05 19:42:13 +00:00
fs . IPVar ( & s . HealthzBindAddress , "healthz-bind-address" , s . HealthzBindAddress , "The IP address for the health check server to serve on, defaulting to 127.0.0.1 (set to 0.0.0.0 for all interfaces)" )
2015-08-13 23:52:01 +00:00
fs . IntVar ( & s . OOMScoreAdj , "oom-score-adj" , s . OOMScoreAdj , "The oom-score-adj value for kube-proxy process. Values must be within the range [-1000, 1000]" )
2015-04-24 06:10:33 +00:00
fs . StringVar ( & s . ResourceContainer , "resource-container" , s . ResourceContainer , "Absolute name of the resource-only container to create and run the Kube-proxy in (Default: /kube-proxy)." )
2015-05-12 03:44:13 +00:00
fs . StringVar ( & s . Kubeconfig , "kubeconfig" , s . Kubeconfig , "Path to kubeconfig file with authorization information (the master location is set by the master flag)." )
2015-05-18 17:11:25 +00:00
fs . Var ( & s . PortRange , "proxy-port-range" , "Range of host ports (beginPort-endPort, inclusive) that may be consumed in order to proxy service traffic. If unspecified (0-0) then ports will be randomly chosen." )
2015-08-09 18:07:36 +00:00
fs . StringVar ( & s . HostnameOverride , "hostname-override" , s . HostnameOverride , "If non-empty, will use this string as identification instead of the actual hostname." )
2015-08-11 02:47:13 +00:00
fs . BoolVar ( & s . ForceUserspaceProxy , "legacy-userspace-proxy" , true , "Use the legacy userspace proxy (instead of the pure iptables proxy)." )
2015-08-13 00:33:05 +00:00
fs . DurationVar ( & s . SyncPeriod , "iptables-sync-period" , 5 * time . Second , "How often iptables rules are refreshed (e.g. '5s', '1m', '2h22m'). Must be greater than 0." )
2015-08-20 18:39:01 +00:00
fs . BoolVar ( & s . MasqueradeAll , "masquerade-all" , false , "If using the pure iptables proxy, SNAT everything" )
2015-08-20 17:01:37 +00:00
fs . BoolVar ( & s . CleanupAndExit , "cleanup-iptables" , false , "If true cleanup iptables rules and exit." )
2015-02-02 21:54:52 +00:00
}
2015-08-20 17:01:37 +00:00
// Run runs the specified ProxyServer. This should never exit (unless CleanupAndExit is set).
2015-02-02 21:54:52 +00:00
func ( s * ProxyServer ) Run ( _ [ ] string ) error {
2015-08-20 17:01:37 +00:00
protocol := utiliptables . ProtocolIpv4
if s . BindAddress . To4 ( ) == nil {
protocol = utiliptables . ProtocolIpv6
}
// remove iptables rules and exit
if s . CleanupAndExit {
execer := exec . New ( )
2015-08-14 16:36:15 +00:00
dbus := utildbus . New ( )
ipt := utiliptables . New ( execer , dbus , protocol )
2015-08-20 17:01:37 +00:00
encounteredError := userspace . CleanupLeftovers ( ipt )
encounteredError = iptables . CleanupLeftovers ( ipt ) || encounteredError
if encounteredError {
return errors . New ( "Encountered an error while tearing down rules." )
}
return nil
}
2015-04-14 16:49:13 +00:00
// TODO(vmarmol): Use container config for this.
2015-08-04 00:28:33 +00:00
oomAdjuster := oom . NewOomAdjuster ( )
if err := oomAdjuster . ApplyOomScoreAdj ( 0 , s . OOMScoreAdj ) ; err != nil {
2015-05-14 20:03:30 +00:00
glog . V ( 2 ) . Info ( err )
2015-02-02 21:54:52 +00:00
}
2015-04-14 16:49:13 +00:00
// Run in its own container.
if err := util . RunInResourceContainer ( s . ResourceContainer ) ; err != nil {
glog . Warningf ( "Failed to start in resource-only container %q: %v" , s . ResourceContainer , err )
} else {
2015-05-14 20:03:30 +00:00
glog . V ( 2 ) . Infof ( "Running in resource-only container %q" , s . ResourceContainer )
2015-04-14 16:49:13 +00:00
}
2015-08-09 18:07:36 +00:00
// define api config source
if s . Kubeconfig == "" && s . Master == "" {
glog . Warningf ( "Neither --kubeconfig nor --master was specified. Using default API client. This might not work." )
}
// This creates a client, first loading any specified kubeconfig
// file, and then overriding the Master flag, if non-empty.
kubeconfig , err := clientcmd . NewNonInteractiveDeferredLoadingClientConfig (
& clientcmd . ClientConfigLoadingRules { ExplicitPath : s . Kubeconfig } ,
& clientcmd . ConfigOverrides { ClusterInfo : clientcmdapi . Cluster { Server : s . Master } } ) . ClientConfig ( )
if err != nil {
return err
}
client , err := client . New ( kubeconfig )
if err != nil {
glog . Fatalf ( "Invalid API configuration: %v" , err )
}
// Add event recorder
Hostname := nodeutil . GetHostname ( s . HostnameOverride )
eventBroadcaster := record . NewBroadcaster ( )
s . Recorder = eventBroadcaster . NewRecorder ( api . EventSource { Component : "kube-proxy" , Host : Hostname } )
eventBroadcaster . StartRecordingToSink ( client . Events ( "" ) )
s . nodeRef = & api . ObjectReference {
Kind : "Node" ,
Name : Hostname ,
UID : types . UID ( Hostname ) ,
Namespace : "" ,
}
2015-02-02 21:54:52 +00:00
serviceConfig := config . NewServiceConfig ( )
endpointsConfig := config . NewEndpointsConfig ( )
2015-08-11 02:47:13 +00:00
var proxier proxy . ProxyProvider
var endpointsHandler config . EndpointsConfigHandler
2015-08-14 16:36:15 +00:00
execer := exec . New ( )
dbus := utildbus . New ( )
ipt := utiliptables . New ( execer , dbus , protocol )
2015-09-08 23:54:07 +00:00
shouldUseIptables := false
if ! s . ForceUserspaceProxy {
var err error
// guaranteed false on error, error only necessary for debugging
shouldUseIptables , err = iptables . ShouldUseIptablesProxier ( )
if err != nil {
glog . Errorf ( "Can't determine whether to use iptables proxy, using userspace proxier: %v" , err )
}
2015-08-11 02:47:13 +00:00
}
2015-09-08 23:54:07 +00:00
if shouldUseIptables {
2015-08-11 02:47:13 +00:00
glog . V ( 2 ) . Info ( "Using iptables Proxier." )
2015-08-20 17:01:37 +00:00
proxierIptables , err := iptables . NewProxier ( ipt , execer , s . SyncPeriod , s . MasqueradeAll )
2015-08-11 02:47:13 +00:00
if err != nil {
glog . Fatalf ( "Unable to create proxier: %v" , err )
}
proxier = proxierIptables
endpointsHandler = proxierIptables
2015-08-20 17:01:37 +00:00
// No turning back. Remove artifacts that might still exist from the userspace Proxier.
glog . V ( 2 ) . Info ( "Tearing down userspace rules. Errors here are acceptable." )
userspace . CleanupLeftovers ( ipt )
2015-08-11 02:47:13 +00:00
} else {
glog . V ( 2 ) . Info ( "Using userspace Proxier." )
// This is a proxy.LoadBalancer which NewProxier needs but has methods we don't need for
// our config.EndpointsConfigHandler.
loadBalancer := userspace . NewLoadBalancerRR ( )
// set EndpointsConfigHandler to our loadBalancer
endpointsHandler = loadBalancer
2015-08-20 17:01:37 +00:00
proxierUserspace , err := userspace . NewProxier ( loadBalancer , s . BindAddress , ipt , s . PortRange , s . SyncPeriod )
2015-08-11 02:47:13 +00:00
if err != nil {
2015-09-08 18:03:45 +00:00
glog . Fatalf ( "Unable to create proxier: %v" , err )
2015-08-11 02:47:13 +00:00
}
proxier = proxierUserspace
2015-08-20 17:01:37 +00:00
// Remove artifacts from the pure-iptables Proxier.
glog . V ( 2 ) . Info ( "Tearing down pure-iptables proxy rules. Errors here are acceptable." )
iptables . CleanupLeftovers ( ipt )
2015-02-02 21:54:52 +00:00
}
2015-09-08 13:33:42 +00:00
// Birth Cry after the birth is successful
s . birthCry ( )
2015-02-02 21:54:52 +00:00
// Wire proxier to handle changes to services
serviceConfig . RegisterHandler ( proxier )
2015-08-11 02:47:13 +00:00
// And wire endpointsHandler to handle changes to endpoints to services
endpointsConfig . RegisterHandler ( endpointsHandler )
2015-02-02 21:54:52 +00:00
// Note: RegisterHandler() calls need to happen before creation of Sources because sources
// only notify on changes, and the initial update (on process start) may be lost if no handlers
// are registered yet.
2015-04-17 07:18:07 +00:00
config . NewSourceAPI (
2015-06-28 19:28:10 +00:00
client ,
2015-04-17 07:18:07 +00:00
30 * time . Second ,
serviceConfig . Channel ( "api" ) ,
endpointsConfig . Channel ( "api" ) ,
)
2015-02-02 21:54:52 +00:00
if s . HealthzPort > 0 {
2015-08-24 01:59:15 +00:00
go util . Until ( func ( ) {
2015-03-26 06:49:20 +00:00
err := http . ListenAndServe ( s . HealthzBindAddress . String ( ) + ":" + strconv . Itoa ( s . HealthzPort ) , nil )
2015-02-02 21:54:52 +00:00
if err != nil {
glog . Errorf ( "Starting health server failed: %v" , err )
}
2015-08-24 01:59:15 +00:00
} , 5 * time . Second , util . NeverStop )
2015-02-02 21:54:52 +00:00
}
2015-08-14 16:38:43 +00:00
ipt . AddReloadFunc ( proxier . Sync )
2015-02-02 21:54:52 +00:00
// Just loop forever for now...
proxier . SyncLoop ( )
return nil
}
2015-08-09 18:07:36 +00:00
func ( s * ProxyServer ) birthCry ( ) {
s . Recorder . Eventf ( s . nodeRef , "Starting" , "Starting kube-proxy." )
}