2014-10-27 17:04:39 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2015 The Kubernetes Authors .
2014-10-27 17:04:39 +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:30:53 +00:00
// Package app makes it easy to create a kubelet server for various contexts.
package app
2014-10-27 17:04:39 +00:00
import (
2015-04-01 23:19:17 +00:00
"crypto/tls"
2016-05-05 22:24:54 +00:00
"errors"
2014-10-27 17:04:39 +00:00
"fmt"
2016-05-20 22:52:35 +00:00
"io/ioutil"
2015-02-02 21:30:31 +00:00
"math/rand"
2014-10-27 17:04:39 +00:00
"net"
2015-03-30 21:09:50 +00:00
"net/http"
2015-04-17 06:07:00 +00:00
_ "net/http/pprof"
2017-04-07 23:43:57 +00:00
"net/url"
2016-08-06 00:08:58 +00:00
"os"
2015-04-01 23:19:17 +00:00
"path"
2015-03-30 21:09:50 +00:00
"strconv"
2015-03-24 23:09:16 +00:00
"strings"
2014-10-27 17:04:39 +00:00
"time"
2015-12-24 23:46:56 +00:00
"github.com/golang/glog"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
2017-02-10 05:14:10 +00:00
"k8s.io/apimachinery/pkg/api/resource"
2017-01-11 14:09:48 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
2017-02-09 20:13:28 +00:00
"k8s.io/apimachinery/pkg/util/sets"
2017-01-11 14:09:48 +00:00
"k8s.io/apimachinery/pkg/util/wait"
2017-01-20 13:05:41 +00:00
"k8s.io/apiserver/pkg/server/healthz"
utilfeature "k8s.io/apiserver/pkg/util/feature"
clientgoclientset "k8s.io/client-go/kubernetes"
2017-01-30 18:39:54 +00:00
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
clientv1 "k8s.io/client-go/pkg/api/v1"
2017-01-19 18:27:59 +00:00
restclient "k8s.io/client-go/rest"
2017-01-20 18:06:17 +00:00
clientauth "k8s.io/client-go/tools/auth"
"k8s.io/client-go/tools/clientcmd"
2017-01-18 14:57:11 +00:00
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
2017-01-30 18:39:54 +00:00
"k8s.io/client-go/tools/record"
2017-01-23 18:37:22 +00:00
certutil "k8s.io/client-go/util/cert"
2015-12-24 23:46:56 +00:00
"k8s.io/kubernetes/cmd/kubelet/app/options"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/api"
2016-11-18 20:50:58 +00:00
"k8s.io/kubernetes/pkg/api/v1"
2016-03-07 19:55:09 +00:00
"k8s.io/kubernetes/pkg/apis/componentconfig"
2016-09-06 16:55:36 +00:00
componentconfigv1alpha1 "k8s.io/kubernetes/pkg/apis/componentconfig/v1alpha1"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/capabilities"
"k8s.io/kubernetes/pkg/client/chaosclient"
2017-01-10 08:49:34 +00:00
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
2015-12-24 23:46:56 +00:00
"k8s.io/kubernetes/pkg/cloudprovider"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/credentialprovider"
2017-01-20 13:05:41 +00:00
"k8s.io/kubernetes/pkg/features"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/kubelet"
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
2015-10-10 00:09:53 +00:00
"k8s.io/kubernetes/pkg/kubelet/cm"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/kubelet/config"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
2017-04-07 23:43:57 +00:00
"k8s.io/kubernetes/pkg/kubelet/dockershim"
2017-05-03 17:46:35 +00:00
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
2017-04-07 23:43:57 +00:00
dockerremote "k8s.io/kubernetes/pkg/kubelet/dockershim/remote"
2017-02-10 05:14:10 +00:00
"k8s.io/kubernetes/pkg/kubelet/eviction"
evictionapi "k8s.io/kubernetes/pkg/kubelet/eviction/api"
2015-12-10 20:14:26 +00:00
"k8s.io/kubernetes/pkg/kubelet/server"
2017-04-07 23:43:57 +00:00
"k8s.io/kubernetes/pkg/kubelet/server/streaming"
2015-10-09 17:24:31 +00:00
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
2016-02-02 02:09:02 +00:00
"k8s.io/kubernetes/pkg/util/configz"
2016-01-28 02:31:15 +00:00
"k8s.io/kubernetes/pkg/util/flock"
2016-07-13 23:11:12 +00:00
kubeio "k8s.io/kubernetes/pkg/util/io"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/util/mount"
nodeutil "k8s.io/kubernetes/pkg/util/node"
2015-08-04 00:28:33 +00:00
"k8s.io/kubernetes/pkg/util/oom"
2016-07-03 11:18:03 +00:00
"k8s.io/kubernetes/pkg/util/rlimit"
2016-03-30 16:54:20 +00:00
"k8s.io/kubernetes/pkg/version"
2014-10-27 17:04:39 +00:00
)
2017-02-10 05:14:10 +00:00
const (
// Kubelet component name
componentKubelet = "kubelet"
)
2015-10-12 14:33:39 +00:00
// NewKubeletCommand creates a *cobra.Command object with default parameters
func NewKubeletCommand ( ) * cobra . Command {
2015-12-24 23:46:56 +00:00
s := options . NewKubeletServer ( )
2015-10-12 14:33:39 +00:00
s . AddFlags ( pflag . CommandLine )
cmd := & cobra . Command {
2017-02-10 05:14:10 +00:00
Use : componentKubelet ,
2015-10-12 14:33:39 +00:00
Long : ` The kubelet is the primary "node agent" that runs on each
node . The kubelet works in terms of a PodSpec . A PodSpec is a YAML or JSON object
that describes a pod . The kubelet takes a set of PodSpecs that are provided through
various mechanisms ( primarily through the apiserver ) and ensures that the containers
2016-08-11 08:00:13 +00:00
described in those PodSpecs are running and healthy . The kubelet doesn ' t manage
containers which were not created by Kubernetes .
2015-10-12 14:33:39 +00:00
Other than from an PodSpec from the apiserver , there are three ways that a container
manifest can be provided to the Kubelet .
2016-12-06 01:46:54 +00:00
File : Path passed as a flag on the command line . Files under this path will be monitored
periodically for updates . The monitoring period is 20 s by default and is configurable
via a flag .
2015-10-12 14:33:39 +00:00
HTTP endpoint : HTTP endpoint passed as a parameter on the command line . This endpoint
is checked every 20 seconds ( also configurable with a flag ) .
HTTP server : The kubelet can also listen for HTTP and respond to a simple API
( underspec ' d currently ) to submit a new manifest . ` ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
} ,
}
return cmd
}
2016-07-13 23:11:12 +00:00
// UnsecuredKubeletDeps returns a KubeletDeps suitable for being run, or an error if the server setup
2015-09-29 03:32:20 +00:00
// is not valid. It will not start any background processes, and does not include authentication/authorization
2016-07-13 23:11:12 +00:00
func UnsecuredKubeletDeps ( s * options . KubeletServer ) ( * kubelet . KubeletDeps , error ) {
// Initialize the TLS Options
2017-01-18 19:34:49 +00:00
tlsOptions , err := InitializeTLS ( & s . KubeletFlags , & s . KubeletConfiguration )
2015-08-10 08:14:01 +00:00
if err != nil {
return nil , err
}
2016-11-04 23:13:07 +00:00
mounter := mount . New ( s . ExperimentalMounterPath )
2016-07-13 23:11:12 +00:00
var writer kubeio . Writer = & kubeio . StdWriter { }
2015-07-01 19:02:30 +00:00
if s . Containerized {
glog . V ( 2 ) . Info ( "Running kubelet in containerized mode (experimental)" )
mounter = mount . NewNsenterMounter ( )
2016-07-13 23:11:12 +00:00
writer = & kubeio . NsenterWriter { }
}
2017-05-03 17:46:35 +00:00
var dockerClient libdocker . Interface
2016-08-12 16:56:50 +00:00
if s . ContainerRuntime == "docker" {
2017-05-03 17:46:35 +00:00
dockerClient = libdocker . ConnectToDockerOrDie ( s . DockerEndpoint , s . RuntimeRequestTimeout . Duration ,
2016-12-08 01:25:26 +00:00
s . ImagePullProgressDeadline . Duration )
2016-08-12 16:56:50 +00:00
} else {
dockerClient = nil
}
2016-07-13 23:11:12 +00:00
return & kubelet . KubeletDeps {
2017-01-04 20:13:06 +00:00
Auth : nil , // default does not enforce auth[nz]
CAdvisorInterface : nil , // cadvisor.New launches background processes (bg http.ListenAndServe, and some bg cleaners), not set here
Cloud : nil , // cloud provider might start background processes
ContainerManager : nil ,
DockerClient : dockerClient ,
KubeClient : nil ,
ExternalKubeClient : nil ,
Mounter : mounter ,
NetworkPlugins : ProbeNetworkPlugins ( s . NetworkPluginDir , s . CNIConfDir , s . CNIBinDir ) ,
OOMAdjuster : oom . NewOOMAdjuster ( ) ,
OSInterface : kubecontainer . RealOS { } ,
Writer : writer ,
VolumePlugins : ProbeVolumePlugins ( s . VolumePluginDir ) ,
TLSOptions : tlsOptions ,
2015-07-01 19:02:30 +00:00
} , nil
}
2016-08-24 16:03:16 +00:00
func getKubeClient ( s * options . KubeletServer ) ( * clientset . Clientset , error ) {
clientConfig , err := CreateAPIServerClientConfig ( s )
if err == nil {
kubeClient , err := clientset . NewForConfig ( clientConfig )
if err != nil {
return nil , err
}
return kubeClient , nil
}
return nil , err
}
// Tries to download the kubelet-<node-name> configmap from "kube-system" namespace via the API server and returns a JSON string or error
2016-07-13 23:11:12 +00:00
func getRemoteKubeletConfig ( s * options . KubeletServer , kubeDeps * kubelet . KubeletDeps ) ( string , error ) {
2016-08-24 16:03:16 +00:00
// TODO(mtaufen): should probably cache clientset and pass into this function rather than regenerate on every request
kubeClient , err := getKubeClient ( s )
if err != nil {
return "" , err
}
2016-11-18 20:50:58 +00:00
configmap , err := func ( ) ( * v1 . ConfigMap , error ) {
2016-07-16 06:10:29 +00:00
var nodename types . NodeName
2016-08-24 16:03:16 +00:00
hostname := nodeutil . GetHostname ( s . HostnameOverride )
2016-07-13 23:11:12 +00:00
if kubeDeps != nil && kubeDeps . Cloud != nil {
instances , ok := kubeDeps . Cloud . Instances ( )
2016-08-24 16:03:16 +00:00
if ! ok {
2016-12-03 07:17:18 +00:00
err = fmt . Errorf ( "failed to get instances from cloud provider, can't determine nodename" )
2016-08-24 16:03:16 +00:00
return nil , err
}
nodename , err = instances . CurrentNodeName ( hostname )
if err != nil {
err = fmt . Errorf ( "error fetching current instance name from cloud provider: %v" , err )
return nil , err
}
// look for kubelet-<node-name> configmap from "kube-system"
2016-12-07 13:26:33 +00:00
configmap , err := kubeClient . CoreV1Client . ConfigMaps ( "kube-system" ) . Get ( fmt . Sprintf ( "kubelet-%s" , nodename ) , metav1 . GetOptions { } )
2016-08-24 16:03:16 +00:00
if err != nil {
return nil , err
}
return configmap , nil
}
// No cloud provider yet, so can't get the nodename via Cloud.Instances().CurrentNodeName(hostname), try just using the hostname
2016-12-07 13:26:33 +00:00
configmap , err := kubeClient . CoreV1Client . ConfigMaps ( "kube-system" ) . Get ( fmt . Sprintf ( "kubelet-%s" , hostname ) , metav1 . GetOptions { } )
2016-08-24 16:03:16 +00:00
if err != nil {
return nil , fmt . Errorf ( "cloud provider was nil, and attempt to use hostname to find config resulted in: %v" , err )
}
return configmap , nil
} ( )
if err != nil {
return "" , err
}
// When we create the KubeletConfiguration configmap, we put a json string
// representation of the config in a `kubelet.config` key.
jsonstr , ok := configmap . Data [ "kubelet.config" ]
if ! ok {
return "" , fmt . Errorf ( "KubeletConfiguration configmap did not contain a value with key `kubelet.config`" )
}
return jsonstr , nil
}
func startKubeletConfigSyncLoop ( s * options . KubeletServer , currentKC string ) {
glog . Infof ( "Starting Kubelet configuration sync loop" )
go func ( ) {
wait . PollInfinite ( 30 * time . Second , func ( ) ( bool , error ) {
glog . Infof ( "Checking API server for new Kubelet configuration." )
remoteKC , err := getRemoteKubeletConfig ( s , nil )
if err == nil {
// Detect new config by comparing with the last JSON string we extracted.
if remoteKC != currentKC {
glog . Info ( "Found new Kubelet configuration via API server, restarting!" )
os . Exit ( 0 )
}
} else {
glog . Infof ( "Did not find a configuration for this Kubelet via API server: %v" , err )
}
return false , nil // Always return (false, nil) so we poll forever.
} )
} ( )
}
// Try to check for config on the API server, return that config if we get it, and start
// a background thread that checks for updates to configs.
func initKubeletConfigSync ( s * options . KubeletServer ) ( * componentconfig . KubeletConfiguration , error ) {
jsonstr , err := getRemoteKubeletConfig ( s , nil )
if err == nil {
// We will compare future API server config against the config we just got (jsonstr):
startKubeletConfigSyncLoop ( s , jsonstr )
// Convert json from API server to external type struct, and convert that to internal type struct
2016-09-06 16:55:36 +00:00
extKC := componentconfigv1alpha1 . KubeletConfiguration { }
2016-08-24 16:03:16 +00:00
err := runtime . DecodeInto ( api . Codecs . UniversalDecoder ( ) , [ ] byte ( jsonstr ) , & extKC )
if err != nil {
return nil , err
}
2016-09-30 21:39:47 +00:00
api . Scheme . Default ( & extKC )
2016-08-24 16:03:16 +00:00
kc := componentconfig . KubeletConfiguration { }
err = api . Scheme . Convert ( & extKC , & kc , nil )
if err != nil {
return nil , err
}
return & kc , nil
} else {
// Couldn't get a configuration from the API server yet.
// Restart as soon as anything comes back from the API server.
startKubeletConfigSyncLoop ( s , "" )
return nil , err
}
}
2016-07-13 23:11:12 +00:00
// Run runs the specified KubeletServer with the given KubeletDeps. This should never exit.
// The kubeDeps argument may be nil - if so, it is initialized from the settings on KubeletServer.
// Otherwise, the caller is assumed to have set up the KubeletDeps object and a default one will
// not be generated.
func Run ( s * options . KubeletServer , kubeDeps * kubelet . KubeletDeps ) error {
if err := run ( s , kubeDeps ) ; err != nil {
2016-08-17 18:18:17 +00:00
return fmt . Errorf ( "failed to run Kubelet: %v" , err )
2016-02-10 01:55:51 +00:00
}
2016-08-17 18:18:17 +00:00
return nil
2016-02-10 01:55:51 +00:00
}
2016-08-11 18:59:59 +00:00
func checkPermissions ( ) error {
if uid := os . Getuid ( ) ; uid != 0 {
return fmt . Errorf ( "Kubelet needs to run as uid `0`. It is being run as %d" , uid )
}
// TODO: Check if kubelet is running in the `initial` user namespace.
// http://man7.org/linux/man-pages/man7/user_namespaces.7.html
return nil
}
2016-08-24 16:03:16 +00:00
func setConfigz ( cz * configz . Config , kc * componentconfig . KubeletConfiguration ) {
2016-09-06 16:55:36 +00:00
tmp := componentconfigv1alpha1 . KubeletConfiguration { }
2016-08-24 16:03:16 +00:00
api . Scheme . Convert ( kc , & tmp , nil )
cz . Set ( tmp )
}
func initConfigz ( kc * componentconfig . KubeletConfiguration ) ( * configz . Config , error ) {
cz , err := configz . New ( "componentconfig" )
if err == nil {
setConfigz ( cz , kc )
} else {
glog . Errorf ( "unable to register configz: %s" , err )
}
return cz , err
}
2017-02-10 05:14:10 +00:00
// validateConfig validates configuration of Kubelet and returns an error is the input configuration is invalid.
func validateConfig ( s * options . KubeletServer ) error {
if ! s . CgroupsPerQOS && len ( s . EnforceNodeAllocatable ) > 0 {
return fmt . Errorf ( "Node Allocatable enforcement is not supported unless Cgroups Per QOS feature is turned on" )
}
if s . SystemCgroups != "" && s . CgroupRoot == "" {
return fmt . Errorf ( "invalid configuration: system container was specified and cgroup root was not specified" )
}
for _ , val := range s . EnforceNodeAllocatable {
switch val {
case cm . NodeAllocatableEnforcementKey :
case cm . SystemReservedEnforcementKey :
case cm . KubeReservedEnforcementKey :
continue
default :
return fmt . Errorf ( "invalid option %q specified for EnforceNodeAllocatable setting. Valid options are %q, %q or %q" , val , cm . NodeAllocatableEnforcementKey , cm . SystemReservedEnforcementKey , cm . KubeReservedEnforcementKey )
}
}
return nil
}
// makeEventRecorder sets up kubeDeps.Recorder if its nil. Its a no-op otherwise.
func makeEventRecorder ( s * componentconfig . KubeletConfiguration , kubeDeps * kubelet . KubeletDeps , nodeName types . NodeName ) {
if kubeDeps . Recorder != nil {
return
}
eventBroadcaster := record . NewBroadcaster ( )
kubeDeps . Recorder = eventBroadcaster . NewRecorder ( api . Scheme , clientv1 . EventSource { Component : componentKubelet , Host : string ( nodeName ) } )
eventBroadcaster . StartLogging ( glog . V ( 3 ) . Infof )
if kubeDeps . EventClient != nil {
glog . V ( 4 ) . Infof ( "Sending events to api server." )
eventBroadcaster . StartRecordingToSink ( & v1core . EventSinkImpl { Interface : kubeDeps . EventClient . Events ( "" ) } )
} else {
glog . Warning ( "No api server defined - no events will be sent to API server." )
}
}
2016-07-13 23:11:12 +00:00
func run ( s * options . KubeletServer , kubeDeps * kubelet . KubeletDeps ) ( err error ) {
// TODO: this should be replaced by a --standalone flag
2016-09-05 18:50:44 +00:00
standaloneMode := ( len ( s . APIServerList ) == 0 && ! s . RequireKubeConfig )
2016-07-13 23:11:12 +00:00
2016-05-05 22:24:54 +00:00
if s . ExitOnLockContention && s . LockFilePath == "" {
return errors . New ( "cannot exit on lock file contention: no lock file specified" )
}
done := make ( chan struct { } )
2016-01-28 02:31:15 +00:00
if s . LockFilePath != "" {
2016-11-02 09:26:54 +00:00
glog . Infof ( "acquiring file lock on %q" , s . LockFilePath )
2016-01-28 02:31:15 +00:00
if err := flock . Acquire ( s . LockFilePath ) ; err != nil {
2016-08-02 22:13:54 +00:00
return fmt . Errorf ( "unable to acquire file lock on %q: %v" , s . LockFilePath , err )
2016-01-28 02:31:15 +00:00
}
2016-05-05 22:24:54 +00:00
if s . ExitOnLockContention {
glog . Infof ( "watching for inotify events for: %v" , s . LockFilePath )
if err := watchForLockfileContention ( s . LockFilePath , done ) ; err != nil {
return err
}
}
2016-01-28 02:31:15 +00:00
}
2016-08-24 16:03:16 +00:00
2016-08-26 22:06:07 +00:00
// Set feature gates based on the value in KubeletConfiguration
2017-01-20 13:05:41 +00:00
err = utilfeature . DefaultFeatureGate . Set ( s . KubeletConfiguration . FeatureGates )
2016-08-26 22:06:07 +00:00
if err != nil {
return err
}
2016-08-24 16:03:16 +00:00
// Register current configuration with /configz endpoint
cfgz , cfgzErr := initConfigz ( & s . KubeletConfiguration )
2017-01-20 13:05:41 +00:00
if utilfeature . DefaultFeatureGate . Enabled ( features . DynamicKubeletConfig ) {
2016-07-13 23:11:12 +00:00
// Look for config on the API server. If it exists, replace s.KubeletConfiguration
// with it and continue. initKubeletConfigSync also starts the background thread that checks for new config.
2016-08-06 00:08:58 +00:00
2016-07-13 23:11:12 +00:00
// Don't do dynamic Kubelet configuration in runonce mode
if s . RunOnce == false {
remoteKC , err := initKubeletConfigSync ( s )
if err == nil {
// Update s (KubeletServer) with new config from API server
s . KubeletConfiguration = * remoteKC
// Ensure that /configz is up to date with the new config
if cfgzErr != nil {
glog . Errorf ( "was unable to register configz before due to %s, will not be able to set now" , cfgzErr )
} else {
setConfigz ( cfgz , & s . KubeletConfiguration )
2016-08-24 16:03:16 +00:00
}
2016-08-26 22:06:07 +00:00
// Update feature gates from the new config
2017-01-20 13:05:41 +00:00
err = utilfeature . DefaultFeatureGate . Set ( s . KubeletConfiguration . FeatureGates )
2016-08-26 22:06:07 +00:00
if err != nil {
return err
}
2017-01-03 14:05:02 +00:00
} else {
glog . Errorf ( "failed to init dynamic Kubelet configuration sync: %v" , err )
2016-08-24 16:03:16 +00:00
}
}
2016-07-13 23:11:12 +00:00
}
2016-08-24 16:03:16 +00:00
2017-02-10 05:14:10 +00:00
// Validate configuration.
if err := validateConfig ( s ) ; err != nil {
return err
}
2016-07-13 23:11:12 +00:00
if kubeDeps == nil {
2017-01-31 22:34:39 +00:00
var kubeClient clientset . Interface
2017-01-30 18:39:54 +00:00
var eventClient v1core . EventsGetter
2017-01-04 20:13:06 +00:00
var externalKubeClient clientgoclientset . Interface
2016-08-18 04:56:52 +00:00
var cloud cloudprovider . Interface
2017-03-01 17:43:46 +00:00
if ! cloudprovider . IsExternal ( s . CloudProvider ) && s . CloudProvider != componentconfigv1alpha1 . AutoDetectCloudProvider {
2016-08-18 04:56:52 +00:00
cloud , err = cloudprovider . InitCloudProvider ( s . CloudProvider , s . CloudConfigFile )
if err != nil {
return err
}
if cloud == nil {
glog . V ( 2 ) . Infof ( "No cloud provider specified: %q from the config file: %q\n" , s . CloudProvider , s . CloudConfigFile )
} else {
glog . V ( 2 ) . Infof ( "Successfully initialized cloud provider: %q from the config file: %q\n" , s . CloudProvider , s . CloudConfigFile )
}
}
2017-02-10 05:14:10 +00:00
nodeName , err := getNodeName ( cloud , nodeutil . GetHostname ( s . HostnameOverride ) )
if err != nil {
return err
}
2016-08-13 01:06:48 +00:00
if s . BootstrapKubeconfig != "" {
2016-08-18 04:56:52 +00:00
if err := bootstrapClientCert ( s . KubeConfig . Value ( ) , s . BootstrapKubeconfig , s . CertDirectory , nodeName ) ; err != nil {
2016-08-13 01:06:48 +00:00
return err
}
}
2015-12-24 23:46:56 +00:00
clientConfig , err := CreateAPIServerClientConfig ( s )
2015-07-01 19:02:30 +00:00
if err == nil {
2016-08-17 18:18:17 +00:00
kubeClient , err = clientset . NewForConfig ( clientConfig )
2016-07-27 02:02:53 +00:00
if err != nil {
glog . Warningf ( "New kubeClient from clientConfig error: %v" , err )
}
2017-02-02 14:57:58 +00:00
externalKubeClient , err = clientgoclientset . NewForConfig ( clientConfig )
if err != nil {
glog . Warningf ( "New kubeClient from clientConfig error: %v" , err )
}
2015-11-20 17:13:41 +00:00
// make a separate client for events
eventClientConfig := * clientConfig
2016-06-28 14:46:17 +00:00
eventClientConfig . QPS = float32 ( s . EventRecordQPS )
2016-04-27 04:35:14 +00:00
eventClientConfig . Burst = int ( s . EventBurst )
2017-01-30 18:39:54 +00:00
eventClient , err = clientgoclientset . NewForConfig ( & eventClientConfig )
2016-12-03 15:12:52 +00:00
if err != nil {
glog . Warningf ( "Failed to create API Server client: %v" , err )
}
2016-11-24 11:06:17 +00:00
} else {
2016-08-17 18:18:17 +00:00
if s . RequireKubeConfig {
return fmt . Errorf ( "invalid kubeconfig: %v" , err )
}
2016-07-13 23:11:12 +00:00
if standaloneMode {
2016-08-17 18:18:17 +00:00
glog . Warningf ( "No API client: %v" , err )
}
}
2016-07-13 23:11:12 +00:00
kubeDeps , err = UnsecuredKubeletDeps ( s )
2016-08-17 18:18:17 +00:00
if err != nil {
return err
2015-07-01 19:02:30 +00:00
}
2016-08-18 04:56:52 +00:00
2016-07-13 23:11:12 +00:00
kubeDeps . Cloud = cloud
kubeDeps . KubeClient = kubeClient
2017-01-04 20:13:06 +00:00
kubeDeps . ExternalKubeClient = externalKubeClient
2016-07-13 23:11:12 +00:00
kubeDeps . EventClient = eventClient
2015-07-01 19:02:30 +00:00
}
2017-02-10 05:14:10 +00:00
nodeName , err := getNodeName ( kubeDeps . Cloud , nodeutil . GetHostname ( s . HostnameOverride ) )
if err != nil {
return err
}
2017-01-04 20:13:06 +00:00
2017-02-10 05:14:10 +00:00
if kubeDeps . Auth == nil {
2017-05-02 18:55:56 +00:00
auth , err := BuildAuth ( nodeName , kubeDeps . ExternalKubeClient , s . KubeletConfiguration )
2016-10-08 04:45:15 +00:00
if err != nil {
return err
}
kubeDeps . Auth = auth
}
2016-07-13 23:11:12 +00:00
if kubeDeps . CAdvisorInterface == nil {
2016-10-22 23:06:47 +00:00
kubeDeps . CAdvisorInterface , err = cadvisor . New ( uint ( s . CAdvisorPort ) , s . ContainerRuntime , s . RootDirectory )
2015-10-10 00:09:53 +00:00
if err != nil {
return err
}
}
2017-02-10 05:14:10 +00:00
// Setup event recorder if required.
makeEventRecorder ( & s . KubeletConfiguration , kubeDeps , nodeName )
2016-07-13 23:11:12 +00:00
if kubeDeps . ContainerManager == nil {
2017-02-20 17:05:06 +00:00
if s . CgroupsPerQOS && s . CgroupRoot == "" {
glog . Infof ( "--cgroups-per-qos enabled, but --cgroup-root was not specified. defaulting to /" )
s . CgroupRoot = "/"
}
2017-02-10 05:14:10 +00:00
kubeReserved , err := parseResourceList ( s . KubeReserved )
if err != nil {
return err
}
systemReserved , err := parseResourceList ( s . SystemReserved )
if err != nil {
return err
}
var hardEvictionThresholds [ ] evictionapi . Threshold
// If the user requested to ignore eviction thresholds, then do not set valid values for hardEvictionThresholds here.
if ! s . ExperimentalNodeAllocatableIgnoreEvictionThreshold {
2017-03-02 01:56:24 +00:00
hardEvictionThresholds , err = eviction . ParseThresholdConfig ( [ ] string { } , s . EvictionHard , "" , "" , "" )
2017-02-10 05:14:10 +00:00
if err != nil {
return err
}
}
2017-02-28 21:03:06 +00:00
experimentalQOSReserved , err := cm . ParseQOSReserved ( s . ExperimentalQOSReserved )
if err != nil {
return err
}
2016-09-02 18:13:02 +00:00
kubeDeps . ContainerManager , err = cm . NewContainerManager (
kubeDeps . Mounter ,
kubeDeps . CAdvisorInterface ,
cm . NodeConfig {
RuntimeCgroupsName : s . RuntimeCgroups ,
SystemCgroupsName : s . SystemCgroups ,
KubeletCgroupsName : s . KubeletCgroups ,
ContainerRuntime : s . ContainerRuntime ,
2017-02-03 22:10:53 +00:00
CgroupsPerQOS : s . CgroupsPerQOS ,
2016-09-02 18:13:02 +00:00
CgroupRoot : s . CgroupRoot ,
CgroupDriver : s . CgroupDriver ,
ProtectKernelDefaults : s . ProtectKernelDefaults ,
2017-02-09 20:13:28 +00:00
NodeAllocatableConfig : cm . NodeAllocatableConfig {
KubeReservedCgroupName : s . KubeReservedCgroup ,
SystemReservedCgroupName : s . SystemReservedCgroup ,
EnforceNodeAllocatable : sets . NewString ( s . EnforceNodeAllocatable ... ) ,
KubeReserved : kubeReserved ,
SystemReserved : systemReserved ,
HardEvictionThresholds : hardEvictionThresholds ,
} ,
2017-02-28 21:03:06 +00:00
ExperimentalQOSReserved : * experimentalQOSReserved ,
2016-09-02 18:13:02 +00:00
} ,
2017-02-10 05:14:10 +00:00
s . ExperimentalFailSwapOn ,
kubeDeps . Recorder )
2016-09-02 18:13:02 +00:00
2015-07-01 19:02:30 +00:00
if err != nil {
return err
}
}
2016-08-17 18:18:17 +00:00
if err := checkPermissions ( ) ; err != nil {
glog . Error ( err )
}
2016-08-24 16:03:16 +00:00
utilruntime . ReallyCrash = s . ReallyCrashForTesting
2015-07-01 19:02:30 +00:00
rand . Seed ( time . Now ( ) . UTC ( ) . UnixNano ( ) )
// TODO(vmarmol): Do this through container config.
2016-07-13 23:11:12 +00:00
oomAdjuster := kubeDeps . OOMAdjuster
2016-04-27 04:35:14 +00:00
if err := oomAdjuster . ApplyOOMScoreAdj ( 0 , int ( s . OOMScoreAdj ) ) ; err != nil {
2015-07-01 19:02:30 +00:00
glog . Warning ( err )
2015-02-02 21:30:31 +00:00
}
2017-01-18 19:34:49 +00:00
if err := RunKubelet ( & s . KubeletFlags , & s . KubeletConfiguration , kubeDeps , s . RunOnce , standaloneMode ) ; err != nil {
2015-05-16 20:12:33 +00:00
return err
}
2015-02-02 21:30:31 +00:00
2015-03-30 21:09:50 +00:00
if s . HealthzPort > 0 {
healthz . DefaultHealthz ( )
2016-02-02 10:57:06 +00:00
go wait . Until ( func ( ) {
2016-04-27 04:35:14 +00:00
err := http . ListenAndServe ( net . JoinHostPort ( s . HealthzBindAddress , strconv . Itoa ( int ( s . HealthzPort ) ) ) , nil )
2015-03-30 21:09:50 +00:00
if err != nil {
glog . Errorf ( "Starting health server failed: %v" , err )
}
2016-02-02 10:57:06 +00:00
} , 5 * time . Second , wait . NeverStop )
2015-03-30 21:09:50 +00:00
}
2015-05-16 20:12:33 +00:00
if s . RunOnce {
return nil
}
2015-02-02 21:30:31 +00:00
2016-05-05 22:24:54 +00:00
<- done
return nil
2015-02-02 21:30:31 +00:00
}
2016-08-13 01:06:48 +00:00
// getNodeName returns the node name according to the cloud provider
2016-08-18 04:56:52 +00:00
// if cloud provider is specified. Otherwise, returns the hostname of the node.
2016-07-16 06:10:29 +00:00
func getNodeName ( cloud cloudprovider . Interface , hostname string ) ( types . NodeName , error ) {
2016-08-18 04:56:52 +00:00
if cloud == nil {
2016-07-16 06:10:29 +00:00
return types . NodeName ( hostname ) , nil
2016-08-13 01:06:48 +00:00
}
2016-08-18 04:56:52 +00:00
instances , ok := cloud . Instances ( )
if ! ok {
return "" , fmt . Errorf ( "failed to get instances from cloud provider" )
2016-08-13 01:06:48 +00:00
}
2016-08-18 04:56:52 +00:00
nodeName , err := instances . CurrentNodeName ( hostname )
2016-08-13 01:06:48 +00:00
if err != nil {
2016-11-02 09:26:54 +00:00
return "" , fmt . Errorf ( "error fetching current node name from cloud provider: %v" , err )
2016-08-13 01:06:48 +00:00
}
2016-08-18 04:56:52 +00:00
glog . V ( 2 ) . Infof ( "cloud provider determined current node name to be %s" , nodeName )
2016-08-13 01:06:48 +00:00
2016-08-18 04:56:52 +00:00
return nodeName , nil
2016-08-13 01:06:48 +00:00
}
2015-06-05 11:45:40 +00:00
// InitializeTLS checks for a configured TLSCertFile and TLSPrivateKeyFile: if unspecified a new self-signed
2015-12-10 20:14:26 +00:00
// certificate and key file are generated. Returns a configured server.TLSOptions object.
2017-01-18 19:34:49 +00:00
func InitializeTLS ( kf * options . KubeletFlags , kc * componentconfig . KubeletConfiguration ) ( * server . TLSOptions , error ) {
2017-02-17 19:32:41 +00:00
if ! utilfeature . DefaultFeatureGate . Enabled ( features . RotateKubeletServerCertificate ) && kc . TLSCertFile == "" && kc . TLSPrivateKeyFile == "" {
2016-07-13 23:11:12 +00:00
kc . TLSCertFile = path . Join ( kc . CertDirectory , "kubelet.crt" )
kc . TLSPrivateKeyFile = path . Join ( kc . CertDirectory , "kubelet.key" )
2016-11-09 02:33:21 +00:00
canReadCertAndKey , err := certutil . CanReadCertAndKey ( kc . TLSCertFile , kc . TLSPrivateKeyFile )
if err != nil {
return nil , err
}
if ! canReadCertAndKey {
2017-01-18 19:34:49 +00:00
cert , key , err := certutil . GenerateSelfSignedCertKey ( nodeutil . GetHostname ( kf . HostnameOverride ) , nil , nil )
2016-10-19 11:28:56 +00:00
if err != nil {
2016-05-24 03:25:12 +00:00
return nil , fmt . Errorf ( "unable to generate self signed cert: %v" , err )
}
2016-10-19 11:28:56 +00:00
if err := certutil . WriteCert ( kc . TLSCertFile , cert ) ; err != nil {
return nil , err
}
if err := certutil . WriteKey ( kc . TLSPrivateKeyFile , key ) ; err != nil {
return nil , err
}
2016-07-13 23:11:12 +00:00
glog . V ( 4 ) . Infof ( "Using self-signed cert (%s, %s)" , kc . TLSCertFile , kc . TLSPrivateKeyFile )
2015-06-05 11:45:40 +00:00
}
}
2015-12-10 20:14:26 +00:00
tlsOptions := & server . TLSOptions {
2015-06-05 11:45:40 +00:00
Config : & tls . Config {
2016-05-24 14:18:28 +00:00
// Can't use SSLv3 because of POODLE and BEAST
// Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
// Can't use TLSv1.1 because of RC4 cipher usage
MinVersion : tls . VersionTLS12 ,
2015-06-05 11:45:40 +00:00
} ,
2016-07-13 23:11:12 +00:00
CertFile : kc . TLSCertFile ,
KeyFile : kc . TLSPrivateKeyFile ,
2015-06-05 11:45:40 +00:00
}
2016-10-08 04:45:15 +00:00
if len ( kc . Authentication . X509 . ClientCAFile ) > 0 {
2017-01-20 13:05:41 +00:00
clientCAs , err := certutil . NewPool ( kc . Authentication . X509 . ClientCAFile )
2016-10-08 04:45:15 +00:00
if err != nil {
return nil , fmt . Errorf ( "unable to load client CA file %s: %v" , kc . Authentication . X509 . ClientCAFile , err )
}
// Specify allowed CAs for client certificates
tlsOptions . Config . ClientCAs = clientCAs
// Populate PeerCertificates in requests, but don't reject connections without verified certificates
tlsOptions . Config . ClientAuth = tls . RequestClientCert
}
2015-06-05 11:45:40 +00:00
return tlsOptions , nil
}
2016-02-12 18:58:43 +00:00
func kubeconfigClientConfig ( s * options . KubeletServer ) ( * restclient . Config , error ) {
2016-08-17 18:18:17 +00:00
if s . RequireKubeConfig {
// Ignores the values of s.APIServerList
return clientcmd . NewNonInteractiveDeferredLoadingClientConfig (
& clientcmd . ClientConfigLoadingRules { ExplicitPath : s . KubeConfig . Value ( ) } ,
& clientcmd . ConfigOverrides { } ,
) . ClientConfig ( )
}
2015-05-12 03:44:13 +00:00
return clientcmd . NewNonInteractiveDeferredLoadingClientConfig (
& clientcmd . ClientConfigLoadingRules { ExplicitPath : s . KubeConfig . Value ( ) } ,
2016-08-17 18:18:17 +00:00
& clientcmd . ConfigOverrides { ClusterInfo : clientcmdapi . Cluster { Server : s . APIServerList [ 0 ] } } ,
) . ClientConfig ( )
2015-05-12 03:44:13 +00:00
}
// createClientConfig creates a client configuration from the command line
2016-08-13 01:29:59 +00:00
// arguments. If --kubeconfig is explicitly set, it will be used. If it is
// not set, we attempt to load the default kubeconfig file, and if we cannot,
// we fall back to the default client with no auth - this fallback does not, in
// and of itself, constitute an error.
2016-02-12 18:58:43 +00:00
func createClientConfig ( s * options . KubeletServer ) ( * restclient . Config , error ) {
2016-08-17 18:18:17 +00:00
if s . RequireKubeConfig {
return kubeconfigClientConfig ( s )
}
// TODO: handle a new --standalone flag that bypasses kubeconfig loading and returns no error.
// DEPRECATED: all subsequent code is deprecated
if len ( s . APIServerList ) == 0 {
return nil , fmt . Errorf ( "no api servers specified" )
}
// TODO: adapt Kube client to support LB over several servers
if len ( s . APIServerList ) > 1 {
glog . Infof ( "Multiple api servers specified. Picking first one" )
}
2015-05-12 03:44:13 +00:00
if s . KubeConfig . Provided ( ) {
2015-12-24 23:46:56 +00:00
return kubeconfigClientConfig ( s )
}
2016-08-13 01:29:59 +00:00
// If KubeConfig was not provided, try to load the default file, then fall back
// to a default auth config.
2015-12-24 23:46:56 +00:00
clientConfig , err := kubeconfigClientConfig ( s )
2015-05-12 03:44:13 +00:00
if err != nil {
2016-08-13 01:29:59 +00:00
glog . Warningf ( "Could not load kubeconfig file %s: %v. Using default client config instead." , s . KubeConfig , err )
authInfo := & clientauth . Info { }
authConfig , err := authInfo . MergeWithConfig ( restclient . Config { } )
if err != nil {
return nil , err
}
authConfig . Host = s . APIServerList [ 0 ]
clientConfig = & authConfig
2015-05-12 03:44:13 +00:00
}
return clientConfig , nil
}
2015-06-08 19:19:17 +00:00
// CreateAPIServerClientConfig generates a client.Config from command line flags,
// including api-server-list, via createClientConfig and then injects chaos into
// the configuration via addChaosToClientConfig. This func is exported to support
// integration with third party kubelet extensions (e.g. kubernetes-mesos).
2016-02-12 18:58:43 +00:00
func CreateAPIServerClientConfig ( s * options . KubeletServer ) ( * restclient . Config , error ) {
2015-12-24 23:46:56 +00:00
clientConfig , err := createClientConfig ( s )
2015-05-12 03:44:13 +00:00
if err != nil {
return nil , err
}
2015-10-12 15:56:15 +00:00
2016-04-19 07:35:32 +00:00
clientConfig . ContentType = s . ContentType
2015-10-12 15:56:15 +00:00
// Override kubeconfig qps/burst settings from flags
2016-06-28 14:46:17 +00:00
clientConfig . QPS = float32 ( s . KubeAPIQPS )
2016-04-27 04:35:14 +00:00
clientConfig . Burst = int ( s . KubeAPIBurst )
2015-10-12 15:56:15 +00:00
2015-12-24 23:46:56 +00:00
addChaosToClientConfig ( s , clientConfig )
2015-06-08 19:19:17 +00:00
return clientConfig , nil
2015-01-07 15:18:56 +00:00
}
2015-04-11 16:45:45 +00:00
// addChaosToClientConfig injects random errors into client connections if configured.
2016-02-12 18:58:43 +00:00
func addChaosToClientConfig ( s * options . KubeletServer , config * restclient . Config ) {
2015-04-11 16:45:45 +00:00
if s . ChaosChance != 0.0 {
config . WrapTransport = func ( rt http . RoundTripper ) http . RoundTripper {
seed := chaosclient . NewSeed ( 1 )
// TODO: introduce a standard chaos package with more tunables - this is just a proof of concept
// TODO: introduce random latency and stalls
return chaosclient . NewChaosRoundTripper ( rt , chaosclient . LogChaos , seed . P ( s . ChaosChance , chaosclient . ErrSimulatedConnectionResetByPeer ) )
}
}
}
2014-11-27 21:28:56 +00:00
// RunKubelet is responsible for setting up and running a kubelet. It is used in three different applications:
// 1 Integration tests
// 2 Kubelet binary
// 3 Standalone 'kubernetes' binary
// Eventually, #2 will be replaced with instances of #3
2017-01-18 19:34:49 +00:00
func RunKubelet ( kubeFlags * options . KubeletFlags , kubeCfg * componentconfig . KubeletConfiguration , kubeDeps * kubelet . KubeletDeps , runOnce bool , standaloneMode bool ) error {
hostname := nodeutil . GetHostname ( kubeFlags . HostnameOverride )
2016-07-13 23:11:12 +00:00
// Query the cloud provider for our node name, default to hostname if kcfg.Cloud == nil
nodeName , err := getNodeName ( kubeDeps . Cloud , hostname )
if err != nil {
return err
2015-06-12 15:42:38 +00:00
}
2017-02-10 05:14:10 +00:00
// Setup event recorder if required.
makeEventRecorder ( kubeCfg , kubeDeps , nodeName )
2015-08-24 17:41:51 +00:00
2016-07-13 23:11:12 +00:00
// TODO(mtaufen): I moved the validation of these fields here, from UnsecuredKubeletConfig,
// so that I could remove the associated fields from KubeletConfig. I would
// prefer this to be done as part of an independent validation step on the
// KubeletConfiguration. But as far as I can tell, we don't have an explicit
// place for validation of the KubeletConfiguration yet.
hostNetworkSources , err := kubetypes . GetValidatedSources ( kubeCfg . HostNetworkSources )
if err != nil {
return err
}
hostPIDSources , err := kubetypes . GetValidatedSources ( kubeCfg . HostPIDSources )
if err != nil {
return err
}
hostIPCSources , err := kubetypes . GetValidatedSources ( kubeCfg . HostIPCSources )
if err != nil {
return err
}
2015-08-24 17:41:51 +00:00
privilegedSources := capabilities . PrivilegedSources {
2016-07-13 23:11:12 +00:00
HostNetworkSources : hostNetworkSources ,
HostPIDSources : hostPIDSources ,
HostIPCSources : hostIPCSources ,
2015-08-24 17:41:51 +00:00
}
2016-07-13 23:11:12 +00:00
capabilities . Setup ( kubeCfg . AllowPrivileged , privilegedSources , 0 )
2014-11-27 21:28:56 +00:00
2016-07-13 23:11:12 +00:00
credentialprovider . SetPreferredDockercfgPath ( kubeCfg . RootDirectory )
glog . V ( 2 ) . Infof ( "Using root directory: %v" , kubeCfg . RootDirectory )
2015-01-27 20:16:47 +00:00
2016-07-13 23:11:12 +00:00
builder := kubeDeps . Builder
2015-03-26 12:31:54 +00:00
if builder == nil {
2015-09-23 11:05:05 +00:00
builder = CreateAndInitKubelet
2015-03-26 12:31:54 +00:00
}
2016-07-13 23:11:12 +00:00
if kubeDeps . OSInterface == nil {
kubeDeps . OSInterface = kubecontainer . RealOS { }
2015-04-21 00:26:40 +00:00
}
2017-05-24 22:19:54 +00:00
k , err := builder ( kubeCfg , kubeDeps , & kubeFlags . ContainerRuntimeOptions , standaloneMode , kubeFlags . HostnameOverride , kubeFlags . NodeIP , kubeFlags . ProviderID )
2015-01-07 02:31:40 +00:00
if err != nil {
2015-05-16 20:12:33 +00:00
return fmt . Errorf ( "failed to create kubelet: %v" , err )
2015-01-07 02:31:40 +00:00
}
2015-09-22 21:41:18 +00:00
2016-07-13 23:11:12 +00:00
// NewMainKubelet should have set up a pod source config if one didn't exist
// when the builder was run. This is just a precaution.
if kubeDeps . PodConfig == nil {
2016-12-03 07:17:18 +00:00
return fmt . Errorf ( "failed to create kubelet, pod source config was nil" )
2016-07-13 23:11:12 +00:00
}
podCfg := kubeDeps . PodConfig
rlimit . RlimitNumFiles ( uint64 ( kubeCfg . MaxOpenFiles ) )
2015-09-22 21:41:18 +00:00
2016-05-20 22:52:35 +00:00
// TODO(dawnchen): remove this once we deprecated old debian containervm images.
// This is a workaround for issue: https://github.com/opencontainers/runc/issues/726
// The current chosen number is consistent with most of other os dist.
2017-01-09 03:31:18 +00:00
const maxKeysPath = "/proc/sys/kernel/keys/root_maxkeys"
2016-05-24 00:02:11 +00:00
const minKeys uint64 = 1000000
2017-01-09 03:31:18 +00:00
key , err := ioutil . ReadFile ( maxKeysPath )
2016-05-20 22:52:35 +00:00
if err != nil {
2017-01-09 03:31:18 +00:00
glog . Errorf ( "Cannot read keys quota in %s" , maxKeysPath )
2016-05-24 00:02:11 +00:00
} else {
fields := strings . Fields ( string ( key ) )
2017-01-09 03:31:18 +00:00
nKey , _ := strconv . ParseUint ( fields [ 0 ] , 10 , 64 )
if nKey < minKeys {
glog . Infof ( "Setting keys quota in %s to %d" , maxKeysPath , minKeys )
err = ioutil . WriteFile ( maxKeysPath , [ ] byte ( fmt . Sprintf ( "%d" , uint64 ( minKeys ) ) ) , 0644 )
2016-05-24 00:02:11 +00:00
if err != nil {
2017-01-09 03:31:18 +00:00
glog . Warningf ( "Failed to update %s: %v" , maxKeysPath , err )
2016-05-24 00:02:11 +00:00
}
}
2016-05-20 22:52:35 +00:00
}
2017-01-09 03:31:18 +00:00
const maxBytesPath = "/proc/sys/kernel/keys/root_maxbytes"
2016-05-24 00:02:11 +00:00
const minBytes uint64 = 25000000
2017-01-09 03:31:18 +00:00
bytes , err := ioutil . ReadFile ( maxBytesPath )
2016-05-20 22:52:35 +00:00
if err != nil {
2017-01-09 03:31:18 +00:00
glog . Errorf ( "Cannot read keys bytes in %s" , maxBytesPath )
2016-05-24 00:02:11 +00:00
} else {
fields := strings . Fields ( string ( bytes ) )
2017-01-09 03:31:18 +00:00
nByte , _ := strconv . ParseUint ( fields [ 0 ] , 10 , 64 )
if nByte < minBytes {
glog . Infof ( "Setting keys bytes in %s to %d" , maxBytesPath , minBytes )
err = ioutil . WriteFile ( maxBytesPath , [ ] byte ( fmt . Sprintf ( "%d" , uint64 ( minBytes ) ) ) , 0644 )
2016-05-24 00:02:11 +00:00
if err != nil {
2017-01-09 03:31:18 +00:00
glog . Warningf ( "Failed to update %s: %v" , maxBytesPath , err )
2016-05-24 00:02:11 +00:00
}
}
2016-05-20 22:52:35 +00:00
}
2014-11-27 21:28:56 +00:00
// process pods and exit.
2016-07-13 23:11:12 +00:00
if runOnce {
2015-02-02 21:30:31 +00:00
if _ , err := k . RunOnce ( podCfg . Updates ( ) ) ; err != nil {
2015-05-16 20:12:33 +00:00
return fmt . Errorf ( "runonce failed: %v" , err )
2014-11-27 21:28:56 +00:00
}
2016-03-30 16:54:20 +00:00
glog . Infof ( "Started kubelet %s as runonce" , version . Get ( ) . String ( ) )
2014-11-27 21:28:56 +00:00
} else {
2016-11-28 09:21:58 +00:00
startKubelet ( k , podCfg , kubeCfg , kubeDeps )
2016-03-30 16:54:20 +00:00
glog . Infof ( "Started kubelet %s" , version . Get ( ) . String ( ) )
2014-11-27 21:28:56 +00:00
}
2015-05-16 20:12:33 +00:00
return nil
2014-11-27 21:28:56 +00:00
}
2016-11-28 09:21:58 +00:00
func startKubelet ( k kubelet . KubeletBootstrap , podCfg * config . PodConfig , kubeCfg * componentconfig . KubeletConfiguration , kubeDeps * kubelet . KubeletDeps ) {
2014-11-27 21:28:56 +00:00
// start the kubelet
2016-02-02 10:57:06 +00:00
go wait . Until ( func ( ) { k . Run ( podCfg . Updates ( ) ) } , 0 , wait . NeverStop )
2014-11-27 21:28:56 +00:00
// start the kubelet server
2016-07-13 23:11:12 +00:00
if kubeCfg . EnableServer {
2016-02-02 10:57:06 +00:00
go wait . Until ( func ( ) {
2017-02-28 18:43:08 +00:00
k . ListenAndServe ( net . ParseIP ( kubeCfg . Address ) , uint ( kubeCfg . Port ) , kubeDeps . TLSOptions , kubeDeps . Auth , kubeCfg . EnableDebuggingHandlers , kubeCfg . EnableContentionProfiling )
2016-02-02 10:57:06 +00:00
} , 0 , wait . NeverStop )
2014-11-27 21:28:56 +00:00
}
2016-07-13 23:11:12 +00:00
if kubeCfg . ReadOnlyPort > 0 {
2016-02-02 10:57:06 +00:00
go wait . Until ( func ( ) {
2016-07-13 23:11:12 +00:00
k . ListenAndServeReadOnly ( net . ParseIP ( kubeCfg . Address ) , uint ( kubeCfg . ReadOnlyPort ) )
2016-02-02 10:57:06 +00:00
} , 0 , wait . NeverStop )
2015-04-02 04:41:32 +00:00
}
2014-11-27 21:28:56 +00:00
}
2017-05-24 22:19:54 +00:00
func CreateAndInitKubelet ( kubeCfg * componentconfig . KubeletConfiguration , kubeDeps * kubelet . KubeletDeps , crOptions * options . ContainerRuntimeOptions , standaloneMode bool , hostnameOverride , nodeIP , providerID string ) ( k kubelet . KubeletBootstrap , err error ) {
2014-11-27 21:28:56 +00:00
// TODO: block until all sources have delivered at least one update to the channel, or break the sync loop
// up into "per source" synchronizations
2017-05-24 22:19:54 +00:00
k , err = kubelet . NewMainKubelet ( kubeCfg , kubeDeps , crOptions , standaloneMode , hostnameOverride , nodeIP , providerID )
2015-01-07 02:31:40 +00:00
if err != nil {
2016-07-13 23:11:12 +00:00
return nil , err
2015-01-07 02:31:40 +00:00
}
2014-11-27 21:28:56 +00:00
k . BirthCry ( )
2015-03-16 04:00:46 +00:00
k . StartGarbageCollection ( )
2014-10-27 17:04:39 +00:00
2016-07-13 23:11:12 +00:00
return k , nil
2015-12-12 01:51:39 +00:00
}
2017-02-10 05:14:10 +00:00
// parseResourceList parses the given configuration map into an API
// ResourceList or returns an error.
func parseResourceList ( m componentconfig . ConfigurationMap ) ( v1 . ResourceList , error ) {
if len ( m ) == 0 {
return nil , nil
}
rl := make ( v1 . ResourceList )
for k , v := range m {
switch v1 . ResourceName ( k ) {
// Only CPU and memory resources are supported.
case v1 . ResourceCPU , v1 . ResourceMemory :
q , err := resource . ParseQuantity ( v )
if err != nil {
return nil , err
}
if q . Sign ( ) == - 1 {
return nil , fmt . Errorf ( "resource quantity for %q cannot be negative: %v" , k , v )
}
rl [ v1 . ResourceName ( k ) ] = q
default :
return nil , fmt . Errorf ( "cannot reserve %q resource" , k )
}
}
return rl , nil
}
2017-04-07 23:43:57 +00:00
// RunDockershim only starts the dockershim in current process. This is only used for cri validate testing purpose
// TODO(random-liu): Move this to a separate binary.
2017-05-24 22:19:54 +00:00
func RunDockershim ( c * componentconfig . KubeletConfiguration , r * options . ContainerRuntimeOptions ) error {
2017-04-07 23:43:57 +00:00
// Create docker client.
2017-05-24 22:19:54 +00:00
dockerClient := libdocker . ConnectToDockerOrDie ( r . DockerEndpoint , c . RuntimeRequestTimeout . Duration ,
r . ImagePullProgressDeadline . Duration )
2017-04-07 23:43:57 +00:00
// Initialize network plugin settings.
2017-05-24 22:19:54 +00:00
binDir := r . CNIBinDir
2017-04-07 23:43:57 +00:00
if binDir == "" {
2017-05-24 22:19:54 +00:00
binDir = r . NetworkPluginDir
2017-04-07 23:43:57 +00:00
}
2017-05-03 23:32:01 +00:00
nh := & kubelet . NoOpLegacyHost { }
2017-04-07 23:43:57 +00:00
pluginSettings := dockershim . NetworkPluginSettings {
HairpinMode : componentconfig . HairpinMode ( c . HairpinMode ) ,
NonMasqueradeCIDR : c . NonMasqueradeCIDR ,
2017-05-24 22:19:54 +00:00
PluginName : r . NetworkPluginName ,
PluginConfDir : r . CNIConfDir ,
2017-04-07 23:43:57 +00:00
PluginBinDir : binDir ,
2017-05-24 22:19:54 +00:00
MTU : int ( r . NetworkPluginMTU ) ,
2017-05-03 23:32:01 +00:00
LegacyRuntimeHost : nh ,
2017-04-07 23:43:57 +00:00
}
// Initialize streaming configuration. (Not using TLS now)
streamingConfig := & streaming . Config {
// Use a relative redirect (no scheme or host).
BaseURL : & url . URL { Path : "/cri/" } ,
StreamIdleTimeout : c . StreamingConnectionIdleTimeout . Duration ,
StreamCreationTimeout : streaming . DefaultConfig . StreamCreationTimeout ,
SupportedRemoteCommandProtocols : streaming . DefaultConfig . SupportedRemoteCommandProtocols ,
SupportedPortForwardProtocols : streaming . DefaultConfig . SupportedPortForwardProtocols ,
}
2017-05-24 22:19:54 +00:00
ds , err := dockershim . NewDockerService ( dockerClient , c . SeccompProfileRoot , r . PodSandboxImage ,
streamingConfig , & pluginSettings , c . RuntimeCgroups , c . CgroupDriver , r . DockerExecHandlerName , r . DockershimRootDirectory ,
r . DockerDisableSharedPID )
2017-04-07 23:43:57 +00:00
if err != nil {
return err
}
if err := ds . Start ( ) ; err != nil {
return err
}
glog . V ( 2 ) . Infof ( "Starting the GRPC server for the docker CRI shim." )
2017-05-19 03:18:18 +00:00
server := dockerremote . NewDockerServer ( c . RemoteRuntimeEndpoint , ds )
2017-04-07 23:43:57 +00:00
if err := server . Start ( ) ; err != nil {
return err
}
// Start the streaming server
addr := net . JoinHostPort ( c . Address , strconv . Itoa ( int ( c . Port ) ) )
return http . ListenAndServe ( addr , ds )
}