From 5322cc5e02a910ced5ddd9528f269af5ed498813 Mon Sep 17 00:00:00 2001 From: xiangpengzhao Date: Sun, 19 Nov 2017 23:17:46 +0800 Subject: [PATCH 1/5] Auto generated BUILD files. --- cmd/kubeadm/app/cmd/BUILD | 1 - cmd/kubeadm/app/phases/kubelet/BUILD | 29 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cmd/kubeadm/app/cmd/BUILD b/cmd/kubeadm/app/cmd/BUILD index 195f639a333..fb3f2d7a92b 100644 --- a/cmd/kubeadm/app/cmd/BUILD +++ b/cmd/kubeadm/app/cmd/BUILD @@ -70,7 +70,6 @@ go_library( "//vendor/k8s.io/apimachinery/pkg/fields:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//vendor/k8s.io/apimachinery/pkg/version:go_default_library", "//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library", diff --git a/cmd/kubeadm/app/phases/kubelet/BUILD b/cmd/kubeadm/app/phases/kubelet/BUILD index bba6c62ad69..9c462bd2fd8 100644 --- a/cmd/kubeadm/app/phases/kubelet/BUILD +++ b/cmd/kubeadm/app/phases/kubelet/BUILD @@ -10,6 +10,7 @@ go_library( "//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/util:go_default_library", "//cmd/kubeadm/app/util/apiclient:go_default_library", + "//cmd/kubeadm/app/util/kubeconfig:go_default_library", "//pkg/apis/rbac/v1:go_default_library", "//pkg/kubelet/apis/kubeletconfig/scheme:go_default_library", "//pkg/kubelet/apis/kubeletconfig/v1alpha1:go_default_library", @@ -24,20 +25,6 @@ go_library( ], ) -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], - visibility = ["//visibility:public"], -) - go_test( name = "go_default_test", srcs = ["kubelet_test.go"], @@ -54,3 +41,17 @@ go_test( "//vendor/k8s.io/client-go/testing:go_default_library", ], ) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) From 8565ee89c58c184349ab9d86207f201858c30833 Mon Sep 17 00:00:00 2001 From: xiangpengzhao Date: Sun, 19 Nov 2017 23:17:07 +0800 Subject: [PATCH 2/5] Write marshalled kubeletconfig object to init-config-dir --- cmd/kubeadm/app/constants/constants.go | 8 ++++++++ cmd/kubeadm/app/phases/kubelet/kubelet.go | 13 +++++++++++++ 2 files changed, 21 insertions(+) diff --git a/cmd/kubeadm/app/constants/constants.go b/cmd/kubeadm/app/constants/constants.go index 0139adaea2e..77a38bca5fd 100644 --- a/cmd/kubeadm/app/constants/constants.go +++ b/cmd/kubeadm/app/constants/constants.go @@ -155,6 +155,14 @@ const ( // after https://github.com/kubernetes/kubernetes/pull/53833 being merged. KubeletBaseConfigurationConfigMapKey = "kubelet" + // KubeletBaseConfigurationDir specifies the directory on the node where stores the initial remote configuration of kubelet + KubeletBaseConfigurationDir = "/var/lib/kubelet/config/init" + + // KubeletBaseConfigurationFile specifies the file name on the node which stores initial remote configuration of kubelet + // TODO: Use the constant ("kubelet.config.k8s.io") defined in pkg/kubelet/kubeletconfig/util/keys/keys.go + // after https://github.com/kubernetes/kubernetes/pull/53833 being merged. + KubeletBaseConfigurationFile = "kubelet" + // MinExternalEtcdVersion indicates minimum external etcd version which kubeadm supports MinExternalEtcdVersion = "3.0.14" diff --git a/cmd/kubeadm/app/phases/kubelet/kubelet.go b/cmd/kubeadm/app/phases/kubelet/kubelet.go index bc42c6d1529..a9df2a28227 100644 --- a/cmd/kubeadm/app/phases/kubelet/kubelet.go +++ b/cmd/kubeadm/app/phases/kubelet/kubelet.go @@ -19,6 +19,10 @@ package kubelet import ( "encoding/json" "fmt" + "io/ioutil" + "path/filepath" + + "github.com/ghodss/yaml" "k8s.io/api/core/v1" rbac "k8s.io/api/rbac/v1" @@ -92,6 +96,15 @@ func UpdateNodeWithConfigMap(client clientset.Interface, nodeName string) error return false, nil } + baseCongfig, err := yaml.Marshal(kubeletCfg.Data[kubeadmconstants.KubeletBaseConfigurationConfigMapKey]) + if err != nil { + return false, err + } + baseCongfigFile := filepath.Join(kubeadmconstants.KubeletBaseConfigurationDir, kubeadmconstants.KubeletBaseConfigurationFile) + if err := ioutil.WriteFile(baseCongfigFile, baseCongfig, 0644); err != nil { + return false, fmt.Errorf("failed to write initial remote configuration of kubelet into file %q for node %s: %v", baseCongfigFile, nodeName, err) + } + node.Spec.ConfigSource = &v1.NodeConfigSource{ ConfigMapRef: &v1.ObjectReference{ Name: kubeadmconstants.KubeletBaseConfigurationConfigMap, From 7adced12a65a09b793fede8b5cd1c178718ca089 Mon Sep 17 00:00:00 2001 From: xiangpengzhao Date: Tue, 21 Nov 2017 17:46:21 +0800 Subject: [PATCH 3/5] Refactoring writing kubeletconfig. --- cmd/kubeadm/app/cmd/init.go | 2 +- cmd/kubeadm/app/cmd/join.go | 32 +------ cmd/kubeadm/app/phases/kubelet/kubelet.go | 91 ++++++++++++++++--- .../app/phases/kubelet/kubelet_test.go | 2 +- 4 files changed, 80 insertions(+), 47 deletions(-) diff --git a/cmd/kubeadm/app/cmd/init.go b/cmd/kubeadm/app/cmd/init.go index 458e02f8373..3bdfe3c6628 100644 --- a/cmd/kubeadm/app/cmd/init.go +++ b/cmd/kubeadm/app/cmd/init.go @@ -364,7 +364,7 @@ func (i *Init) Run(out io.Writer) error { if features.Enabled(i.cfg.FeatureGates, features.DynamicKubeletConfig) { // Create base kubelet configuration for dynamic kubelet configuration feature. if err := kubeletphase.CreateBaseKubeletConfiguration(i.cfg, client); err != nil { - return fmt.Errorf("error uploading configuration: %v", err) + return fmt.Errorf("error creating base kubelet configuration: %v", err) } } diff --git a/cmd/kubeadm/app/cmd/join.go b/cmd/kubeadm/app/cmd/join.go index 9b34fc08460..4cb94d0fb02 100644 --- a/cmd/kubeadm/app/cmd/join.go +++ b/cmd/kubeadm/app/cmd/join.go @@ -20,7 +20,6 @@ import ( "fmt" "io" "io/ioutil" - "os" "path/filepath" "strings" @@ -30,8 +29,6 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/apimachinery/pkg/util/wait" - clientset "k8s.io/client-go/kubernetes" certutil "k8s.io/client-go/util/cert" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" @@ -262,36 +259,11 @@ func (j *Join) Run(out io.Writer) error { // NOTE: flag "--dynamic-config-dir" should be specified in /etc/systemd/system/kubelet.service.d/10-kubeadm.conf if features.Enabled(j.cfg.FeatureGates, features.DynamicKubeletConfig) { - client, err := getTLSBootstrappedClient() - if err != nil { - return err - } - - // Update the node with remote base kubelet configuration - if err := kubeletphase.UpdateNodeWithConfigMap(client, j.cfg.NodeName); err != nil { - return err + if err := kubeletphase.ConsumeBaseKubeletConfiguration(j.cfg.NodeName); err != nil { + return fmt.Errorf("error consuming base kubelet configuration: %v", err) } } fmt.Fprintf(out, joinDoneMsgf) return nil } - -// getTLSBootstrappedClient waits for the kubelet to perform the TLS bootstrap -// and then creates a client from config file /etc/kubernetes/kubelet.conf -func getTLSBootstrappedClient() (clientset.Interface, error) { - fmt.Println("[tlsbootstrap] Waiting for the kubelet to perform the TLS Bootstrap...") - - kubeletKubeConfig := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.KubeletKubeConfigFileName) - - // Loop on every falsy return. Return with an error if raised. Exit successfully if true is returned. - err := wait.PollImmediateInfinite(kubeadmconstants.APICallRetryInterval, func() (bool, error) { - _, err := os.Stat(kubeletKubeConfig) - return (err == nil), nil - }) - if err != nil { - return nil, err - } - - return kubeconfigutil.ClientSetFromFile(kubeletKubeConfig) -} diff --git a/cmd/kubeadm/app/phases/kubelet/kubelet.go b/cmd/kubeadm/app/phases/kubelet/kubelet.go index a9df2a28227..5096bf8982a 100644 --- a/cmd/kubeadm/app/phases/kubelet/kubelet.go +++ b/cmd/kubeadm/app/phases/kubelet/kubelet.go @@ -20,10 +20,9 @@ import ( "encoding/json" "fmt" "io/ioutil" + "os" "path/filepath" - "github.com/ghodss/yaml" - "k8s.io/api/core/v1" rbac "k8s.io/api/rbac/v1" apierrs "k8s.io/apimachinery/pkg/api/errors" @@ -34,8 +33,10 @@ import ( clientset "k8s.io/client-go/kubernetes" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" + tokenphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" + kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" rbachelper "k8s.io/kubernetes/pkg/apis/rbac/v1" kubeletconfigscheme "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/scheme" kubeletconfigv1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1" @@ -55,6 +56,10 @@ func CreateBaseKubeletConfiguration(cfg *kubeadmapi.MasterConfiguration, client return err } + if err := writeInitKubeletConfigToDisk(kubeletBytes); err != nil { + return fmt.Errorf("failed to write initial remote configuration of kubelet to disk for node %s: %v", cfg.NodeName, err) + } + if err = apiclient.CreateOrUpdateConfigMap(client, &v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: kubeadmconstants.KubeletBaseConfigurationConfigMap, @@ -71,11 +76,30 @@ func CreateBaseKubeletConfiguration(cfg *kubeadmapi.MasterConfiguration, client return fmt.Errorf("error creating base kubelet configmap RBAC rules: %v", err) } - return UpdateNodeWithConfigMap(client, cfg.NodeName) + return updateNodeWithConfigMap(client, cfg.NodeName) } -// UpdateNodeWithConfigMap updates node ConfigSource with KubeletBaseConfigurationConfigMap -func UpdateNodeWithConfigMap(client clientset.Interface, nodeName string) error { +// ConsumeBaseKubeletConfiguration consumes base kubelet configuration for dynamic kubelet configuration feature. +func ConsumeBaseKubeletConfiguration(nodeName string) error { + client, err := getTLSBootstrappedClient() + if err != nil { + return err + } + + kubeletCfg, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(kubeadmconstants.KubeletBaseConfigurationConfigMap, metav1.GetOptions{}) + if err != nil { + return err + } + + if err := writeInitKubeletConfigToDisk([]byte(kubeletCfg.Data[kubeadmconstants.KubeletBaseConfigurationConfigMapKey])); err != nil { + return fmt.Errorf("failed to write initial remote configuration of kubelet to disk for node %s: %v", nodeName, err) + } + + return updateNodeWithConfigMap(client, nodeName) +} + +// updateNodeWithConfigMap updates node ConfigSource with KubeletBaseConfigurationConfigMap +func updateNodeWithConfigMap(client clientset.Interface, nodeName string) error { fmt.Printf("[kubelet] Using Dynamic Kubelet Config for node %q; config sourced from ConfigMap %q in namespace %s", nodeName, kubeadmconstants.KubeletBaseConfigurationConfigMap, metav1.NamespaceSystem) @@ -96,15 +120,6 @@ func UpdateNodeWithConfigMap(client clientset.Interface, nodeName string) error return false, nil } - baseCongfig, err := yaml.Marshal(kubeletCfg.Data[kubeadmconstants.KubeletBaseConfigurationConfigMapKey]) - if err != nil { - return false, err - } - baseCongfigFile := filepath.Join(kubeadmconstants.KubeletBaseConfigurationDir, kubeadmconstants.KubeletBaseConfigurationFile) - if err := ioutil.WriteFile(baseCongfigFile, baseCongfig, 0644); err != nil { - return false, fmt.Errorf("failed to write initial remote configuration of kubelet into file %q for node %s: %v", baseCongfigFile, nodeName, err) - } - node.Spec.ConfigSource = &v1.NodeConfigSource{ ConfigMapRef: &v1.ObjectReference{ Name: kubeadmconstants.KubeletBaseConfigurationConfigMap, @@ -149,7 +164,7 @@ func createKubeletBaseConfigMapRBACRules(client clientset.Interface) error { return err } - return apiclient.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{ + if err := apiclient.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ Name: kubeadmconstants.KubeletBaseConfigMapRoleName, Namespace: metav1.NamespaceSystem, @@ -165,5 +180,51 @@ func createKubeletBaseConfigMapRBACRules(client clientset.Interface) error { Name: kubeadmconstants.NodesGroup, }, }, + }); err != nil { + return err + } + + return apiclient.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: tokenphase.NodeKubeletBootstrap, + }, + RoleRef: rbac.RoleRef{ + APIGroup: rbac.GroupName, + Kind: "ClusterRole", + Name: tokenphase.NodeBootstrapperClusterRoleName, + }, + Subjects: []rbac.Subject{ + { + Kind: rbac.GroupKind, + Name: kubeadmconstants.NodeBootstrapTokenAuthGroup, + }, + }, }) } + +// getTLSBootstrappedClient waits for the kubelet to perform the TLS bootstrap +// and then creates a client from config file /etc/kubernetes/kubelet.conf +func getTLSBootstrappedClient() (clientset.Interface, error) { + fmt.Println("[tlsbootstrap] Waiting for the kubelet to perform the TLS Bootstrap...") + + kubeletKubeConfig := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.KubeletKubeConfigFileName) + + // Loop on every falsy return. Return with an error if raised. Exit successfully if true is returned. + err := wait.PollImmediateInfinite(kubeadmconstants.APICallRetryInterval, func() (bool, error) { + _, err := os.Stat(kubeletKubeConfig) + return (err == nil), nil + }) + if err != nil { + return nil, err + } + + return kubeconfigutil.ClientSetFromFile(kubeletKubeConfig) +} + +func writeInitKubeletConfigToDisk(kubeletConfig []byte) error { + baseCongfigFile := filepath.Join(kubeadmconstants.KubeletBaseConfigurationDir, kubeadmconstants.KubeletBaseConfigurationFile) + if err := ioutil.WriteFile(baseCongfigFile, kubeletConfig, 0644); err != nil { + return fmt.Errorf("failed to write initial remote configuration of kubelet into file %q: %v", baseCongfigFile, err) + } + return nil +} diff --git a/cmd/kubeadm/app/phases/kubelet/kubelet_test.go b/cmd/kubeadm/app/phases/kubelet/kubelet_test.go index 5c1d5c012c8..0b38320b715 100644 --- a/cmd/kubeadm/app/phases/kubelet/kubelet_test.go +++ b/cmd/kubeadm/app/phases/kubelet/kubelet_test.go @@ -114,7 +114,7 @@ func TestUpdateNodeWithConfigMap(t *testing.T) { return true, nil, nil }) - if err := UpdateNodeWithConfigMap(client, nodeName); err != nil { + if err := updateNodeWithConfigMap(client, nodeName); err != nil { t.Errorf("UpdateNodeWithConfigMap: unexepected error %v", err) } } From 6034ef48a9868f8240e8add51ae1701622b525cd Mon Sep 17 00:00:00 2001 From: xiangpengzhao Date: Wed, 22 Nov 2017 15:52:23 +0800 Subject: [PATCH 4/5] Fix deadlock of writing file on node. --- cmd/kubeadm/app/cmd/init.go | 8 ++++ cmd/kubeadm/app/phases/kubelet/kubelet.go | 51 ++++++++++++----------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/cmd/kubeadm/app/cmd/init.go b/cmd/kubeadm/app/cmd/init.go index 3bdfe3c6628..62b9292a536 100644 --- a/cmd/kubeadm/app/cmd/init.go +++ b/cmd/kubeadm/app/cmd/init.go @@ -338,6 +338,14 @@ func (i *Init) Run(out io.Writer) error { return fmt.Errorf("error printing files on dryrun: %v", err) } + // NOTE: flag "--dynamic-config-dir" should be specified in /etc/systemd/system/kubelet.service.d/10-kubeadm.conf + if features.Enabled(i.cfg.FeatureGates, features.DynamicKubeletConfig) { + // Write base kubelet configuration for dynamic kubelet configuration feature. + if err := kubeletphase.WriteInitKubeletConfigToDiskOnMaster(i.cfg); err != nil { + return fmt.Errorf("error writing base kubelet configuration to disk: %v", err) + } + } + // Create a kubernetes client and wait for the API server to be healthy (if not dryrunning) client, err := createClient(i.cfg, i.dryRun) if err != nil { diff --git a/cmd/kubeadm/app/phases/kubelet/kubelet.go b/cmd/kubeadm/app/phases/kubelet/kubelet.go index 5096bf8982a..79db338d1c2 100644 --- a/cmd/kubeadm/app/phases/kubelet/kubelet.go +++ b/cmd/kubeadm/app/phases/kubelet/kubelet.go @@ -33,7 +33,6 @@ import ( clientset "k8s.io/client-go/kubernetes" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" - tokenphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" @@ -56,10 +55,6 @@ func CreateBaseKubeletConfiguration(cfg *kubeadmapi.MasterConfiguration, client return err } - if err := writeInitKubeletConfigToDisk(kubeletBytes); err != nil { - return fmt.Errorf("failed to write initial remote configuration of kubelet to disk for node %s: %v", cfg.NodeName, err) - } - if err = apiclient.CreateOrUpdateConfigMap(client, &v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: kubeadmconstants.KubeletBaseConfigurationConfigMap, @@ -81,7 +76,7 @@ func CreateBaseKubeletConfiguration(cfg *kubeadmapi.MasterConfiguration, client // ConsumeBaseKubeletConfiguration consumes base kubelet configuration for dynamic kubelet configuration feature. func ConsumeBaseKubeletConfiguration(nodeName string) error { - client, err := getTLSBootstrappedClient() + client, err := getLocalNodeTLSBootstrappedClient() if err != nil { return err } @@ -164,7 +159,7 @@ func createKubeletBaseConfigMapRBACRules(client clientset.Interface) error { return err } - if err := apiclient.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{ + return apiclient.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ Name: kubeadmconstants.KubeletBaseConfigMapRoleName, Namespace: metav1.NamespaceSystem, @@ -176,24 +171,9 @@ func createKubeletBaseConfigMapRBACRules(client clientset.Interface) error { }, Subjects: []rbac.Subject{ { - Kind: "Group", + Kind: rbac.GroupKind, Name: kubeadmconstants.NodesGroup, }, - }, - }); err != nil { - return err - } - - return apiclient.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: tokenphase.NodeKubeletBootstrap, - }, - RoleRef: rbac.RoleRef{ - APIGroup: rbac.GroupName, - Kind: "ClusterRole", - Name: tokenphase.NodeBootstrapperClusterRoleName, - }, - Subjects: []rbac.Subject{ { Kind: rbac.GroupKind, Name: kubeadmconstants.NodeBootstrapTokenAuthGroup, @@ -202,9 +182,9 @@ func createKubeletBaseConfigMapRBACRules(client clientset.Interface) error { }) } -// getTLSBootstrappedClient waits for the kubelet to perform the TLS bootstrap +// getLocalNodeTLSBootstrappedClient waits for the kubelet to perform the TLS bootstrap // and then creates a client from config file /etc/kubernetes/kubelet.conf -func getTLSBootstrappedClient() (clientset.Interface, error) { +func getLocalNodeTLSBootstrappedClient() (clientset.Interface, error) { fmt.Println("[tlsbootstrap] Waiting for the kubelet to perform the TLS Bootstrap...") kubeletKubeConfig := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.KubeletKubeConfigFileName) @@ -221,6 +201,27 @@ func getTLSBootstrappedClient() (clientset.Interface, error) { return kubeconfigutil.ClientSetFromFile(kubeletKubeConfig) } +// WriteInitKubeletConfigToDiskOnMaster writes base kubelet configuration to disk on master. +func WriteInitKubeletConfigToDiskOnMaster(cfg *kubeadmapi.MasterConfiguration) error { + fmt.Printf("[kubelet] Writing base configuration of kubelets to disk on master node %s", cfg.NodeName) + + _, kubeletCodecs, err := kubeletconfigscheme.NewSchemeAndCodecs() + if err != nil { + return err + } + + kubeletBytes, err := kubeadmutil.MarshalToYamlForCodecs(cfg.KubeletConfiguration.BaseConfig, kubeletconfigv1alpha1.SchemeGroupVersion, *kubeletCodecs) + if err != nil { + return err + } + + if err := writeInitKubeletConfigToDisk(kubeletBytes); err != nil { + return fmt.Errorf("failed to write base configuration of kubelet to disk on master node %s: %v", cfg.NodeName, err) + } + + return nil +} + func writeInitKubeletConfigToDisk(kubeletConfig []byte) error { baseCongfigFile := filepath.Join(kubeadmconstants.KubeletBaseConfigurationDir, kubeadmconstants.KubeletBaseConfigurationFile) if err := ioutil.WriteFile(baseCongfigFile, kubeletConfig, 0644); err != nil { From e89927a8908f5a1edc0f79f3522ef6d88e97f164 Mon Sep 17 00:00:00 2001 From: xiangpengzhao Date: Wed, 22 Nov 2017 22:58:48 +0800 Subject: [PATCH 5/5] Should make dir before writing file. --- cmd/kubeadm/app/phases/kubelet/kubelet.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cmd/kubeadm/app/phases/kubelet/kubelet.go b/cmd/kubeadm/app/phases/kubelet/kubelet.go index 79db338d1c2..7d2ac055156 100644 --- a/cmd/kubeadm/app/phases/kubelet/kubelet.go +++ b/cmd/kubeadm/app/phases/kubelet/kubelet.go @@ -223,9 +223,12 @@ func WriteInitKubeletConfigToDiskOnMaster(cfg *kubeadmapi.MasterConfiguration) e } func writeInitKubeletConfigToDisk(kubeletConfig []byte) error { - baseCongfigFile := filepath.Join(kubeadmconstants.KubeletBaseConfigurationDir, kubeadmconstants.KubeletBaseConfigurationFile) - if err := ioutil.WriteFile(baseCongfigFile, kubeletConfig, 0644); err != nil { - return fmt.Errorf("failed to write initial remote configuration of kubelet into file %q: %v", baseCongfigFile, err) + if err := os.MkdirAll(kubeadmconstants.KubeletBaseConfigurationDir, 0644); err != nil { + return fmt.Errorf("failed to create directory %q: %v", kubeadmconstants.KubeletBaseConfigurationDir, err) + } + baseConfigFile := filepath.Join(kubeadmconstants.KubeletBaseConfigurationDir, kubeadmconstants.KubeletBaseConfigurationFile) + if err := ioutil.WriteFile(baseConfigFile, kubeletConfig, 0644); err != nil { + return fmt.Errorf("failed to write initial remote configuration of kubelet into file %q: %v", baseConfigFile, err) } return nil }