mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-02-22 07:03:28 +00:00
kubeadm: ensure waiting for apiserver uses a local client
When waiting for the kube-apiserver to report 'ok' in the 'init' and 'join' phase 'wait-control-plane', a client constructed from the 'admin.conf' is used. In the case of the kube-apiserver, the discovery client is used so that anonymous-auth works. But if 'admin.conf' is used as is, it would point to the CPE and not the LAE. Implement a new method WaitControlPlaneClient() for both init.go and join.go that patches the 'Server' field in the loaded v1.Config to point to the LAE, before constructing a client set and using it in the kube-apiserver waiter.
This commit is contained in:
@@ -568,24 +568,23 @@ func (d *initData) Client() (clientset.Interface, error) {
|
||||
return d.client, nil
|
||||
}
|
||||
|
||||
// ClientWithoutBootstrap returns a dry-run client or a regular client from admin.conf.
|
||||
// Unlike Client(), it does not call EnsureAdminClusterRoleBinding() or sets d.client.
|
||||
// This means the client only has anonymous permissions and does not persist in initData.
|
||||
func (d *initData) ClientWithoutBootstrap() (clientset.Interface, error) {
|
||||
var (
|
||||
client clientset.Interface
|
||||
err error
|
||||
)
|
||||
if d.dryRun {
|
||||
client, err = getDryRunClient(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else { // Use a real client
|
||||
client, err = kubeconfigutil.ClientSetFromFile(d.KubeConfigPath())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// WaitControlPlaneClient returns a basic client used for the purpose of waiting
|
||||
// for control plane components to report 'ok' on their respective health check endpoints.
|
||||
// It uses the admin.conf as the base, but modifies it to point at the local API server instead
|
||||
// of the control plane endpoint.
|
||||
func (d *initData) WaitControlPlaneClient() (clientset.Interface, error) {
|
||||
config, err := clientcmd.LoadFromFile(d.KubeConfigPath())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range config.Clusters {
|
||||
v.Server = fmt.Sprintf("https://%s:%d",
|
||||
d.Cfg().LocalAPIEndpoint.AdvertiseAddress,
|
||||
d.Cfg().LocalAPIEndpoint.BindPort)
|
||||
}
|
||||
client, err := kubeconfigutil.ToClientSet(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
@@ -625,6 +625,28 @@ func (j *joinData) Client() (clientset.Interface, error) {
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// WaitControlPlaneClient returns a basic client used for the purpose of waiting
|
||||
// for control plane components to report 'ok' on their respective health check endpoints.
|
||||
// It uses the admin.conf as the base, but modifies it to point at the local API server instead
|
||||
// of the control plane endpoint.
|
||||
func (j *joinData) WaitControlPlaneClient() (clientset.Interface, error) {
|
||||
pathAdmin := filepath.Join(j.KubeConfigDir(), kubeadmconstants.AdminKubeConfigFileName)
|
||||
config, err := clientcmd.LoadFromFile(pathAdmin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range config.Clusters {
|
||||
v.Server = fmt.Sprintf("https://%s:%d",
|
||||
j.Cfg().ControlPlane.LocalAPIEndpoint.AdvertiseAddress,
|
||||
j.Cfg().ControlPlane.LocalAPIEndpoint.BindPort)
|
||||
}
|
||||
client, err := kubeconfigutil.ToClientSet(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// IgnorePreflightErrors returns the list of preflight errors to ignore.
|
||||
func (j *joinData) IgnorePreflightErrors() sets.Set[string] {
|
||||
return j.ignorePreflightErrors
|
||||
|
||||
@@ -47,7 +47,7 @@ type InitData interface {
|
||||
ExternalCA() bool
|
||||
OutputWriter() io.Writer
|
||||
Client() (clientset.Interface, error)
|
||||
ClientWithoutBootstrap() (clientset.Interface, error)
|
||||
WaitControlPlaneClient() (clientset.Interface, error)
|
||||
Tokens() []string
|
||||
PatchesDir() string
|
||||
}
|
||||
|
||||
@@ -50,6 +50,6 @@ func (t *testInitData) KubeletDir() string { r
|
||||
func (t *testInitData) ExternalCA() bool { return false }
|
||||
func (t *testInitData) OutputWriter() io.Writer { return nil }
|
||||
func (t *testInitData) Client() (clientset.Interface, error) { return nil, nil }
|
||||
func (t *testInitData) ClientWithoutBootstrap() (clientset.Interface, error) { return nil, nil }
|
||||
func (t *testInitData) WaitControlPlaneClient() (clientset.Interface, error) { return nil, nil }
|
||||
func (t *testInitData) Tokens() []string { return nil }
|
||||
func (t *testInitData) PatchesDir() string { return "" }
|
||||
|
||||
@@ -63,8 +63,7 @@ func runWaitControlPlanePhase(c workflow.RunData) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Both Wait* calls below use a /healthz endpoint, thus a client without permissions works fine
|
||||
client, err := data.ClientWithoutBootstrap()
|
||||
client, err := data.WaitControlPlaneClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot obtain client without bootstrap")
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ type JoinData interface {
|
||||
TLSBootstrapCfg() (*clientcmdapi.Config, error)
|
||||
InitCfg() (*kubeadmapi.InitConfiguration, error)
|
||||
Client() (clientset.Interface, error)
|
||||
WaitControlPlaneClient() (clientset.Interface, error)
|
||||
IgnorePreflightErrors() sets.Set[string]
|
||||
OutputWriter() io.Writer
|
||||
PatchesDir() string
|
||||
|
||||
@@ -32,16 +32,17 @@ type testJoinData struct{}
|
||||
// testJoinData must satisfy JoinData.
|
||||
var _ JoinData = &testJoinData{}
|
||||
|
||||
func (j *testJoinData) CertificateKey() string { return "" }
|
||||
func (j *testJoinData) Cfg() *kubeadmapi.JoinConfiguration { return nil }
|
||||
func (j *testJoinData) TLSBootstrapCfg() (*clientcmdapi.Config, error) { return nil, nil }
|
||||
func (j *testJoinData) InitCfg() (*kubeadmapi.InitConfiguration, error) { return nil, nil }
|
||||
func (j *testJoinData) Client() (clientset.Interface, error) { return nil, nil }
|
||||
func (j *testJoinData) IgnorePreflightErrors() sets.Set[string] { return nil }
|
||||
func (j *testJoinData) OutputWriter() io.Writer { return nil }
|
||||
func (j *testJoinData) PatchesDir() string { return "" }
|
||||
func (j *testJoinData) DryRun() bool { return false }
|
||||
func (j *testJoinData) KubeConfigDir() string { return "" }
|
||||
func (j *testJoinData) KubeletDir() string { return "" }
|
||||
func (j *testJoinData) ManifestDir() string { return "" }
|
||||
func (j *testJoinData) CertificateWriteDir() string { return "" }
|
||||
func (j *testJoinData) CertificateKey() string { return "" }
|
||||
func (j *testJoinData) Cfg() *kubeadmapi.JoinConfiguration { return nil }
|
||||
func (j *testJoinData) TLSBootstrapCfg() (*clientcmdapi.Config, error) { return nil, nil }
|
||||
func (j *testJoinData) InitCfg() (*kubeadmapi.InitConfiguration, error) { return nil, nil }
|
||||
func (j *testJoinData) Client() (clientset.Interface, error) { return nil, nil }
|
||||
func (j *testJoinData) WaitControlPlaneClient() (clientset.Interface, error) { return nil, nil }
|
||||
func (j *testJoinData) IgnorePreflightErrors() sets.Set[string] { return nil }
|
||||
func (j *testJoinData) OutputWriter() io.Writer { return nil }
|
||||
func (j *testJoinData) PatchesDir() string { return "" }
|
||||
func (j *testJoinData) DryRun() bool { return false }
|
||||
func (j *testJoinData) KubeConfigDir() string { return "" }
|
||||
func (j *testJoinData) KubeletDir() string { return "" }
|
||||
func (j *testJoinData) ManifestDir() string { return "" }
|
||||
func (j *testJoinData) CertificateWriteDir() string { return "" }
|
||||
|
||||
@@ -67,7 +67,7 @@ func runWaitControlPlanePhase(c workflow.RunData) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
client, err := data.Client()
|
||||
client, err := data.WaitControlPlaneClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user