2014-10-27 17:04:39 +00:00
|
|
|
/*
|
2015-09-01 13:35:38 +00:00
|
|
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
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"
|
2014-10-27 17:04:39 +00:00
|
|
|
"fmt"
|
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"
|
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"
|
|
|
|
|
|
|
|
"k8s.io/kubernetes/cmd/kubelet/app/options"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api"
|
2015-12-12 01:51:39 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api/resource"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/capabilities"
|
|
|
|
"k8s.io/kubernetes/pkg/client/chaosclient"
|
2016-02-05 21:58:03 +00:00
|
|
|
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
2015-09-03 21:43:19 +00:00
|
|
|
"k8s.io/kubernetes/pkg/client/record"
|
2016-02-03 21:21:05 +00:00
|
|
|
unversioned_core "k8s.io/kubernetes/pkg/client/typed/generated/core/unversioned"
|
2015-08-13 19:01:50 +00:00
|
|
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
|
|
|
clientauth "k8s.io/kubernetes/pkg/client/unversioned/auth"
|
|
|
|
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
|
|
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
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"
|
|
|
|
"k8s.io/kubernetes/pkg/healthz"
|
|
|
|
"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"
|
|
|
|
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
|
|
|
"k8s.io/kubernetes/pkg/kubelet/network"
|
2015-12-10 20:14:26 +00:00
|
|
|
"k8s.io/kubernetes/pkg/kubelet/server"
|
2015-10-09 17:24:31 +00:00
|
|
|
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/util"
|
2016-01-28 02:31:15 +00:00
|
|
|
"k8s.io/kubernetes/pkg/util/flock"
|
2015-09-14 09:51:40 +00:00
|
|
|
"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-01-15 07:32:10 +00:00
|
|
|
"k8s.io/kubernetes/pkg/util/runtime"
|
2016-02-02 10:57:06 +00:00
|
|
|
"k8s.io/kubernetes/pkg/util/wait"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/volume"
|
2014-10-27 17:04:39 +00:00
|
|
|
)
|
|
|
|
|
2015-03-26 12:31:54 +00:00
|
|
|
// bootstrapping interface for kubelet, targets the initialization protocol
|
|
|
|
type KubeletBootstrap interface {
|
|
|
|
BirthCry()
|
|
|
|
StartGarbageCollection()
|
2015-12-10 20:14:26 +00:00
|
|
|
ListenAndServe(address net.IP, port uint, tlsOptions *server.TLSOptions, auth server.AuthInterface, enableDebuggingHandlers bool)
|
2015-09-29 03:32:20 +00:00
|
|
|
ListenAndServeReadOnly(address net.IP, port uint)
|
2015-10-09 17:24:31 +00:00
|
|
|
Run(<-chan kubetypes.PodUpdate)
|
|
|
|
RunOnce(<-chan kubetypes.PodUpdate) ([]kubelet.RunPodResult, error)
|
2015-03-26 12:31:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// create and initialize a Kubelet instance
|
|
|
|
type KubeletBuilder func(kc *KubeletConfig) (KubeletBootstrap, *config.PodConfig, error)
|
|
|
|
|
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{
|
|
|
|
Use: "kubelet",
|
|
|
|
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
|
|
|
|
described in those PodSpecs are running and healthy.
|
|
|
|
|
|
|
|
Other than from an PodSpec from the apiserver, there are three ways that a container
|
|
|
|
manifest can be provided to the Kubelet.
|
|
|
|
|
|
|
|
File: Path passed as a flag on the command line. This file is rechecked every 20
|
|
|
|
seconds (configurable with a flag).
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2015-09-29 03:32:20 +00:00
|
|
|
// UnsecuredKubeletConfig returns a KubeletConfig suitable for being run, or an error if the server setup
|
|
|
|
// is not valid. It will not start any background processes, and does not include authentication/authorization
|
2015-12-24 23:46:56 +00:00
|
|
|
func UnsecuredKubeletConfig(s *options.KubeletServer) (*KubeletConfig, error) {
|
2015-10-09 17:24:31 +00:00
|
|
|
hostNetworkSources, err := kubetypes.GetValidatedSources(strings.Split(s.HostNetworkSources, ","))
|
2015-07-01 19:02:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2015-02-02 21:30:31 +00:00
|
|
|
}
|
|
|
|
|
2015-10-09 17:24:31 +00:00
|
|
|
hostPIDSources, err := kubetypes.GetValidatedSources(strings.Split(s.HostPIDSources, ","))
|
2015-09-15 16:43:59 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2015-10-09 17:24:31 +00:00
|
|
|
hostIPCSources, err := kubetypes.GetValidatedSources(strings.Split(s.HostIPCSources, ","))
|
2015-08-10 08:14:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2015-07-01 19:02:30 +00:00
|
|
|
mounter := mount.New()
|
2015-09-14 09:51:40 +00:00
|
|
|
var writer io.Writer = &io.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()
|
2015-09-14 09:51:40 +00:00
|
|
|
writer = &io.NsenterWriter{}
|
2015-02-02 21:30:31 +00:00
|
|
|
}
|
|
|
|
|
2015-12-24 23:46:56 +00:00
|
|
|
tlsOptions, err := InitializeTLS(s)
|
2015-03-10 05:39:00 +00:00
|
|
|
if err != nil {
|
2015-07-01 19:02:30 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var dockerExecHandler dockertools.ExecHandler
|
|
|
|
switch s.DockerExecHandlerName {
|
|
|
|
case "native":
|
|
|
|
dockerExecHandler = &dockertools.NativeExecHandler{}
|
|
|
|
case "nsenter":
|
|
|
|
dockerExecHandler = &dockertools.NsenterExecHandler{}
|
|
|
|
default:
|
|
|
|
glog.Warningf("Unknown Docker exec handler %q; defaulting to native", s.DockerExecHandlerName)
|
|
|
|
dockerExecHandler = &dockertools.NativeExecHandler{}
|
2015-03-10 05:39:00 +00:00
|
|
|
}
|
|
|
|
|
2015-03-16 04:00:46 +00:00
|
|
|
imageGCPolicy := kubelet.ImageGCPolicy{
|
|
|
|
HighThresholdPercent: s.ImageGCHighThresholdPercent,
|
|
|
|
LowThresholdPercent: s.ImageGCLowThresholdPercent,
|
|
|
|
}
|
2015-03-23 22:31:13 +00:00
|
|
|
|
2015-05-12 08:24:08 +00:00
|
|
|
diskSpacePolicy := kubelet.DiskSpacePolicy{
|
|
|
|
DockerFreeDiskMB: s.LowDiskSpaceThresholdMB,
|
|
|
|
RootFreeDiskMB: s.LowDiskSpaceThresholdMB,
|
|
|
|
}
|
2015-03-23 22:31:13 +00:00
|
|
|
|
2015-07-30 16:28:47 +00:00
|
|
|
manifestURLHeader := make(http.Header)
|
|
|
|
if s.ManifestURLHeader != "" {
|
|
|
|
pieces := strings.Split(s.ManifestURLHeader, ":")
|
|
|
|
if len(pieces) != 2 {
|
2015-07-01 19:02:30 +00:00
|
|
|
return nil, fmt.Errorf("manifest-url-header must have a single ':' key-value separator, got %q", s.ManifestURLHeader)
|
2015-07-30 16:28:47 +00:00
|
|
|
}
|
|
|
|
manifestURLHeader.Set(pieces[0], pieces[1])
|
|
|
|
}
|
|
|
|
|
2015-12-12 01:51:39 +00:00
|
|
|
reservation, err := parseReservation(s.KubeReserved, s.SystemReserved)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2015-07-01 19:02:30 +00:00
|
|
|
return &KubeletConfig{
|
2016-01-11 20:28:09 +00:00
|
|
|
Address: net.ParseIP(s.Address),
|
2015-09-09 11:10:08 +00:00
|
|
|
AllowPrivileged: s.AllowPrivileged,
|
2015-09-29 03:32:20 +00:00
|
|
|
Auth: nil, // default does not enforce auth[nz]
|
2015-08-13 14:05:32 +00:00
|
|
|
CAdvisorInterface: nil, // launches background processes, not set here
|
2016-01-14 19:19:26 +00:00
|
|
|
VolumeStatsAggPeriod: s.VolumeStatsAggPeriod.Duration,
|
2015-04-24 00:07:52 +00:00
|
|
|
CgroupRoot: s.CgroupRoot,
|
2015-09-09 11:10:08 +00:00
|
|
|
Cloud: nil, // cloud provider might start background processes
|
2016-01-11 20:28:09 +00:00
|
|
|
ClusterDNS: net.ParseIP(s.ClusterDNS),
|
2015-09-09 11:10:08 +00:00
|
|
|
ClusterDomain: s.ClusterDomain,
|
|
|
|
ConfigFile: s.Config,
|
|
|
|
ConfigureCBR0: s.ConfigureCBR0,
|
2015-10-10 00:09:53 +00:00
|
|
|
ContainerManager: nil,
|
2015-05-01 21:24:07 +00:00
|
|
|
ContainerRuntime: s.ContainerRuntime,
|
2015-09-09 11:10:08 +00:00
|
|
|
CPUCFSQuota: s.CPUCFSQuota,
|
|
|
|
DiskSpacePolicy: diskSpacePolicy,
|
|
|
|
DockerClient: dockertools.ConnectToDockerOrDie(s.DockerEndpoint),
|
2016-02-05 01:49:17 +00:00
|
|
|
RuntimeContainer: s.RuntimeContainer,
|
2015-05-27 12:51:01 +00:00
|
|
|
DockerExecHandler: dockerExecHandler,
|
2016-01-21 16:44:28 +00:00
|
|
|
EnableCustomMetrics: s.EnableCustomMetrics,
|
2015-09-09 11:10:08 +00:00
|
|
|
EnableDebuggingHandlers: s.EnableDebuggingHandlers,
|
|
|
|
EnableServer: s.EnableServer,
|
|
|
|
EventBurst: s.EventBurst,
|
|
|
|
EventRecordQPS: s.EventRecordQPS,
|
2016-01-11 20:28:09 +00:00
|
|
|
FileCheckFrequency: s.FileCheckFrequency.Duration,
|
2015-09-09 11:10:08 +00:00
|
|
|
HostnameOverride: s.HostnameOverride,
|
|
|
|
HostNetworkSources: hostNetworkSources,
|
2015-09-15 16:43:59 +00:00
|
|
|
HostPIDSources: hostPIDSources,
|
2015-08-10 08:14:01 +00:00
|
|
|
HostIPCSources: hostIPCSources,
|
2016-01-11 20:28:09 +00:00
|
|
|
HTTPCheckFrequency: s.HTTPCheckFrequency.Duration,
|
2015-09-09 11:10:08 +00:00
|
|
|
ImageGCPolicy: imageGCPolicy,
|
|
|
|
KubeClient: nil,
|
|
|
|
ManifestURL: s.ManifestURL,
|
|
|
|
ManifestURLHeader: manifestURLHeader,
|
|
|
|
MasterServiceNamespace: s.MasterServiceNamespace,
|
|
|
|
MaxContainerCount: s.MaxContainerCount,
|
2015-09-22 21:41:18 +00:00
|
|
|
MaxOpenFiles: s.MaxOpenFiles,
|
2015-09-09 11:10:08 +00:00
|
|
|
MaxPerPodContainerCount: s.MaxPerPodContainerCount,
|
|
|
|
MaxPods: s.MaxPods,
|
2016-01-11 20:28:09 +00:00
|
|
|
MinimumGCAge: s.MinimumGCAge.Duration,
|
2015-09-09 11:10:08 +00:00
|
|
|
Mounter: mounter,
|
|
|
|
NetworkPluginName: s.NetworkPluginName,
|
|
|
|
NetworkPlugins: ProbeNetworkPlugins(s.NetworkPluginDir),
|
2015-11-13 23:59:23 +00:00
|
|
|
NodeLabels: s.NodeLabels,
|
2016-01-11 20:28:09 +00:00
|
|
|
NodeStatusUpdateFrequency: s.NodeStatusUpdateFrequency.Duration,
|
2016-01-07 20:44:40 +00:00
|
|
|
NonMasqueradeCIDR: s.NonMasqueradeCIDR,
|
2015-09-30 10:55:37 +00:00
|
|
|
OOMAdjuster: oom.NewOOMAdjuster(),
|
2015-09-09 11:05:22 +00:00
|
|
|
OSInterface: kubecontainer.RealOS{},
|
2015-09-09 11:10:08 +00:00
|
|
|
PodCIDR: s.PodCIDR,
|
2015-09-16 04:53:33 +00:00
|
|
|
ReconcileCIDR: s.ReconcileCIDR,
|
2015-09-09 11:10:08 +00:00
|
|
|
PodInfraContainerImage: s.PodInfraContainerImage,
|
|
|
|
Port: s.Port,
|
|
|
|
ReadOnlyPort: s.ReadOnlyPort,
|
|
|
|
RegisterNode: s.RegisterNode,
|
2015-09-16 04:53:33 +00:00
|
|
|
RegisterSchedulable: s.RegisterSchedulable,
|
2015-09-09 11:10:08 +00:00
|
|
|
RegistryBurst: s.RegistryBurst,
|
|
|
|
RegistryPullQPS: s.RegistryPullQPS,
|
|
|
|
ResolverConfig: s.ResolverConfig,
|
2015-12-12 01:51:39 +00:00
|
|
|
Reservation: *reservation,
|
2015-09-09 11:10:08 +00:00
|
|
|
ResourceContainer: s.ResourceContainer,
|
|
|
|
RktPath: s.RktPath,
|
2015-09-01 02:25:26 +00:00
|
|
|
RktStage1Image: s.RktStage1Image,
|
2015-09-09 11:10:08 +00:00
|
|
|
RootDirectory: s.RootDirectory,
|
|
|
|
Runonce: s.RunOnce,
|
2015-10-20 21:49:44 +00:00
|
|
|
SerializeImagePulls: s.SerializeImagePulls,
|
2015-09-09 11:10:08 +00:00
|
|
|
StandaloneMode: (len(s.APIServerList) == 0),
|
2016-01-11 20:28:09 +00:00
|
|
|
StreamingConnectionIdleTimeout: s.StreamingConnectionIdleTimeout.Duration,
|
|
|
|
SyncFrequency: s.SyncFrequency.Duration,
|
2015-09-09 11:10:08 +00:00
|
|
|
SystemContainer: s.SystemContainer,
|
|
|
|
TLSOptions: tlsOptions,
|
2015-09-14 09:51:40 +00:00
|
|
|
Writer: writer,
|
2015-09-30 18:31:53 +00:00
|
|
|
VolumePlugins: ProbeVolumePlugins(s.VolumePluginDir),
|
2016-01-11 20:28:09 +00:00
|
|
|
OutOfDiskTransitionFrequency: s.OutOfDiskTransitionFrequency.Duration,
|
2016-02-08 18:52:30 +00:00
|
|
|
HairpinMode: s.HairpinMode,
|
2015-11-21 03:41:32 +00:00
|
|
|
|
2015-11-24 02:11:51 +00:00
|
|
|
ExperimentalFlannelOverlay: s.ExperimentalFlannelOverlay,
|
2016-01-11 20:28:09 +00:00
|
|
|
NodeIP: net.ParseIP(s.NodeIP),
|
2015-07-01 19:02:30 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run runs the specified KubeletServer for the given KubeletConfig. This should never exit.
|
|
|
|
// The kcfg argument may be nil - if so, it is initialized from the settings on KubeletServer.
|
|
|
|
// Otherwise, the caller is assumed to have set up the KubeletConfig object and all defaults
|
|
|
|
// will be ignored.
|
2015-12-24 23:46:56 +00:00
|
|
|
func Run(s *options.KubeletServer, kcfg *KubeletConfig) error {
|
2015-10-10 00:09:53 +00:00
|
|
|
var err error
|
2016-01-28 02:31:15 +00:00
|
|
|
if s.LockFilePath != "" {
|
|
|
|
glog.Infof("aquiring lock on %q", s.LockFilePath)
|
|
|
|
if err := flock.Acquire(s.LockFilePath); err != nil {
|
|
|
|
return fmt.Errorf("unable to aquire file lock on %q: %v", s.LockFilePath, err)
|
|
|
|
}
|
|
|
|
}
|
2015-07-01 19:02:30 +00:00
|
|
|
if kcfg == nil {
|
2015-12-24 23:46:56 +00:00
|
|
|
cfg, err := UnsecuredKubeletConfig(s)
|
2015-07-01 19:02:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
kcfg = cfg
|
|
|
|
|
2015-12-24 23:46:56 +00:00
|
|
|
clientConfig, err := CreateAPIServerClientConfig(s)
|
2015-07-01 19:02:30 +00:00
|
|
|
if err == nil {
|
2016-02-01 22:30:47 +00:00
|
|
|
kcfg.KubeClient, err = clientset.NewForConfig(clientConfig)
|
2015-11-20 17:13:41 +00:00
|
|
|
|
|
|
|
// make a separate client for events
|
|
|
|
eventClientConfig := *clientConfig
|
|
|
|
eventClientConfig.QPS = s.EventRecordQPS
|
|
|
|
eventClientConfig.Burst = s.EventBurst
|
2016-02-01 22:30:47 +00:00
|
|
|
kcfg.EventClient, err = clientset.NewForConfig(&eventClientConfig)
|
2015-07-01 19:02:30 +00:00
|
|
|
}
|
|
|
|
if err != nil && len(s.APIServerList) > 0 {
|
|
|
|
glog.Warningf("No API client: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
cloud, err := cloudprovider.InitCloudProvider(s.CloudProvider, s.CloudConfigFile)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
glog.V(2).Infof("Successfully initialized cloud provider: %q from the config file: %q\n", s.CloudProvider, s.CloudConfigFile)
|
|
|
|
kcfg.Cloud = cloud
|
|
|
|
}
|
|
|
|
|
2015-08-13 14:05:32 +00:00
|
|
|
if kcfg.CAdvisorInterface == nil {
|
2015-10-10 00:09:53 +00:00
|
|
|
kcfg.CAdvisorInterface, err = cadvisor.New(s.CAdvisorPort)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if kcfg.ContainerManager == nil {
|
2016-02-05 01:49:17 +00:00
|
|
|
if kcfg.SystemContainer != "" && kcfg.CgroupRoot == "" {
|
|
|
|
return fmt.Errorf("invalid configuration: system container was specified and cgroup root was not specified")
|
|
|
|
}
|
|
|
|
|
|
|
|
kcfg.ContainerManager, err = cm.NewContainerManager(kcfg.Mounter, kcfg.CAdvisorInterface, cm.NodeConfig{
|
|
|
|
RuntimeContainerName: kcfg.RuntimeContainer,
|
|
|
|
SystemContainerName: kcfg.SystemContainer,
|
|
|
|
KubeletContainerName: kcfg.ResourceContainer,
|
|
|
|
ContainerRuntime: kcfg.ContainerRuntime,
|
|
|
|
})
|
2015-07-01 19:02:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-15 07:32:10 +00:00
|
|
|
runtime.ReallyCrash = s.ReallyCrashForTesting
|
2015-07-01 19:02:30 +00:00
|
|
|
rand.Seed(time.Now().UTC().UnixNano())
|
|
|
|
|
|
|
|
credentialprovider.SetPreferredDockercfgPath(s.RootDirectory)
|
|
|
|
|
|
|
|
glog.V(2).Infof("Using root directory: %v", s.RootDirectory)
|
|
|
|
|
|
|
|
// TODO(vmarmol): Do this through container config.
|
2015-09-30 10:55:37 +00:00
|
|
|
oomAdjuster := kcfg.OOMAdjuster
|
2015-09-28 08:00:43 +00:00
|
|
|
if err := oomAdjuster.ApplyOOMScoreAdj(0, s.OOMScoreAdj); err != nil {
|
2015-07-01 19:02:30 +00:00
|
|
|
glog.Warning(err)
|
2015-02-02 21:30:31 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 09:19:39 +00:00
|
|
|
if err := RunKubelet(kcfg); 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-01-11 20:28:09 +00:00
|
|
|
err := http.ListenAndServe(net.JoinHostPort(s.HealthzBindAddress, strconv.Itoa(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
|
|
|
|
2015-05-16 20:12:33 +00:00
|
|
|
// run forever
|
|
|
|
select {}
|
2015-02-02 21:30:31 +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.
|
2015-12-24 23:46:56 +00:00
|
|
|
func InitializeTLS(s *options.KubeletServer) (*server.TLSOptions, error) {
|
2015-06-05 11:45:40 +00:00
|
|
|
if s.TLSCertFile == "" && s.TLSPrivateKeyFile == "" {
|
|
|
|
s.TLSCertFile = path.Join(s.CertDirectory, "kubelet.crt")
|
|
|
|
s.TLSPrivateKeyFile = path.Join(s.CertDirectory, "kubelet.key")
|
2015-07-03 17:21:29 +00:00
|
|
|
if err := util.GenerateSelfSignedCert(nodeutil.GetHostname(s.HostnameOverride), s.TLSCertFile, s.TLSPrivateKeyFile, nil, nil); err != nil {
|
2015-06-05 11:45:40 +00:00
|
|
|
return nil, fmt.Errorf("unable to generate self signed cert: %v", err)
|
|
|
|
}
|
|
|
|
glog.V(4).Infof("Using self-signed cert (%s, %s)", s.TLSCertFile, s.TLSPrivateKeyFile)
|
|
|
|
}
|
2015-12-10 20:14:26 +00:00
|
|
|
tlsOptions := &server.TLSOptions{
|
2015-06-05 11:45:40 +00:00
|
|
|
Config: &tls.Config{
|
|
|
|
// Change default from SSLv3 to TLSv1.0 (because of POODLE vulnerability).
|
|
|
|
MinVersion: tls.VersionTLS10,
|
|
|
|
// Populate PeerCertificates in requests, but don't yet reject connections without certificates.
|
|
|
|
ClientAuth: tls.RequestClientCert,
|
|
|
|
},
|
|
|
|
CertFile: s.TLSCertFile,
|
|
|
|
KeyFile: s.TLSPrivateKeyFile,
|
|
|
|
}
|
|
|
|
return tlsOptions, nil
|
|
|
|
}
|
|
|
|
|
2015-12-24 23:46:56 +00:00
|
|
|
func authPathClientConfig(s *options.KubeletServer, useDefaults bool) (*client.Config, error) {
|
2015-05-12 03:44:13 +00:00
|
|
|
authInfo, err := clientauth.LoadFromFile(s.AuthPath.Value())
|
|
|
|
if err != nil && !useDefaults {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// If loading the default auth path, for backwards compatibility keep going
|
|
|
|
// with the default auth.
|
2015-01-07 15:18:56 +00:00
|
|
|
if err != nil {
|
2015-05-12 03:44:13 +00:00
|
|
|
glog.Warningf("Could not load kubernetes auth path %s: %v. Continuing with defaults.", s.AuthPath, err)
|
2015-01-31 02:07:07 +00:00
|
|
|
}
|
|
|
|
if authInfo == nil {
|
|
|
|
// authInfo didn't load correctly - continue with defaults.
|
|
|
|
authInfo = &clientauth.Info{}
|
2015-01-07 15:18:56 +00:00
|
|
|
}
|
2015-05-12 03:44:13 +00:00
|
|
|
authConfig, err := authInfo.MergeWithConfig(client.Config{})
|
2015-01-07 15:18:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-05-12 03:44:13 +00:00
|
|
|
authConfig.Host = s.APIServerList[0]
|
|
|
|
return &authConfig, nil
|
|
|
|
}
|
|
|
|
|
2015-12-24 23:46:56 +00:00
|
|
|
func kubeconfigClientConfig(s *options.KubeletServer) (*client.Config, error) {
|
2015-05-12 03:44:13 +00:00
|
|
|
return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
|
|
|
|
&clientcmd.ClientConfigLoadingRules{ExplicitPath: s.KubeConfig.Value()},
|
|
|
|
&clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: s.APIServerList[0]}}).ClientConfig()
|
|
|
|
}
|
|
|
|
|
|
|
|
// createClientConfig creates a client configuration from the command line
|
|
|
|
// arguments. If either --auth-path or --kubeconfig is explicitly set, it
|
|
|
|
// will be used (setting both is an error). If neither are set first attempt
|
|
|
|
// to load the default kubeconfig file, then the default auth path file, and
|
|
|
|
// fall back to the default auth (none) without an error.
|
|
|
|
// TODO(roberthbailey): Remove support for --auth-path
|
2015-12-24 23:46:56 +00:00
|
|
|
func createClientConfig(s *options.KubeletServer) (*client.Config, error) {
|
2015-05-12 03:44:13 +00:00
|
|
|
if s.KubeConfig.Provided() && s.AuthPath.Provided() {
|
|
|
|
return nil, fmt.Errorf("cannot specify both --kubeconfig and --auth-path")
|
|
|
|
}
|
|
|
|
if s.KubeConfig.Provided() {
|
2015-12-24 23:46:56 +00:00
|
|
|
return kubeconfigClientConfig(s)
|
|
|
|
}
|
|
|
|
if s.AuthPath.Provided() {
|
|
|
|
return authPathClientConfig(s, false)
|
2015-05-12 03:44:13 +00:00
|
|
|
}
|
|
|
|
// Try the kubeconfig default first, falling back to the auth path default.
|
2015-12-24 23:46:56 +00:00
|
|
|
clientConfig, err := kubeconfigClientConfig(s)
|
2015-05-12 03:44:13 +00:00
|
|
|
if err != nil {
|
|
|
|
glog.Warningf("Could not load kubeconfig file %s: %v. Trying auth path instead.", s.KubeConfig, err)
|
2015-12-24 23:46:56 +00:00
|
|
|
return authPathClientConfig(s, true)
|
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).
|
2015-12-24 23:46:56 +00:00
|
|
|
func CreateAPIServerClientConfig(s *options.KubeletServer) (*client.Config, error) {
|
2015-02-02 21:30:31 +00:00
|
|
|
if len(s.APIServerList) < 1 {
|
|
|
|
return nil, fmt.Errorf("no api servers specified")
|
2015-01-07 15:18:56 +00:00
|
|
|
}
|
|
|
|
// TODO: adapt Kube client to support LB over several servers
|
2015-02-02 21:30:31 +00:00
|
|
|
if len(s.APIServerList) > 1 {
|
2015-01-18 07:32:34 +00:00
|
|
|
glog.Infof("Multiple api servers specified. Picking first one")
|
2015-01-07 15:18:56 +00:00
|
|
|
}
|
2015-04-11 16:45:45 +00:00
|
|
|
|
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
|
|
|
|
|
|
|
// Override kubeconfig qps/burst settings from flags
|
2015-10-20 12:33:48 +00:00
|
|
|
clientConfig.QPS = s.KubeAPIQPS
|
|
|
|
clientConfig.Burst = 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.
|
2015-12-24 23:46:56 +00:00
|
|
|
func addChaosToClientConfig(s *options.KubeletServer, config *client.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))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-11 23:40:20 +00:00
|
|
|
// SimpleRunKubelet is a simple way to start a Kubelet talking to dockerEndpoint, using an API Client.
|
2014-11-27 21:28:56 +00:00
|
|
|
// Under the hood it calls RunKubelet (below)
|
2016-02-01 22:30:47 +00:00
|
|
|
func SimpleKubelet(client *clientset.Clientset,
|
2015-01-08 15:25:14 +00:00
|
|
|
dockerClient dockertools.DockerInterface,
|
|
|
|
hostname, rootDir, manifestURL, address string,
|
|
|
|
port uint,
|
2015-09-09 11:05:22 +00:00
|
|
|
readOnlyPort uint,
|
2014-11-23 15:47:25 +00:00
|
|
|
masterServiceNamespace string,
|
2015-03-19 05:18:31 +00:00
|
|
|
volumePlugins []volume.VolumePlugin,
|
2015-12-10 20:14:26 +00:00
|
|
|
tlsOptions *server.TLSOptions,
|
2015-03-09 22:46:47 +00:00
|
|
|
cadvisorInterface cadvisor.Interface,
|
2015-03-23 22:31:13 +00:00
|
|
|
configFilePath string,
|
2015-04-21 00:26:40 +00:00
|
|
|
cloud cloudprovider.Interface,
|
2015-09-09 11:05:22 +00:00
|
|
|
osInterface kubecontainer.OSInterface,
|
2016-01-04 20:03:28 +00:00
|
|
|
fileCheckFrequency, httpCheckFrequency, minimumGCAge, nodeStatusUpdateFrequency, syncFrequency, outOfDiskTransitionFrequency time.Duration,
|
2015-09-01 13:35:38 +00:00
|
|
|
maxPods int,
|
2015-10-14 17:34:29 +00:00
|
|
|
containerManager cm.ContainerManager, clusterDNS net.IP) *KubeletConfig {
|
2015-03-16 04:00:46 +00:00
|
|
|
imageGCPolicy := kubelet.ImageGCPolicy{
|
|
|
|
HighThresholdPercent: 90,
|
|
|
|
LowThresholdPercent: 80,
|
|
|
|
}
|
2015-05-12 08:24:08 +00:00
|
|
|
diskSpacePolicy := kubelet.DiskSpacePolicy{
|
|
|
|
DockerFreeDiskMB: 256,
|
|
|
|
RootFreeDiskMB: 256,
|
|
|
|
}
|
2015-09-14 09:51:40 +00:00
|
|
|
|
2014-11-27 21:28:56 +00:00
|
|
|
kcfg := KubeletConfig{
|
2015-09-09 11:10:08 +00:00
|
|
|
Address: net.ParseIP(address),
|
2015-08-13 14:05:32 +00:00
|
|
|
CAdvisorInterface: cadvisorInterface,
|
2016-01-14 19:19:26 +00:00
|
|
|
VolumeStatsAggPeriod: time.Minute,
|
2015-05-13 22:50:23 +00:00
|
|
|
CgroupRoot: "",
|
2015-09-09 11:10:08 +00:00
|
|
|
Cloud: cloud,
|
2015-10-14 17:34:29 +00:00
|
|
|
ClusterDNS: clusterDNS,
|
2015-09-09 11:10:08 +00:00
|
|
|
ConfigFile: configFilePath,
|
2015-10-10 00:09:53 +00:00
|
|
|
ContainerManager: containerManager,
|
2015-05-01 21:24:07 +00:00
|
|
|
ContainerRuntime: "docker",
|
2016-01-21 01:32:17 +00:00
|
|
|
CPUCFSQuota: true,
|
2015-09-09 11:10:08 +00:00
|
|
|
DiskSpacePolicy: diskSpacePolicy,
|
|
|
|
DockerClient: dockerClient,
|
2016-02-09 21:39:23 +00:00
|
|
|
RuntimeContainer: "",
|
2015-05-27 12:51:01 +00:00
|
|
|
DockerExecHandler: &dockertools.NativeExecHandler{},
|
2016-01-21 16:44:28 +00:00
|
|
|
EnableCustomMetrics: false,
|
2015-09-09 11:10:08 +00:00
|
|
|
EnableDebuggingHandlers: true,
|
|
|
|
EnableServer: true,
|
|
|
|
FileCheckFrequency: fileCheckFrequency,
|
|
|
|
HostnameOverride: hostname,
|
|
|
|
HTTPCheckFrequency: httpCheckFrequency,
|
|
|
|
ImageGCPolicy: imageGCPolicy,
|
|
|
|
KubeClient: client,
|
|
|
|
ManifestURL: manifestURL,
|
|
|
|
MasterServiceNamespace: masterServiceNamespace,
|
|
|
|
MaxContainerCount: 100,
|
2015-09-22 21:41:18 +00:00
|
|
|
MaxOpenFiles: 1024,
|
2015-09-09 11:10:08 +00:00
|
|
|
MaxPerPodContainerCount: 2,
|
2015-09-01 13:35:38 +00:00
|
|
|
MaxPods: maxPods,
|
2015-09-09 11:10:08 +00:00
|
|
|
MinimumGCAge: minimumGCAge,
|
|
|
|
Mounter: mount.New(),
|
|
|
|
NodeStatusUpdateFrequency: nodeStatusUpdateFrequency,
|
2015-09-30 10:55:37 +00:00
|
|
|
OOMAdjuster: oom.NewFakeOOMAdjuster(),
|
2015-09-09 11:10:08 +00:00
|
|
|
OSInterface: osInterface,
|
2015-12-24 23:46:56 +00:00
|
|
|
PodInfraContainerImage: kubetypes.PodInfraContainerImage,
|
2015-09-16 04:53:33 +00:00
|
|
|
Port: port,
|
|
|
|
ReadOnlyPort: readOnlyPort,
|
|
|
|
RegisterNode: true,
|
|
|
|
RegisterSchedulable: true,
|
2015-11-23 23:41:56 +00:00
|
|
|
RegistryBurst: 10,
|
|
|
|
RegistryPullQPS: 5.0,
|
2015-12-24 23:46:56 +00:00
|
|
|
ResolverConfig: kubetypes.ResolvConfDefault,
|
2015-09-16 04:53:33 +00:00
|
|
|
ResourceContainer: "/kubelet",
|
|
|
|
RootDirectory: rootDir,
|
2015-10-20 21:49:44 +00:00
|
|
|
SerializeImagePulls: true,
|
2015-09-16 04:53:33 +00:00
|
|
|
SyncFrequency: syncFrequency,
|
|
|
|
SystemContainer: "",
|
|
|
|
TLSOptions: tlsOptions,
|
|
|
|
VolumePlugins: volumePlugins,
|
2015-10-10 00:09:53 +00:00
|
|
|
Writer: &io.StdWriter{},
|
2016-01-04 20:03:28 +00:00
|
|
|
OutOfDiskTransitionFrequency: outOfDiskTransitionFrequency,
|
2014-11-27 21:28:56 +00:00
|
|
|
}
|
2015-03-23 03:02:18 +00:00
|
|
|
return &kcfg
|
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
|
2015-09-23 09:19:39 +00:00
|
|
|
func RunKubelet(kcfg *KubeletConfig) error {
|
2015-05-26 23:13:00 +00:00
|
|
|
kcfg.Hostname = nodeutil.GetHostname(kcfg.HostnameOverride)
|
2015-06-12 15:42:38 +00:00
|
|
|
|
2015-06-17 20:40:34 +00:00
|
|
|
if len(kcfg.NodeName) == 0 {
|
2015-06-12 15:42:38 +00:00
|
|
|
// Query the cloud provider for our node name, default to Hostname
|
|
|
|
nodeName := kcfg.Hostname
|
|
|
|
if kcfg.Cloud != nil {
|
|
|
|
var err error
|
|
|
|
instances, ok := kcfg.Cloud.Instances()
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("failed to get instances from cloud provider")
|
|
|
|
}
|
|
|
|
|
|
|
|
nodeName, err = instances.CurrentNodeName(kcfg.Hostname)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error fetching current instance name from cloud provider: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
glog.V(2).Infof("cloud provider determined current node name to be %s", nodeName)
|
|
|
|
}
|
|
|
|
|
|
|
|
kcfg.NodeName = nodeName
|
|
|
|
}
|
2015-06-12 15:40:34 +00:00
|
|
|
|
2015-03-17 04:03:07 +00:00
|
|
|
eventBroadcaster := record.NewBroadcaster()
|
2015-06-12 15:40:34 +00:00
|
|
|
kcfg.Recorder = eventBroadcaster.NewRecorder(api.EventSource{Component: "kubelet", Host: kcfg.NodeName})
|
2015-06-17 20:40:34 +00:00
|
|
|
eventBroadcaster.StartLogging(glog.V(3).Infof)
|
2015-11-20 17:13:41 +00:00
|
|
|
if kcfg.EventClient != nil {
|
2015-05-16 20:12:33 +00:00
|
|
|
glog.V(4).Infof("Sending events to api server.")
|
2016-02-03 21:21:05 +00:00
|
|
|
eventBroadcaster.StartRecordingToSink(&unversioned_core.EventSinkImpl{kcfg.EventClient.Events("")})
|
2015-01-07 15:18:56 +00:00
|
|
|
} else {
|
2015-05-16 20:12:33 +00:00
|
|
|
glog.Warning("No api server defined - no events will be sent to API server.")
|
2015-01-07 15:18:56 +00:00
|
|
|
}
|
2015-08-24 17:41:51 +00:00
|
|
|
|
|
|
|
privilegedSources := capabilities.PrivilegedSources{
|
|
|
|
HostNetworkSources: kcfg.HostNetworkSources,
|
2015-09-15 16:43:59 +00:00
|
|
|
HostPIDSources: kcfg.HostPIDSources,
|
2015-08-10 08:14:01 +00:00
|
|
|
HostIPCSources: kcfg.HostIPCSources,
|
2015-08-24 17:41:51 +00:00
|
|
|
}
|
|
|
|
capabilities.Setup(kcfg.AllowPrivileged, privilegedSources, 0)
|
2014-11-27 21:28:56 +00:00
|
|
|
|
2015-01-27 20:16:47 +00:00
|
|
|
credentialprovider.SetPreferredDockercfgPath(kcfg.RootDirectory)
|
|
|
|
|
2015-09-23 09:19:39 +00:00
|
|
|
builder := kcfg.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
|
|
|
}
|
2015-04-21 00:26:40 +00:00
|
|
|
if kcfg.OSInterface == nil {
|
2015-04-27 20:03:55 +00:00
|
|
|
kcfg.OSInterface = kubecontainer.RealOS{}
|
2015-04-21 00:26:40 +00:00
|
|
|
}
|
2015-03-26 12:31:54 +00:00
|
|
|
k, podCfg, err := builder(kcfg)
|
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
|
|
|
|
|
|
|
util.ApplyRLimitForSelf(kcfg.MaxOpenFiles)
|
|
|
|
|
2014-11-27 21:28:56 +00:00
|
|
|
// process pods and exit.
|
|
|
|
if kcfg.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
|
|
|
}
|
2015-12-05 02:01:29 +00:00
|
|
|
glog.Info("Started kubelet as runonce")
|
2014-11-27 21:28:56 +00:00
|
|
|
} else {
|
2015-02-02 21:30:31 +00:00
|
|
|
startKubelet(k, podCfg, kcfg)
|
2015-12-05 02:01:29 +00:00
|
|
|
glog.Info("Started kubelet")
|
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
|
|
|
}
|
|
|
|
|
2015-03-26 12:31:54 +00:00
|
|
|
func startKubelet(k KubeletBootstrap, podCfg *config.PodConfig, kc *KubeletConfig) {
|
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
|
|
|
|
if kc.EnableServer {
|
2016-02-02 10:57:06 +00:00
|
|
|
go wait.Until(func() {
|
2015-09-29 03:32:20 +00:00
|
|
|
k.ListenAndServe(kc.Address, kc.Port, kc.TLSOptions, kc.Auth, kc.EnableDebuggingHandlers)
|
2016-02-02 10:57:06 +00:00
|
|
|
}, 0, wait.NeverStop)
|
2014-11-27 21:28:56 +00:00
|
|
|
}
|
2015-04-02 04:41:32 +00:00
|
|
|
if kc.ReadOnlyPort > 0 {
|
2016-02-02 10:57:06 +00:00
|
|
|
go wait.Until(func() {
|
2015-08-05 19:42:13 +00:00
|
|
|
k.ListenAndServeReadOnly(kc.Address, kc.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
|
|
|
}
|
|
|
|
|
|
|
|
func makePodSourceConfig(kc *KubeletConfig) *config.PodConfig {
|
|
|
|
// source of all configuration
|
2015-08-19 00:52:26 +00:00
|
|
|
cfg := config.NewPodConfig(config.PodConfigNotificationIncremental, kc.Recorder)
|
2014-11-27 21:28:56 +00:00
|
|
|
|
|
|
|
// define file config source
|
|
|
|
if kc.ConfigFile != "" {
|
2014-12-17 05:11:27 +00:00
|
|
|
glog.Infof("Adding manifest file: %v", kc.ConfigFile)
|
2015-10-09 17:24:31 +00:00
|
|
|
config.NewSourceFile(kc.ConfigFile, kc.NodeName, kc.FileCheckFrequency, cfg.Channel(kubetypes.FileSource))
|
2014-11-27 21:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// define url config source
|
|
|
|
if kc.ManifestURL != "" {
|
2015-07-30 16:28:47 +00:00
|
|
|
glog.Infof("Adding manifest url %q with HTTP header %v", kc.ManifestURL, kc.ManifestURLHeader)
|
2015-10-09 17:24:31 +00:00
|
|
|
config.NewSourceURL(kc.ManifestURL, kc.ManifestURLHeader, kc.NodeName, kc.HTTPCheckFrequency, cfg.Channel(kubetypes.HTTPSource))
|
2014-11-27 21:28:56 +00:00
|
|
|
}
|
2015-01-17 00:38:09 +00:00
|
|
|
if kc.KubeClient != nil {
|
2014-11-21 21:14:30 +00:00
|
|
|
glog.Infof("Watching apiserver")
|
2015-10-09 17:24:31 +00:00
|
|
|
config.NewSourceApiserver(kc.KubeClient, kc.NodeName, cfg.Channel(kubetypes.ApiserverSource))
|
2014-11-21 21:14:30 +00:00
|
|
|
}
|
2014-11-27 21:28:56 +00:00
|
|
|
return cfg
|
|
|
|
}
|
|
|
|
|
2015-02-02 21:30:31 +00:00
|
|
|
// KubeletConfig is all of the parameters necessary for running a kubelet.
|
|
|
|
// TODO: This should probably be merged with KubeletServer. The extra object is a consequence of refactoring.
|
2014-11-27 21:28:56 +00:00
|
|
|
type KubeletConfig struct {
|
2015-08-05 19:42:13 +00:00
|
|
|
Address net.IP
|
2015-01-08 20:41:38 +00:00
|
|
|
AllowPrivileged bool
|
2015-12-10 20:14:26 +00:00
|
|
|
Auth server.AuthInterface
|
2015-09-23 09:19:39 +00:00
|
|
|
Builder KubeletBuilder
|
2015-08-13 14:05:32 +00:00
|
|
|
CAdvisorInterface cadvisor.Interface
|
2016-01-14 19:19:26 +00:00
|
|
|
VolumeStatsAggPeriod time.Duration
|
2015-09-09 11:10:08 +00:00
|
|
|
CgroupRoot string
|
|
|
|
Cloud cloudprovider.Interface
|
|
|
|
ClusterDNS net.IP
|
|
|
|
ClusterDomain string
|
2015-01-08 20:41:38 +00:00
|
|
|
ConfigFile string
|
2015-09-09 11:10:08 +00:00
|
|
|
ConfigureCBR0 bool
|
2015-10-10 00:09:53 +00:00
|
|
|
ContainerManager cm.ContainerManager
|
2015-09-09 11:10:08 +00:00
|
|
|
ContainerRuntime string
|
|
|
|
CPUCFSQuota bool
|
|
|
|
DiskSpacePolicy kubelet.DiskSpacePolicy
|
|
|
|
DockerClient dockertools.DockerInterface
|
2016-02-05 01:49:17 +00:00
|
|
|
RuntimeContainer string
|
2015-09-09 11:10:08 +00:00
|
|
|
DockerExecHandler dockertools.ExecHandler
|
2016-01-21 16:44:28 +00:00
|
|
|
EnableCustomMetrics bool
|
2015-09-09 11:10:08 +00:00
|
|
|
EnableDebuggingHandlers bool
|
|
|
|
EnableServer bool
|
2016-02-01 22:30:47 +00:00
|
|
|
EventClient *clientset.Clientset
|
2015-09-09 11:10:08 +00:00
|
|
|
EventBurst int
|
|
|
|
EventRecordQPS float32
|
2015-01-08 20:41:38 +00:00
|
|
|
FileCheckFrequency time.Duration
|
|
|
|
Hostname string
|
2015-09-09 11:10:08 +00:00
|
|
|
HostnameOverride string
|
|
|
|
HostNetworkSources []string
|
2015-09-15 16:43:59 +00:00
|
|
|
HostPIDSources []string
|
2015-08-10 08:14:01 +00:00
|
|
|
HostIPCSources []string
|
2015-09-09 11:10:08 +00:00
|
|
|
HTTPCheckFrequency time.Duration
|
|
|
|
ImageGCPolicy kubelet.ImageGCPolicy
|
2016-02-01 22:30:47 +00:00
|
|
|
KubeClient *clientset.Clientset
|
2015-09-09 11:10:08 +00:00
|
|
|
ManifestURL string
|
|
|
|
ManifestURLHeader http.Header
|
|
|
|
MasterServiceNamespace string
|
|
|
|
MaxContainerCount int
|
2015-09-22 21:41:18 +00:00
|
|
|
MaxOpenFiles uint64
|
2015-09-09 11:10:08 +00:00
|
|
|
MaxPerPodContainerCount int
|
|
|
|
MaxPods int
|
|
|
|
MinimumGCAge time.Duration
|
|
|
|
Mounter mount.Interface
|
|
|
|
NetworkPluginName string
|
|
|
|
NetworkPlugins []network.NetworkPlugin
|
2015-06-12 15:40:34 +00:00
|
|
|
NodeName string
|
2016-01-13 23:56:51 +00:00
|
|
|
NodeLabels map[string]string
|
2015-09-09 11:10:08 +00:00
|
|
|
NodeStatusUpdateFrequency time.Duration
|
2016-01-07 20:44:40 +00:00
|
|
|
NonMasqueradeCIDR string
|
2015-09-30 10:55:37 +00:00
|
|
|
OOMAdjuster *oom.OOMAdjuster
|
2015-09-09 11:10:08 +00:00
|
|
|
OSInterface kubecontainer.OSInterface
|
|
|
|
PodCIDR string
|
2015-09-16 04:53:33 +00:00
|
|
|
ReconcileCIDR bool
|
2015-09-23 11:05:36 +00:00
|
|
|
PodConfig *config.PodConfig
|
2015-01-08 20:41:38 +00:00
|
|
|
PodInfraContainerImage string
|
|
|
|
Port uint
|
2015-04-02 04:41:32 +00:00
|
|
|
ReadOnlyPort uint
|
2015-03-03 06:06:20 +00:00
|
|
|
Recorder record.EventRecorder
|
2015-09-09 11:10:08 +00:00
|
|
|
RegisterNode bool
|
2015-09-16 04:53:33 +00:00
|
|
|
RegisterSchedulable bool
|
2015-09-09 11:10:08 +00:00
|
|
|
RegistryBurst int
|
|
|
|
RegistryPullQPS float64
|
2015-12-12 01:51:39 +00:00
|
|
|
Reservation kubetypes.Reservation
|
2015-09-09 11:10:08 +00:00
|
|
|
ResolverConfig string
|
2015-04-14 00:30:57 +00:00
|
|
|
ResourceContainer string
|
2015-08-17 17:03:45 +00:00
|
|
|
RktPath string
|
2015-09-01 02:25:26 +00:00
|
|
|
RktStage1Image string
|
2015-09-09 11:10:08 +00:00
|
|
|
RootDirectory string
|
|
|
|
Runonce bool
|
2015-10-20 21:49:44 +00:00
|
|
|
SerializeImagePulls bool
|
2015-09-09 11:10:08 +00:00
|
|
|
StandaloneMode bool
|
|
|
|
StreamingConnectionIdleTimeout time.Duration
|
|
|
|
SyncFrequency time.Duration
|
2015-05-19 23:19:12 +00:00
|
|
|
SystemContainer string
|
2015-12-10 20:14:26 +00:00
|
|
|
TLSOptions *server.TLSOptions
|
2015-09-14 09:51:40 +00:00
|
|
|
Writer io.Writer
|
2015-09-09 11:10:08 +00:00
|
|
|
VolumePlugins []volume.VolumePlugin
|
2016-01-04 20:03:28 +00:00
|
|
|
OutOfDiskTransitionFrequency time.Duration
|
2015-11-21 03:41:32 +00:00
|
|
|
|
2015-11-24 02:11:51 +00:00
|
|
|
ExperimentalFlannelOverlay bool
|
2015-12-10 02:05:35 +00:00
|
|
|
NodeIP net.IP
|
2016-02-05 15:47:06 +00:00
|
|
|
ContainerRuntimeOptions []kubecontainer.Option
|
2016-02-08 18:52:30 +00:00
|
|
|
HairpinMode bool
|
2014-11-27 21:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 11:05:05 +00:00
|
|
|
func CreateAndInitKubelet(kc *KubeletConfig) (k KubeletBootstrap, pc *config.PodConfig, 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
|
2015-02-27 18:44:44 +00:00
|
|
|
// TODO: KubeletConfig.KubeClient should be a client interface, but client interface misses certain methods
|
|
|
|
// used by kubelet. Since NewMainKubelet expects a client interface, we need to make sure we are not passing
|
|
|
|
// a nil pointer to it when what we really want is a nil interface.
|
2016-02-01 22:30:47 +00:00
|
|
|
var kubeClient clientset.Interface
|
2015-03-26 12:31:54 +00:00
|
|
|
if kc.KubeClient != nil {
|
2015-02-27 18:44:44 +00:00
|
|
|
kubeClient = kc.KubeClient
|
2016-01-15 05:00:58 +00:00
|
|
|
// TODO: remove this when we've refactored kubelet to only use clientset.
|
2015-02-27 18:44:44 +00:00
|
|
|
}
|
2015-03-06 07:56:30 +00:00
|
|
|
|
2015-10-05 22:35:32 +00:00
|
|
|
gcPolicy := kubecontainer.ContainerGCPolicy{
|
2015-03-14 17:13:20 +00:00
|
|
|
MinAge: kc.MinimumGCAge,
|
|
|
|
MaxPerPodContainer: kc.MaxPerPodContainerCount,
|
|
|
|
MaxContainers: kc.MaxContainerCount,
|
|
|
|
}
|
|
|
|
|
2015-08-13 14:05:32 +00:00
|
|
|
daemonEndpoints := &api.NodeDaemonEndpoints{
|
|
|
|
KubeletEndpoint: api.DaemonEndpoint{Port: int(kc.Port)},
|
|
|
|
}
|
|
|
|
|
2015-09-23 11:05:36 +00:00
|
|
|
pc = kc.PodConfig
|
|
|
|
if pc == nil {
|
|
|
|
pc = makePodSourceConfig(kc)
|
|
|
|
}
|
2015-03-26 12:31:54 +00:00
|
|
|
k, err = kubelet.NewMainKubelet(
|
2014-11-27 21:28:56 +00:00
|
|
|
kc.Hostname,
|
2015-06-12 15:40:34 +00:00
|
|
|
kc.NodeName,
|
2014-11-27 21:28:56 +00:00
|
|
|
kc.DockerClient,
|
2015-02-27 18:44:44 +00:00
|
|
|
kubeClient,
|
2014-11-27 21:28:56 +00:00
|
|
|
kc.RootDirectory,
|
2015-01-21 00:59:26 +00:00
|
|
|
kc.PodInfraContainerImage,
|
2014-11-27 21:28:56 +00:00
|
|
|
kc.SyncFrequency,
|
|
|
|
float32(kc.RegistryPullQPS),
|
|
|
|
kc.RegistryBurst,
|
2015-09-09 08:57:21 +00:00
|
|
|
kc.EventRecordQPS,
|
|
|
|
kc.EventBurst,
|
2015-03-14 17:13:20 +00:00
|
|
|
gcPolicy,
|
2015-03-05 18:49:36 +00:00
|
|
|
pc.SeenAllSources,
|
2015-05-20 21:21:03 +00:00
|
|
|
kc.RegisterNode,
|
2015-09-16 04:53:33 +00:00
|
|
|
kc.RegisterSchedulable,
|
2015-06-12 17:20:26 +00:00
|
|
|
kc.StandaloneMode,
|
2014-11-12 05:21:40 +00:00
|
|
|
kc.ClusterDomain,
|
2015-08-05 19:42:13 +00:00
|
|
|
kc.ClusterDNS,
|
2014-11-23 15:47:25 +00:00
|
|
|
kc.MasterServiceNamespace,
|
2015-01-08 20:41:38 +00:00
|
|
|
kc.VolumePlugins,
|
2015-03-19 23:14:13 +00:00
|
|
|
kc.NetworkPlugins,
|
|
|
|
kc.NetworkPluginName,
|
2015-03-03 06:06:20 +00:00
|
|
|
kc.StreamingConnectionIdleTimeout,
|
2015-03-06 07:56:30 +00:00
|
|
|
kc.Recorder,
|
2015-08-13 14:05:32 +00:00
|
|
|
kc.CAdvisorInterface,
|
2015-03-23 22:31:13 +00:00
|
|
|
kc.ImageGCPolicy,
|
2015-05-12 08:24:08 +00:00
|
|
|
kc.DiskSpacePolicy,
|
2015-03-31 11:17:12 +00:00
|
|
|
kc.Cloud,
|
2015-11-13 23:59:23 +00:00
|
|
|
kc.NodeLabels,
|
2015-04-14 00:30:57 +00:00
|
|
|
kc.NodeStatusUpdateFrequency,
|
2015-04-24 00:07:52 +00:00
|
|
|
kc.OSInterface,
|
2015-05-01 21:24:07 +00:00
|
|
|
kc.CgroupRoot,
|
2015-05-04 14:43:10 +00:00
|
|
|
kc.ContainerRuntime,
|
2015-08-17 17:03:45 +00:00
|
|
|
kc.RktPath,
|
2015-09-01 02:25:26 +00:00
|
|
|
kc.RktStage1Image,
|
2015-05-12 16:59:02 +00:00
|
|
|
kc.Mounter,
|
2015-09-14 09:51:40 +00:00
|
|
|
kc.Writer,
|
2015-03-17 14:43:49 +00:00
|
|
|
kc.ConfigureCBR0,
|
2016-01-07 20:44:40 +00:00
|
|
|
kc.NonMasqueradeCIDR,
|
2015-06-24 18:10:10 +00:00
|
|
|
kc.PodCIDR,
|
2015-09-16 04:53:33 +00:00
|
|
|
kc.ReconcileCIDR,
|
2015-05-27 12:51:01 +00:00
|
|
|
kc.MaxPods,
|
2015-07-28 18:54:32 +00:00
|
|
|
kc.DockerExecHandler,
|
2015-09-01 13:27:01 +00:00
|
|
|
kc.ResolverConfig,
|
2015-08-13 14:05:32 +00:00
|
|
|
kc.CPUCFSQuota,
|
2015-09-30 10:55:37 +00:00
|
|
|
daemonEndpoints,
|
2015-10-20 21:49:44 +00:00
|
|
|
kc.OOMAdjuster,
|
|
|
|
kc.SerializeImagePulls,
|
2015-10-10 00:09:53 +00:00
|
|
|
kc.ContainerManager,
|
2016-01-04 20:03:28 +00:00
|
|
|
kc.OutOfDiskTransitionFrequency,
|
2015-11-24 02:11:51 +00:00
|
|
|
kc.ExperimentalFlannelOverlay,
|
2015-12-10 02:05:35 +00:00
|
|
|
kc.NodeIP,
|
2015-12-12 01:51:39 +00:00
|
|
|
kc.Reservation,
|
2016-01-21 16:44:28 +00:00
|
|
|
kc.EnableCustomMetrics,
|
2016-01-14 19:19:26 +00:00
|
|
|
kc.VolumeStatsAggPeriod,
|
2016-02-05 15:47:06 +00:00
|
|
|
kc.ContainerRuntimeOptions,
|
2016-02-08 18:52:30 +00:00
|
|
|
kc.HairpinMode,
|
2015-10-20 21:49:44 +00:00
|
|
|
)
|
2014-11-27 21:28:56 +00:00
|
|
|
|
2015-01-07 02:31:40 +00:00
|
|
|
if err != nil {
|
2015-03-26 12:31:54 +00:00
|
|
|
return nil, 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
|
|
|
|
2015-03-26 12:31:54 +00:00
|
|
|
return k, pc, nil
|
2014-10-27 17:04:39 +00:00
|
|
|
}
|
2015-12-12 01:51:39 +00:00
|
|
|
|
|
|
|
func parseReservation(kubeReserved, systemReserved util.ConfigurationMap) (*kubetypes.Reservation, error) {
|
|
|
|
reservation := new(kubetypes.Reservation)
|
|
|
|
if rl, err := parseResourceList(kubeReserved); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
reservation.Kubernetes = rl
|
|
|
|
}
|
|
|
|
if rl, err := parseResourceList(systemReserved); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
reservation.System = rl
|
|
|
|
}
|
|
|
|
return reservation, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseResourceList(m util.ConfigurationMap) (api.ResourceList, error) {
|
|
|
|
rl := make(api.ResourceList)
|
|
|
|
for k, v := range m {
|
|
|
|
switch api.ResourceName(k) {
|
|
|
|
// Only CPU and memory resources are supported.
|
|
|
|
case api.ResourceCPU, api.ResourceMemory:
|
|
|
|
q, err := resource.ParseQuantity(v)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
rl[api.ResourceName(k)] = *q
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("cannot reserve %q resource", k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rl, nil
|
|
|
|
}
|