Separate feature gates for dynamic kubelet config vs loading from a file

This commit is contained in:
Michael Taufen 2017-08-25 14:48:16 -07:00
parent 6f4a15f922
commit 0e25cbd6a0
7 changed files with 27 additions and 31 deletions

View File

@ -20,9 +20,6 @@ go_library(
"//cmd/kubelet/app:go_default_library", "//cmd/kubelet/app:go_default_library",
"//cmd/kubelet/app/options:go_default_library", "//cmd/kubelet/app/options:go_default_library",
"//pkg/client/metrics/prometheus:go_default_library", "//pkg/client/metrics/prometheus:go_default_library",
"//pkg/features:go_default_library",
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
"//pkg/kubelet/kubeletconfig:go_default_library",
"//pkg/version/prometheus:go_default_library", "//pkg/version/prometheus:go_default_library",
"//pkg/version/verflag:go_default_library", "//pkg/version/verflag:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library", "//vendor/github.com/spf13/pflag:go_default_library",

View File

@ -112,6 +112,7 @@ go_library(
"//vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory:go_default_library", "//vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory:go_default_library",
"//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library", "//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1:go_default_library", "//vendor/k8s.io/client-go/kubernetes/typed/authentication/v1beta1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1:go_default_library", "//vendor/k8s.io/client-go/kubernetes/typed/authorization/v1beta1:go_default_library",

View File

@ -138,8 +138,8 @@ func ValidateKubeletFlags(f *KubeletFlags) error {
return fmt.Errorf("the DynamicKubeletConfig feature gate must be enabled in order to use the --dynamic-config-dir flag") return fmt.Errorf("the DynamicKubeletConfig feature gate must be enabled in order to use the --dynamic-config-dir flag")
} }
// ensure that nobody sets InitConfigDir if the dynamic config feature gate is turned off // ensure that nobody sets InitConfigDir if the dynamic config feature gate is turned off
if f.InitConfigDir.Provided() && !utilfeature.DefaultFeatureGate.Enabled(features.DynamicKubeletConfig) { if f.InitConfigDir.Provided() && !utilfeature.DefaultFeatureGate.Enabled(features.KubeletConfigFile) {
return fmt.Errorf("the DynamicKubeletConfig feature gate must be enabled in order to use the --init-config-dir flag") return fmt.Errorf("the KubeletConfigFile feature gate must be enabled in order to use the --init-config-dir flag")
} }
return nil return nil
} }

View File

@ -44,6 +44,7 @@ import (
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/server/healthz" "k8s.io/apiserver/pkg/server/healthz"
utilfeature "k8s.io/apiserver/pkg/util/feature" utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/apiserver/pkg/util/flag"
clientgoclientset "k8s.io/client-go/kubernetes" clientgoclientset "k8s.io/client-go/kubernetes"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
v1core "k8s.io/client-go/kubernetes/typed/core/v1" v1core "k8s.io/client-go/kubernetes/typed/core/v1"
@ -766,29 +767,29 @@ func parseResourceList(m kubeletconfiginternal.ConfigurationMap) (v1.ResourceLis
} }
// BootstrapKubeletConfigController constructs and bootstrap a configuration controller // BootstrapKubeletConfigController constructs and bootstrap a configuration controller
func BootstrapKubeletConfigController( func BootstrapKubeletConfigController(defaultConfig *kubeletconfiginternal.KubeletConfiguration,
flags *options.KubeletFlags, initConfigDirFlag flag.StringFlag,
defaultConfig *kubeletconfiginternal.KubeletConfiguration) (*kubeletconfiginternal.KubeletConfiguration, *kubeletconfig.Controller, error) { dynamicConfigDirFlag flag.StringFlag) (*kubeletconfiginternal.KubeletConfiguration, *kubeletconfig.Controller, error) {
var err error var err error
// Alpha Dynamic Configuration Implementation; this section only loads config from disk, it does not contact the API server // Alpha Dynamic Configuration Implementation; this section only loads config from disk, it does not contact the API server
// compute absolute paths based on current working dir // compute absolute paths based on current working dir
initConfigDir := "" initConfigDir := ""
if flags.InitConfigDir.Provided() { if utilfeature.DefaultFeatureGate.Enabled(features.KubeletConfigFile) && initConfigDirFlag.Provided() {
initConfigDir, err = filepath.Abs(flags.InitConfigDir.Value()) initConfigDir, err = filepath.Abs(initConfigDirFlag.Value())
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("failed to get absolute path for --init-config-dir") return nil, nil, fmt.Errorf("failed to get absolute path for --init-config-dir")
} }
} }
dynamicConfigDir := "" dynamicConfigDir := ""
if flags.DynamicConfigDir.Provided() { if utilfeature.DefaultFeatureGate.Enabled(features.DynamicKubeletConfig) && dynamicConfigDirFlag.Provided() {
dynamicConfigDir, err = filepath.Abs(flags.DynamicConfigDir.Value()) dynamicConfigDir, err = filepath.Abs(dynamicConfigDirFlag.Value())
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("failed to get absolute path for --dynamic-config-dir") return nil, nil, fmt.Errorf("failed to get absolute path for --dynamic-config-dir")
} }
} }
// get the latest KubeletConfiguration checkpoint from disk, or load the init or default config if no valid checkpoints exist // get the latest KubeletConfiguration checkpoint from disk, or load the init or default config if no valid checkpoints exist
kubeletConfigController, err := kubeletconfig.NewController(initConfigDir, dynamicConfigDir, defaultConfig) kubeletConfigController, err := kubeletconfig.NewController(defaultConfig, initConfigDir, dynamicConfigDir)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("failed to construct controller, error: %v", err) return nil, nil, fmt.Errorf("failed to construct controller, error: %v", err)
} }

View File

@ -32,10 +32,7 @@ import (
"k8s.io/kubernetes/cmd/kubelet/app" "k8s.io/kubernetes/cmd/kubelet/app"
"k8s.io/kubernetes/cmd/kubelet/app/options" "k8s.io/kubernetes/cmd/kubelet/app/options"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration _ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
"k8s.io/kubernetes/pkg/features" _ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration
kubeletconfiginternal "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
"k8s.io/kubernetes/pkg/kubelet/kubeletconfig"
_ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration
"k8s.io/kubernetes/pkg/version/verflag" "k8s.io/kubernetes/pkg/version/verflag"
) )
@ -75,17 +72,12 @@ func main() {
if err := options.ValidateKubeletFlags(kubeletFlags); err != nil { if err := options.ValidateKubeletFlags(kubeletFlags); err != nil {
die(err) die(err)
} }
// if dynamic kubelet config is enabled, bootstrap the kubelet config controller // bootstrap the kubelet config controller, app.BootstrapKubeletConfigController will check
var kubeletConfig *kubeletconfiginternal.KubeletConfiguration // feature gates and only turn on relevant parts of the controller
var kubeletConfigController *kubeletconfig.Controller kubeletConfig, kubeletConfigController, err := app.BootstrapKubeletConfigController(
if utilfeature.DefaultFeatureGate.Enabled(features.DynamicKubeletConfig) { defaultConfig, kubeletFlags.InitConfigDir, kubeletFlags.DynamicConfigDir)
var err error if err != nil {
kubeletConfig, kubeletConfigController, err = app.BootstrapKubeletConfigController(kubeletFlags, defaultConfig) die(err)
if err != nil {
die(err)
}
} else if kubeletConfig == nil {
kubeletConfig = defaultConfig
} }
// construct a KubeletServer from kubeletFlags and kubeletConfig // construct a KubeletServer from kubeletFlags and kubeletConfig

View File

@ -45,6 +45,10 @@ const (
// alpha: v1.4 // alpha: v1.4
DynamicKubeletConfig utilfeature.Feature = "DynamicKubeletConfig" DynamicKubeletConfig utilfeature.Feature = "DynamicKubeletConfig"
// owner: @mtaufen
// alpha: v1.8
KubeletConfigFile utilfeature.Feature = "KubeletConfigFile"
// owner: @pweil- // owner: @pweil-
// alpha: v1.5 // alpha: v1.5
// //
@ -146,6 +150,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS
ExternalTrafficLocalOnly: {Default: true, PreRelease: utilfeature.GA}, ExternalTrafficLocalOnly: {Default: true, PreRelease: utilfeature.GA},
AppArmor: {Default: true, PreRelease: utilfeature.Beta}, AppArmor: {Default: true, PreRelease: utilfeature.Beta},
DynamicKubeletConfig: {Default: false, PreRelease: utilfeature.Alpha}, DynamicKubeletConfig: {Default: false, PreRelease: utilfeature.Alpha},
KubeletConfigFile: {Default: false, PreRelease: utilfeature.Alpha},
DynamicVolumeProvisioning: {Default: true, PreRelease: utilfeature.Alpha}, DynamicVolumeProvisioning: {Default: true, PreRelease: utilfeature.Alpha},
ExperimentalHostUserNamespaceDefaultingGate: {Default: false, PreRelease: utilfeature.Beta}, ExperimentalHostUserNamespaceDefaultingGate: {Default: false, PreRelease: utilfeature.Beta},
ExperimentalCriticalPodAnnotation: {Default: false, PreRelease: utilfeature.Alpha}, ExperimentalCriticalPodAnnotation: {Default: false, PreRelease: utilfeature.Alpha},

View File

@ -78,9 +78,9 @@ type Controller struct {
// If the `initConfigDir` is an empty string, skips trying to load the init config. // If the `initConfigDir` is an empty string, skips trying to load the init config.
// If the `dynamicConfigDir` is an empty string, skips trying to load checkpoints or download new config, // If the `dynamicConfigDir` is an empty string, skips trying to load checkpoints or download new config,
// but will still sync the ConfigOK condition if you call StartSync with a non-nil client. // but will still sync the ConfigOK condition if you call StartSync with a non-nil client.
func NewController(initConfigDir string, func NewController(defaultConfig *kubeletconfig.KubeletConfiguration,
dynamicConfigDir string, initConfigDir string,
defaultConfig *kubeletconfig.KubeletConfiguration) (*Controller, error) { dynamicConfigDir string) (*Controller, error) {
var err error var err error
fs := utilfs.DefaultFs{} fs := utilfs.DefaultFs{}