mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-09 20:17:41 +00:00
Merge pull request #129006 from kokes/kubeadm_rereading_kubeconfigs
kubeadm: Do not read kubeconfig from disk repeatedly in the init phase
This commit is contained in:
commit
1f415b4e13
@ -28,6 +28,8 @@ import (
|
|||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
@ -87,6 +89,7 @@ type initData struct {
|
|||||||
cfg *kubeadmapi.InitConfiguration
|
cfg *kubeadmapi.InitConfiguration
|
||||||
skipTokenPrint bool
|
skipTokenPrint bool
|
||||||
dryRun bool
|
dryRun bool
|
||||||
|
kubeconfig *clientcmdapi.Config
|
||||||
kubeconfigDir string
|
kubeconfigDir string
|
||||||
kubeconfigPath string
|
kubeconfigPath string
|
||||||
ignorePreflightErrors sets.Set[string]
|
ignorePreflightErrors sets.Set[string]
|
||||||
@ -456,6 +459,21 @@ func (d *initData) CertificateDir() string {
|
|||||||
return d.certificatesDir
|
return d.certificatesDir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KubeConfig returns a kubeconfig after loading it from KubeConfigPath().
|
||||||
|
func (d *initData) KubeConfig() (*clientcmdapi.Config, error) {
|
||||||
|
if d.kubeconfig != nil {
|
||||||
|
return d.kubeconfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
d.kubeconfig, err = clientcmd.LoadFromFile(d.KubeConfigPath())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.kubeconfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
// KubeConfigDir returns the path of the Kubernetes configuration folder or the temporary folder path in case of DryRun.
|
// KubeConfigDir returns the path of the Kubernetes configuration folder or the temporary folder path in case of DryRun.
|
||||||
func (d *initData) KubeConfigDir() string {
|
func (d *initData) KubeConfigDir() string {
|
||||||
if d.dryRun {
|
if d.dryRun {
|
||||||
@ -536,7 +554,11 @@ func (d *initData) Client() (clientset.Interface, error) {
|
|||||||
d.adminKubeConfigBootstrapped = true
|
d.adminKubeConfigBootstrapped = true
|
||||||
} else {
|
} else {
|
||||||
// Alternatively, just load the config pointed at the --kubeconfig path
|
// Alternatively, just load the config pointed at the --kubeconfig path
|
||||||
d.client, err = kubeconfigutil.ClientSetFromFile(d.KubeConfigPath())
|
cfg, err := d.KubeConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
d.client, err = kubeconfigutil.ToClientSet(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,10 @@ func runBootstrapToken(c workflow.RunData) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
kubeconfig, err := data.KubeConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if !data.SkipTokenPrint() {
|
if !data.SkipTokenPrint() {
|
||||||
tokens := data.Tokens()
|
tokens := data.Tokens()
|
||||||
@ -106,7 +110,7 @@ func runBootstrapToken(c workflow.RunData) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the cluster-info ConfigMap with the associated RBAC rules
|
// Create the cluster-info ConfigMap with the associated RBAC rules
|
||||||
if err := clusterinfophase.CreateBootstrapConfigMapIfNotExists(client, data.KubeConfigPath()); err != nil {
|
if err := clusterinfophase.CreateBootstrapConfigMapIfNotExists(client, kubeconfig); err != nil {
|
||||||
return errors.Wrap(err, "error creating bootstrap ConfigMap")
|
return errors.Wrap(err, "error creating bootstrap ConfigMap")
|
||||||
}
|
}
|
||||||
if err := clusterinfophase.CreateClusterInfoRBACRules(client); err != nil {
|
if err := clusterinfophase.CreateClusterInfoRBACRules(client); err != nil {
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
|
|
||||||
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -38,6 +39,7 @@ type InitData interface {
|
|||||||
IgnorePreflightErrors() sets.Set[string]
|
IgnorePreflightErrors() sets.Set[string]
|
||||||
CertificateWriteDir() string
|
CertificateWriteDir() string
|
||||||
CertificateDir() string
|
CertificateDir() string
|
||||||
|
KubeConfig() (*clientcmdapi.Config, error)
|
||||||
KubeConfigDir() string
|
KubeConfigDir() string
|
||||||
KubeConfigPath() string
|
KubeConfigPath() string
|
||||||
ManifestDir() string
|
ManifestDir() string
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
|
|
||||||
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -41,6 +42,7 @@ func (t *testInitData) SkipTokenPrint() bool { r
|
|||||||
func (t *testInitData) IgnorePreflightErrors() sets.Set[string] { return nil }
|
func (t *testInitData) IgnorePreflightErrors() sets.Set[string] { return nil }
|
||||||
func (t *testInitData) CertificateWriteDir() string { return "" }
|
func (t *testInitData) CertificateWriteDir() string { return "" }
|
||||||
func (t *testInitData) CertificateDir() string { return "" }
|
func (t *testInitData) CertificateDir() string { return "" }
|
||||||
|
func (t *testInitData) KubeConfig() (*clientcmdapi.Config, error) { return nil, nil }
|
||||||
func (t *testInitData) KubeConfigDir() string { return "" }
|
func (t *testInitData) KubeConfigDir() string { return "" }
|
||||||
func (t *testInitData) KubeConfigPath() string { return "" }
|
func (t *testInitData) KubeConfigPath() string { return "" }
|
||||||
func (t *testInitData) ManifestDir() string { return "" }
|
func (t *testInitData) ManifestDir() string { return "" }
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
rbac "k8s.io/api/rbac/v1"
|
rbac "k8s.io/api/rbac/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
@ -40,19 +40,20 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// CreateBootstrapConfigMapIfNotExists creates the kube-public ConfigMap if it doesn't exist already
|
// CreateBootstrapConfigMapIfNotExists creates the kube-public ConfigMap if it doesn't exist already
|
||||||
func CreateBootstrapConfigMapIfNotExists(client clientset.Interface, file string) error {
|
func CreateBootstrapConfigMapIfNotExists(client clientset.Interface, kubeconfig *clientcmdapi.Config) error {
|
||||||
|
|
||||||
fmt.Printf("[bootstrap-token] Creating the %q ConfigMap in the %q namespace\n", bootstrapapi.ConfigMapClusterInfo, metav1.NamespacePublic)
|
fmt.Printf("[bootstrap-token] Creating the %q ConfigMap in the %q namespace\n", bootstrapapi.ConfigMapClusterInfo, metav1.NamespacePublic)
|
||||||
|
|
||||||
klog.V(1).Infoln("[bootstrap-token] loading admin kubeconfig")
|
// Clone the kubeconfig so that it's not mutated.
|
||||||
adminConfig, err := clientcmd.LoadFromFile(file)
|
adminConfig := kubeconfig.DeepCopy()
|
||||||
if err != nil {
|
if err := clientcmdapi.FlattenConfig(adminConfig); err != nil {
|
||||||
return errors.Wrap(err, "failed to load admin kubeconfig")
|
|
||||||
}
|
|
||||||
if err = clientcmdapi.FlattenConfig(adminConfig); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if adminConfig.Contexts[adminConfig.CurrentContext] == nil {
|
||||||
|
return errors.New("invalid kubeconfig")
|
||||||
|
}
|
||||||
|
|
||||||
adminCluster := adminConfig.Contexts[adminConfig.CurrentContext].Cluster
|
adminCluster := adminConfig.Contexts[adminConfig.CurrentContext].Cluster
|
||||||
// Copy the cluster from admin.conf to the bootstrap kubeconfig, contains the CA cert and the server URL
|
// Copy the cluster from admin.conf to the bootstrap kubeconfig, contains the CA cert and the server URL
|
||||||
klog.V(1).Infoln("[bootstrap-token] copying the cluster from admin.conf to the bootstrap kubeconfig")
|
klog.V(1).Infoln("[bootstrap-token] copying the cluster from admin.conf to the bootstrap kubeconfig")
|
||||||
|
@ -17,8 +17,8 @@ limitations under the License.
|
|||||||
package clusterinfo
|
package clusterinfo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
@ -31,6 +31,7 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/authentication/user"
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
clientsetfake "k8s.io/client-go/kubernetes/fake"
|
clientsetfake "k8s.io/client-go/kubernetes/fake"
|
||||||
core "k8s.io/client-go/testing"
|
core "k8s.io/client-go/testing"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
bootstrapapi "k8s.io/cluster-bootstrap/token/api"
|
bootstrapapi "k8s.io/cluster-bootstrap/token/api"
|
||||||
|
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
@ -55,34 +56,24 @@ users:
|
|||||||
func TestCreateBootstrapConfigMapIfNotExists(t *testing.T) {
|
func TestCreateBootstrapConfigMapIfNotExists(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
fileExist bool
|
|
||||||
createErr error
|
createErr error
|
||||||
expectErr bool
|
expectErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"successful case should have no error",
|
"successful case should have no error",
|
||||||
true,
|
|
||||||
nil,
|
nil,
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"if configmap already exists, return error",
|
"if configmap already exists, return error",
|
||||||
true,
|
|
||||||
apierrors.NewAlreadyExists(schema.GroupResource{Resource: "configmaps"}, "test"),
|
apierrors.NewAlreadyExists(schema.GroupResource{Resource: "configmaps"}, "test"),
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"unexpected error should be returned",
|
"unexpected error should be returned",
|
||||||
true,
|
|
||||||
apierrors.NewUnauthorized("go away!"),
|
apierrors.NewUnauthorized("go away!"),
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"if the file does not exist, return error",
|
|
||||||
false,
|
|
||||||
nil,
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
servers := []struct {
|
servers := []struct {
|
||||||
@ -93,20 +84,12 @@ func TestCreateBootstrapConfigMapIfNotExists(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, server := range servers {
|
for _, server := range servers {
|
||||||
file, err := os.CreateTemp("", "")
|
var buf bytes.Buffer
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not create tempfile: %v", err)
|
|
||||||
}
|
|
||||||
defer os.Remove(file.Name())
|
|
||||||
|
|
||||||
if err := testConfigTempl.Execute(file, server); err != nil {
|
if err := testConfigTempl.Execute(&buf, server); err != nil {
|
||||||
t.Fatalf("could not write to tempfile: %v", err)
|
t.Fatalf("could not write to tempfile: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := file.Close(); err != nil {
|
|
||||||
t.Fatalf("could not close tempfile: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override the default timeouts to be shorter
|
// Override the default timeouts to be shorter
|
||||||
defaultTimeouts := kubeadmapi.GetActiveTimeouts()
|
defaultTimeouts := kubeadmapi.GetActiveTimeouts()
|
||||||
defaultAPICallTimeout := defaultTimeouts.KubernetesAPICall
|
defaultAPICallTimeout := defaultTimeouts.KubernetesAPICall
|
||||||
@ -124,11 +107,12 @@ func TestCreateBootstrapConfigMapIfNotExists(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fileName := file.Name()
|
kubeconfig, err := clientcmd.Load(buf.Bytes())
|
||||||
if !tc.fileExist {
|
if err != nil {
|
||||||
fileName = "notexistfile"
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err := CreateBootstrapConfigMapIfNotExists(client, fileName)
|
|
||||||
|
err = CreateBootstrapConfigMapIfNotExists(client, kubeconfig)
|
||||||
if tc.expectErr && err == nil {
|
if tc.expectErr && err == nil {
|
||||||
t.Errorf("CreateBootstrapConfigMapIfNotExists(%s) wanted error, got nil", tc.name)
|
t.Errorf("CreateBootstrapConfigMapIfNotExists(%s) wanted error, got nil", tc.name)
|
||||||
} else if !tc.expectErr && err != nil {
|
} else if !tc.expectErr && err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user