diff --git a/cmd/kubeadm/app/apis/kubeadm/fuzzer/fuzzer.go b/cmd/kubeadm/app/apis/kubeadm/fuzzer/fuzzer.go index a1768876783..f9d1c9df3ea 100644 --- a/cmd/kubeadm/app/apis/kubeadm/fuzzer/fuzzer.go +++ b/cmd/kubeadm/app/apis/kubeadm/fuzzer/fuzzer.go @@ -50,6 +50,11 @@ func fuzzInitConfiguration(obj *kubeadm.InitConfiguration, c fuzz.Continue) { // More specifically: // internal with manually applied defaults -> external object : loosing ClusterConfiguration) -> internal object with automatically applied defaults obj.ClusterConfiguration = kubeadm.ClusterConfiguration{ + APIServer: kubeadm.APIServer{ + TimeoutForControlPlane: &metav1.Duration{ + Duration: constants.DefaultControlPlaneTimeout, + }, + }, AuditPolicyConfiguration: kubeadm.AuditPolicyConfiguration{ LogDir: constants.StaticPodAuditPolicyLogDir, LogMaxAge: &v1beta1.DefaultAuditPolicyLogMaxAge, @@ -97,6 +102,9 @@ func fuzzClusterConfiguration(obj *kubeadm.ClusterConfiguration, c fuzz.Continue obj.ClusterName = "bar" obj.ImageRepository = "baz" obj.KubernetesVersion = "qux" + obj.APIServer.TimeoutForControlPlane = &metav1.Duration{ + Duration: constants.DefaultControlPlaneTimeout, + } } func fuzzAuditPolicyConfiguration(obj *kubeadm.AuditPolicyConfiguration, c fuzz.Continue) { diff --git a/cmd/kubeadm/app/apis/kubeadm/types.go b/cmd/kubeadm/app/apis/kubeadm/types.go index f97844c365a..f05188fcdc7 100644 --- a/cmd/kubeadm/app/apis/kubeadm/types.go +++ b/cmd/kubeadm/app/apis/kubeadm/types.go @@ -130,6 +130,9 @@ type APIServer struct { // CertSANs sets extra Subject Alternative Names for the API Server signing cert. CertSANs []string + + // TimeoutForControlPlane controls the timeout that we use for API server to appear + TimeoutForControlPlane *metav1.Duration } // ComponentConfigs holds known internal ComponentConfig types for other components diff --git a/cmd/kubeadm/app/apis/kubeadm/v1alpha3/conversion.go b/cmd/kubeadm/app/apis/kubeadm/v1alpha3/conversion.go index a70861256b4..bb1ac51eba2 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1alpha3/conversion.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1alpha3/conversion.go @@ -17,8 +17,10 @@ limitations under the License. package v1alpha3 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/conversion" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" + "k8s.io/kubernetes/cmd/kubeadm/app/constants" ) func Convert_v1alpha3_JoinConfiguration_To_kubeadm_JoinConfiguration(in *JoinConfiguration, out *kubeadm.JoinConfiguration, s conversion.Scope) error { @@ -84,6 +86,9 @@ func Convert_v1alpha3_ClusterConfiguration_To_kubeadm_ClusterConfiguration(in *C out.APIServer.ExtraArgs = in.APIServerExtraArgs out.APIServer.CertSANs = in.APIServerCertSANs + out.APIServer.TimeoutForControlPlane = &metav1.Duration{ + Duration: constants.DefaultControlPlaneTimeout, + } if err := convertSlice_v1alpha3_HostPathMount_To_kubeadm_HostPathMount(&in.APIServerExtraVolumes, &out.APIServer.ExtraVolumes, s); err != nil { return err } diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta1/defaults.go b/cmd/kubeadm/app/apis/kubeadm/v1beta1/defaults.go index 68564fa7720..aa56a0cfebc 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1beta1/defaults.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1beta1/defaults.go @@ -101,6 +101,16 @@ func SetDefaults_ClusterConfiguration(obj *ClusterConfiguration) { SetDefaults_Etcd(obj) SetDefaults_AuditPolicyConfiguration(obj) + SetDefaults_APIServer(&obj.APIServer) +} + +// SetDefaults_APIServer assigns default values for the API Server +func SetDefaults_APIServer(obj *APIServer) { + if obj.TimeoutForControlPlane == nil { + obj.TimeoutForControlPlane = &metav1.Duration{ + Duration: constants.DefaultControlPlaneTimeout, + } + } } // SetDefaults_Etcd assigns default values for the Proxy diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta1/doc.go b/cmd/kubeadm/app/apis/kubeadm/v1beta1/doc.go index a1fe2f351a2..e9c3843d93c 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1beta1/doc.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1beta1/doc.go @@ -212,6 +212,7 @@ limitations under the License. // certSANs: // - "10.100.1.1" // - "ec2-10-100-0-1.compute-1.amazonaws.com" +// timeoutForControlPlane: 4m0s // controllerManager: // extraArgs: // node-cidr-mask-size: 20 diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta1/types.go b/cmd/kubeadm/app/apis/kubeadm/v1beta1/types.go index 5ac764c3e44..0dd69c61c77 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1beta1/types.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1beta1/types.go @@ -120,6 +120,9 @@ type APIServer struct { // CertSANs sets extra Subject Alternative Names for the API Server signing cert. CertSANs []string `json:"certSANs,omitempty"` + + // TimeoutForControlPlane controls the timeout that we use for API server to appear + TimeoutForControlPlane *metav1.Duration `json:"timeoutForControlPlane,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta1/zz_generated.conversion.go b/cmd/kubeadm/app/apis/kubeadm/v1beta1/zz_generated.conversion.go index 36b11a3ed94..7370186920d 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1beta1/zz_generated.conversion.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1beta1/zz_generated.conversion.go @@ -257,6 +257,7 @@ func autoConvert_v1beta1_APIServer_To_kubeadm_APIServer(in *APIServer, out *kube return err } out.CertSANs = *(*[]string)(unsafe.Pointer(&in.CertSANs)) + out.TimeoutForControlPlane = (*v1.Duration)(unsafe.Pointer(in.TimeoutForControlPlane)) return nil } @@ -270,6 +271,7 @@ func autoConvert_kubeadm_APIServer_To_v1beta1_APIServer(in *kubeadm.APIServer, o return err } out.CertSANs = *(*[]string)(unsafe.Pointer(&in.CertSANs)) + out.TimeoutForControlPlane = (*v1.Duration)(unsafe.Pointer(in.TimeoutForControlPlane)) return nil } diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta1/zz_generated.deepcopy.go b/cmd/kubeadm/app/apis/kubeadm/v1beta1/zz_generated.deepcopy.go index cc2e1ad7125..72e7e81a440 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1beta1/zz_generated.deepcopy.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1beta1/zz_generated.deepcopy.go @@ -51,6 +51,11 @@ func (in *APIServer) DeepCopyInto(out *APIServer) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.TimeoutForControlPlane != nil { + in, out := &in.TimeoutForControlPlane, &out.TimeoutForControlPlane + *out = new(v1.Duration) + **out = **in + } return } diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta1/zz_generated.defaults.go b/cmd/kubeadm/app/apis/kubeadm/v1beta1/zz_generated.defaults.go index a27612cce03..799ffbb7e09 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1beta1/zz_generated.defaults.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1beta1/zz_generated.defaults.go @@ -37,6 +37,7 @@ func RegisterDefaults(scheme *runtime.Scheme) error { func SetObjectDefaults_ClusterConfiguration(in *ClusterConfiguration) { SetDefaults_ClusterConfiguration(in) + SetDefaults_APIServer(&in.APIServer) } func SetObjectDefaults_ClusterStatus(in *ClusterStatus) { diff --git a/cmd/kubeadm/app/apis/kubeadm/zz_generated.deepcopy.go b/cmd/kubeadm/app/apis/kubeadm/zz_generated.deepcopy.go index ec241bdf08d..89a0ed5709b 100644 --- a/cmd/kubeadm/app/apis/kubeadm/zz_generated.deepcopy.go +++ b/cmd/kubeadm/app/apis/kubeadm/zz_generated.deepcopy.go @@ -53,6 +53,11 @@ func (in *APIServer) DeepCopyInto(out *APIServer) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.TimeoutForControlPlane != nil { + in, out := &in.TimeoutForControlPlane, &out.TimeoutForControlPlane + *out = new(v1.Duration) + **out = **in + } return } diff --git a/cmd/kubeadm/app/cmd/init.go b/cmd/kubeadm/app/cmd/init.go index 301c3bcebae..c0c575c7c5c 100644 --- a/cmd/kubeadm/app/cmd/init.go +++ b/cmd/kubeadm/app/cmd/init.go @@ -469,8 +469,10 @@ func runInit(i *initData, out io.Writer) error { if err != nil { return errors.Wrap(err, "failed to create client") } + // TODO: NewControlPlaneWaiter should be converted to private after the self-hosting phase is removed. - waiter, err := phases.NewControlPlaneWaiter(i.dryRun, client, i.outputWriter) + timeout := i.cfg.ClusterConfiguration.APIServer.TimeoutForControlPlane.Duration + waiter, err := phases.NewControlPlaneWaiter(i.dryRun, timeout, client, i.outputWriter) if err != nil { return errors.Wrap(err, "failed to create waiter") } diff --git a/cmd/kubeadm/app/cmd/phases/waitcontrolplane.go b/cmd/kubeadm/app/cmd/phases/waitcontrolplane.go index c54cbf0a035..4c6ac4be85b 100644 --- a/cmd/kubeadm/app/cmd/phases/waitcontrolplane.go +++ b/cmd/kubeadm/app/cmd/phases/waitcontrolplane.go @@ -93,12 +93,13 @@ func runWaitControlPlanePhase(c workflow.RunData) error { return errors.Wrap(err, "cannot obtain client") } - waiter, err := NewControlPlaneWaiter(data.DryRun(), client, data.OutputWriter()) + timeout := data.Cfg().ClusterConfiguration.APIServer.TimeoutForControlPlane.Duration + waiter, err := NewControlPlaneWaiter(data.DryRun(), timeout, client, data.OutputWriter()) if err != nil { return errors.Wrap(err, "error creating waiter") } - fmt.Printf("[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory %q\n", data.ManifestDir()) + fmt.Printf("[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory %q. This can take up to %v\n", data.ManifestDir(), timeout) if err := waiter.WaitForKubeletAndFunc(waiter.WaitForAPI); err != nil { ctx := map[string]string{ @@ -143,14 +144,10 @@ func printFilesIfDryRunning(data waitControlPlaneData) error { // NewControlPlaneWaiter returns a new waiter that is used to wait on the control plane to boot up. // TODO: make private (lowercase) after self-hosting phase is removed. -func NewControlPlaneWaiter(dryRun bool, client clientset.Interface, out io.Writer) (apiclient.Waiter, error) { +func NewControlPlaneWaiter(dryRun bool, timeout time.Duration, client clientset.Interface, out io.Writer) (apiclient.Waiter, error) { if dryRun { return dryrunutil.NewWaiter(), nil } - // We know that the images should be cached locally already as we have pulled them using - // crictl in the preflight checks. Hence we can have a pretty short timeout for the kubelet - // to start creating Static Pods. - timeout := 4 * time.Minute return apiclient.NewKubeWaiter(client, timeout, out), nil } diff --git a/cmd/kubeadm/app/constants/constants.go b/cmd/kubeadm/app/constants/constants.go index 61374d5806e..71cc804b2a7 100644 --- a/cmd/kubeadm/app/constants/constants.go +++ b/cmd/kubeadm/app/constants/constants.go @@ -178,6 +178,9 @@ const ( // TLSBootstrapTimeout specifies how long kubeadm should wait for the kubelet to perform the TLS Bootstrap TLSBootstrapTimeout = 2 * time.Minute + // DefaultControlPlaneTimeout specifies the default control plane (actually API Server) timeout for use by kubeadm + DefaultControlPlaneTimeout = 4 * time.Minute + // MinimumAddressesInServiceSubnet defines minimum amount of nodes the Service subnet should allow. // We need at least ten, because the DNS service is always at the tenth cluster clusterIP MinimumAddressesInServiceSubnet = 10 diff --git a/cmd/kubeadm/app/util/config/testdata/conversion/master/internal.yaml b/cmd/kubeadm/app/util/config/testdata/conversion/master/internal.yaml index 0e876504fa1..a94f6b1b841 100644 --- a/cmd/kubeadm/app/util/config/testdata/conversion/master/internal.yaml +++ b/cmd/kubeadm/app/util/config/testdata/conversion/master/internal.yaml @@ -16,6 +16,7 @@ APIServer: Name: WritableVolume PathType: "" ReadOnly: false + TimeoutForControlPlane: 4m0s AuditPolicyConfiguration: LogDir: /var/log/kubernetes/audit LogMaxAge: 2 diff --git a/cmd/kubeadm/app/util/config/testdata/conversion/master/v1beta1.yaml b/cmd/kubeadm/app/util/config/testdata/conversion/master/v1beta1.yaml index 98be69edb87..c15ea283fea 100644 --- a/cmd/kubeadm/app/util/config/testdata/conversion/master/v1beta1.yaml +++ b/cmd/kubeadm/app/util/config/testdata/conversion/master/v1beta1.yaml @@ -29,6 +29,7 @@ apiServer: - hostPath: /host/writable mountPath: /mount/writable name: WritableVolume + timeoutForControlPlane: 4m0s apiVersion: kubeadm.k8s.io/v1beta1 auditPolicy: logDir: /var/log/kubernetes/audit diff --git a/cmd/kubeadm/app/util/config/testdata/defaulting/master/defaulted.yaml b/cmd/kubeadm/app/util/config/testdata/defaulting/master/defaulted.yaml index e8346d4f679..520c9dfb993 100644 --- a/cmd/kubeadm/app/util/config/testdata/defaulting/master/defaulted.yaml +++ b/cmd/kubeadm/app/util/config/testdata/defaulting/master/defaulted.yaml @@ -18,7 +18,8 @@ nodeRegistration: - effect: NoSchedule key: node-role.kubernetes.io/master --- -apiServer: {} +apiServer: + timeoutForControlPlane: 4m0s apiVersion: kubeadm.k8s.io/v1beta1 auditPolicy: logDir: /var/log/kubernetes/audit