mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 20:24:09 +00:00
kubeadm: Move .NodeName and .CRISocket to a common sub-struct
This commit is contained in:
parent
e3a4104479
commit
b48f23b786
@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
fuzz "github.com/google/gofuzz"
|
fuzz "github.com/google/gofuzz"
|
||||||
|
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
@ -43,7 +44,6 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
|
|||||||
obj.APIServerCertSANs = []string{"foo"}
|
obj.APIServerCertSANs = []string{"foo"}
|
||||||
|
|
||||||
obj.Token = "foo"
|
obj.Token = "foo"
|
||||||
obj.CRISocket = "foo"
|
|
||||||
obj.TokenTTL = &metav1.Duration{Duration: 1 * time.Hour}
|
obj.TokenTTL = &metav1.Duration{Duration: 1 * time.Hour}
|
||||||
obj.TokenUsages = []string{"foo"}
|
obj.TokenUsages = []string{"foo"}
|
||||||
obj.TokenGroups = []string{"foo"}
|
obj.TokenGroups = []string{"foo"}
|
||||||
@ -59,6 +59,9 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
|
|||||||
MountPath: "foo",
|
MountPath: "foo",
|
||||||
Writable: false,
|
Writable: false,
|
||||||
}}
|
}}
|
||||||
|
// Note: We don't set values here for obj.Etcd.External, as these are mutually exlusive.
|
||||||
|
// And to make sure the fuzzer doesn't set a random value for obj.Etcd.External, we let
|
||||||
|
// kubeadmapi.Etcd implement fuzz.Interface (we handle that ourselves)
|
||||||
obj.Etcd.Local = &kubeadm.LocalEtcd{
|
obj.Etcd.Local = &kubeadm.LocalEtcd{
|
||||||
Image: "foo",
|
Image: "foo",
|
||||||
DataDir: "foo",
|
DataDir: "foo",
|
||||||
@ -66,9 +69,11 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
|
|||||||
PeerCertSANs: []string{"foo"},
|
PeerCertSANs: []string{"foo"},
|
||||||
ExtraArgs: map[string]string{"foo": "foo"},
|
ExtraArgs: map[string]string{"foo": "foo"},
|
||||||
}
|
}
|
||||||
// Note: We don't set values here for obj.Etcd.External, as these are mutually exlusive.
|
obj.NodeRegistration = kubeadm.NodeRegistrationOptions{
|
||||||
// And to make sure the fuzzer doesn't set a random value for obj.Etcd.External, we let
|
CRISocket: "foo",
|
||||||
// kubeadmapi.Etcd implement fuzz.Interface (we handle that ourselves)
|
Name: "foo",
|
||||||
|
Taints: []v1.Taint{},
|
||||||
|
}
|
||||||
obj.KubeletConfiguration = kubeadm.KubeletConfiguration{
|
obj.KubeletConfiguration = kubeadm.KubeletConfiguration{
|
||||||
BaseConfig: &kubeletconfigv1beta1.KubeletConfiguration{
|
BaseConfig: &kubeletconfigv1beta1.KubeletConfiguration{
|
||||||
StaticPodPath: "foo",
|
StaticPodPath: "foo",
|
||||||
@ -139,8 +144,11 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
|
|||||||
obj.DiscoveryTimeout = &metav1.Duration{Duration: 1}
|
obj.DiscoveryTimeout = &metav1.Duration{Duration: 1}
|
||||||
obj.TLSBootstrapToken = "foo"
|
obj.TLSBootstrapToken = "foo"
|
||||||
obj.Token = "foo"
|
obj.Token = "foo"
|
||||||
obj.CRISocket = "foo"
|
|
||||||
obj.ClusterName = "foo"
|
obj.ClusterName = "foo"
|
||||||
|
obj.NodeRegistration = kubeadm.NodeRegistrationOptions{
|
||||||
|
CRISocket: "foo",
|
||||||
|
Name: "foo",
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,13 +44,9 @@ type MasterConfiguration struct {
|
|||||||
Networking Networking
|
Networking Networking
|
||||||
// KubernetesVersion is the target version of the control plane.
|
// KubernetesVersion is the target version of the control plane.
|
||||||
KubernetesVersion string
|
KubernetesVersion string
|
||||||
// NodeName is the name of the node that will host the k8s control plane.
|
|
||||||
// Defaults to the hostname if not provided.
|
// NodeRegistration holds fields that relate to registering the new master node to the cluster
|
||||||
NodeName string
|
NodeRegistration NodeRegistrationOptions
|
||||||
// NoTaintMaster will, if set, suppress the tainting of the
|
|
||||||
// master node allowing workloads to be run on it (e.g. in
|
|
||||||
// single node configurations).
|
|
||||||
NoTaintMaster bool
|
|
||||||
|
|
||||||
// Token is used for establishing bidirectional trust between nodes and masters.
|
// Token is used for establishing bidirectional trust between nodes and masters.
|
||||||
// Used for joining nodes in the cluster.
|
// Used for joining nodes in the cluster.
|
||||||
@ -62,9 +58,6 @@ type MasterConfiguration struct {
|
|||||||
// Extra groups that this token will authenticate as when used for authentication
|
// Extra groups that this token will authenticate as when used for authentication
|
||||||
TokenGroups []string
|
TokenGroups []string
|
||||||
|
|
||||||
// CRISocket is used to retrieve container runtime info.
|
|
||||||
CRISocket string
|
|
||||||
|
|
||||||
// APIServerExtraArgs is a set of extra flags to pass to the API Server or override
|
// APIServerExtraArgs is a set of extra flags to pass to the API Server or override
|
||||||
// default ones in form of <flagname>=<value>.
|
// default ones in form of <flagname>=<value>.
|
||||||
// TODO: This is temporary and ideally we would like to switch all components to
|
// TODO: This is temporary and ideally we would like to switch all components to
|
||||||
@ -138,6 +131,28 @@ type API struct {
|
|||||||
BindPort int32
|
BindPort int32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NodeRegistrationOptions holds fields that relate to registering a new master or node to the cluster, either via "kubeadm init" or "kubeadm join"
|
||||||
|
type NodeRegistrationOptions struct {
|
||||||
|
|
||||||
|
// Name is the `.Metadata.Name` field of the Node API object that will be created in this `kubeadm init` or `kubeadm joiń` operation.
|
||||||
|
// This field is also used in the CommonName field of the kubelet's client certificate to the API server.
|
||||||
|
// Defaults to the hostname of the node if not provided.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// CRISocket is used to retrieve container runtime info. This information will be annotated to the Node API object, for later re-use
|
||||||
|
CRISocket string
|
||||||
|
|
||||||
|
// Taints specifies the taints the Node API object should be registered with. If this field is unset, i.e. nil, in the `kubeadm init` process
|
||||||
|
// it will be defaulted to []v1.Taint{'node-role.kubernetes.io/master=""'}. If you don't want to taint your master node, set this field to an
|
||||||
|
// empty slice, i.e. `taints: {}` in the YAML file. This field is solely used for Node registration.
|
||||||
|
Taints []v1.Taint
|
||||||
|
|
||||||
|
// ExtraArgs passes through extra arguments to the kubelet. The arguments here are passed to the kubelet command line via the environment file
|
||||||
|
// kubeadm writes at runtime for the kubelet to source. This overrides the generic base-level configuration in the kubelet-config-1.X ConfigMap
|
||||||
|
// Flags have higher higher priority when parsing. These values are local and specific to the node kubeadm is executing on.
|
||||||
|
ExtraArgs map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
// TokenDiscovery contains elements needed for token discovery.
|
// TokenDiscovery contains elements needed for token discovery.
|
||||||
type TokenDiscovery struct {
|
type TokenDiscovery struct {
|
||||||
// ID is the first part of a bootstrap token. Considered public information.
|
// ID is the first part of a bootstrap token. Considered public information.
|
||||||
@ -223,6 +238,9 @@ type ExternalEtcd struct {
|
|||||||
type NodeConfiguration struct {
|
type NodeConfiguration struct {
|
||||||
metav1.TypeMeta
|
metav1.TypeMeta
|
||||||
|
|
||||||
|
// NodeRegistration holds fields that relate to registering the new master node to the cluster
|
||||||
|
NodeRegistration NodeRegistrationOptions
|
||||||
|
|
||||||
// CACertPath is the path to the SSL certificate authority used to
|
// CACertPath is the path to the SSL certificate authority used to
|
||||||
// secure comunications between node and master.
|
// secure comunications between node and master.
|
||||||
// Defaults to "/etc/kubernetes/pki/ca.crt".
|
// Defaults to "/etc/kubernetes/pki/ca.crt".
|
||||||
@ -239,16 +257,11 @@ type NodeConfiguration struct {
|
|||||||
DiscoveryTokenAPIServers []string
|
DiscoveryTokenAPIServers []string
|
||||||
// DiscoveryTimeout modifies the discovery timeout
|
// DiscoveryTimeout modifies the discovery timeout
|
||||||
DiscoveryTimeout *metav1.Duration
|
DiscoveryTimeout *metav1.Duration
|
||||||
// NodeName is the name of the node to join the cluster. Defaults
|
|
||||||
// to the name of the host.
|
|
||||||
NodeName string
|
|
||||||
// TLSBootstrapToken is a token used for TLS bootstrapping.
|
// TLSBootstrapToken is a token used for TLS bootstrapping.
|
||||||
// Defaults to Token.
|
// Defaults to Token.
|
||||||
TLSBootstrapToken string
|
TLSBootstrapToken string
|
||||||
// Token is used for both discovery and TLS bootstrapping.
|
// Token is used for both discovery and TLS bootstrapping.
|
||||||
Token string
|
Token string
|
||||||
// CRISocket is used to retrieve container runtime info.
|
|
||||||
CRISocket string
|
|
||||||
// The cluster name
|
// The cluster name
|
||||||
ClusterName string
|
ClusterName string
|
||||||
|
|
||||||
@ -332,13 +345,13 @@ type CommonConfiguration interface {
|
|||||||
// GetCRISocket will return the CRISocket that is defined for the MasterConfiguration.
|
// GetCRISocket will return the CRISocket that is defined for the MasterConfiguration.
|
||||||
// This is used internally to deduplicate the kubeadm preflight checks.
|
// This is used internally to deduplicate the kubeadm preflight checks.
|
||||||
func (cfg *MasterConfiguration) GetCRISocket() string {
|
func (cfg *MasterConfiguration) GetCRISocket() string {
|
||||||
return cfg.CRISocket
|
return cfg.NodeRegistration.CRISocket
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNodeName will return the NodeName that is defined for the MasterConfiguration.
|
// GetNodeName will return the NodeName that is defined for the MasterConfiguration.
|
||||||
// This is used internally to deduplicate the kubeadm preflight checks.
|
// This is used internally to deduplicate the kubeadm preflight checks.
|
||||||
func (cfg *MasterConfiguration) GetNodeName() string {
|
func (cfg *MasterConfiguration) GetNodeName() string {
|
||||||
return cfg.NodeName
|
return cfg.NodeRegistration.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKubernetesVersion will return the KubernetesVersion that is defined for the MasterConfiguration.
|
// GetKubernetesVersion will return the KubernetesVersion that is defined for the MasterConfiguration.
|
||||||
@ -350,13 +363,13 @@ func (cfg *MasterConfiguration) GetKubernetesVersion() string {
|
|||||||
// GetCRISocket will return the CRISocket that is defined for the NodeConfiguration.
|
// GetCRISocket will return the CRISocket that is defined for the NodeConfiguration.
|
||||||
// This is used internally to deduplicate the kubeadm preflight checks.
|
// This is used internally to deduplicate the kubeadm preflight checks.
|
||||||
func (cfg *NodeConfiguration) GetCRISocket() string {
|
func (cfg *NodeConfiguration) GetCRISocket() string {
|
||||||
return cfg.CRISocket
|
return cfg.NodeRegistration.CRISocket
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNodeName will return the NodeName that is defined for the NodeConfiguration.
|
// GetNodeName will return the NodeName that is defined for the NodeConfiguration.
|
||||||
// This is used internally to deduplicate the kubeadm preflight checks.
|
// This is used internally to deduplicate the kubeadm preflight checks.
|
||||||
func (cfg *NodeConfiguration) GetNodeName() string {
|
func (cfg *NodeConfiguration) GetNodeName() string {
|
||||||
return cfg.NodeName
|
return cfg.NodeRegistration.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKubernetesVersion will return an empty string since KubernetesVersion is not a
|
// GetKubernetesVersion will return an empty string since KubernetesVersion is not a
|
||||||
|
@ -20,15 +20,20 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/conversion"
|
"k8s.io/apimachinery/pkg/conversion"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
|
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
func addConversionFuncs(scheme *runtime.Scheme) error {
|
func addConversionFuncs(scheme *runtime.Scheme) error {
|
||||||
// Add non-generated conversion functions
|
// Add non-generated conversion functions
|
||||||
err := scheme.AddConversionFuncs(
|
err := scheme.AddConversionFuncs(
|
||||||
Convert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration,
|
Convert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration,
|
||||||
|
Convert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration,
|
||||||
|
Convert_v1alpha1_NodeConfiguration_To_kubeadm_NodeConfiguration,
|
||||||
|
Convert_kubeadm_NodeConfiguration_To_v1alpha1_NodeConfiguration,
|
||||||
Convert_v1alpha1_Etcd_To_kubeadm_Etcd,
|
Convert_v1alpha1_Etcd_To_kubeadm_Etcd,
|
||||||
Convert_kubeadm_Etcd_To_v1alpha1_Etcd,
|
Convert_kubeadm_Etcd_To_v1alpha1_Etcd,
|
||||||
)
|
)
|
||||||
@ -39,6 +44,8 @@ func addConversionFuncs(scheme *runtime.Scheme) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Upgrades below
|
||||||
|
|
||||||
func Convert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in *MasterConfiguration, out *kubeadm.MasterConfiguration, s conversion.Scope) error {
|
func Convert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in *MasterConfiguration, out *kubeadm.MasterConfiguration, s conversion.Scope) error {
|
||||||
if err := autoConvert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in, out, s); err != nil {
|
if err := autoConvert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in, out, s); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -46,12 +53,26 @@ func Convert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in *Mas
|
|||||||
|
|
||||||
UpgradeCloudProvider(in, out)
|
UpgradeCloudProvider(in, out)
|
||||||
UpgradeAuthorizationModes(in, out)
|
UpgradeAuthorizationModes(in, out)
|
||||||
|
UpgradeNodeRegistrationOptionsForMaster(in, out)
|
||||||
// We don't support migrating information from the .PrivilegedPods field which was removed in v1alpha2
|
// We don't support migrating information from the .PrivilegedPods field which was removed in v1alpha2
|
||||||
// We don't support migrating information from the .ImagePullPolicy field which was removed in v1alpha2
|
// We don't support migrating information from the .ImagePullPolicy field which was removed in v1alpha2
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Convert_v1alpha1_NodeConfiguration_To_kubeadm_NodeConfiguration(in *NodeConfiguration, out *kubeadm.NodeConfiguration, s conversion.Scope) error {
|
||||||
|
if err := autoConvert_v1alpha1_NodeConfiguration_To_kubeadm_NodeConfiguration(in, out, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// .NodeName has moved to .NodeRegistration.Name
|
||||||
|
out.NodeRegistration.Name = in.NodeName
|
||||||
|
// .CRISocket has moved to .NodeRegistration.CRISocket
|
||||||
|
out.NodeRegistration.CRISocket = in.CRISocket
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func Convert_v1alpha1_Etcd_To_kubeadm_Etcd(in *Etcd, out *kubeadm.Etcd, s conversion.Scope) error {
|
func Convert_v1alpha1_Etcd_To_kubeadm_Etcd(in *Etcd, out *kubeadm.Etcd, s conversion.Scope) error {
|
||||||
if err := autoConvert_v1alpha1_Etcd_To_kubeadm_Etcd(in, out, s); err != nil {
|
if err := autoConvert_v1alpha1_Etcd_To_kubeadm_Etcd(in, out, s); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -123,3 +144,45 @@ func UpgradeAuthorizationModes(in *MasterConfiguration, out *kubeadm.MasterConfi
|
|||||||
out.APIServerExtraArgs["authorization-mode"] = strings.Join(in.AuthorizationModes, ",")
|
out.APIServerExtraArgs["authorization-mode"] = strings.Join(in.AuthorizationModes, ",")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UpgradeNodeRegistrationOptionsForMaster(in *MasterConfiguration, out *kubeadm.MasterConfiguration) {
|
||||||
|
// .NodeName has moved to .NodeRegistration.Name
|
||||||
|
out.NodeRegistration.Name = in.NodeName
|
||||||
|
|
||||||
|
// .CRISocket has moved to .NodeRegistration.CRISocket
|
||||||
|
out.NodeRegistration.CRISocket = in.CRISocket
|
||||||
|
|
||||||
|
// Transfer the information from .NoTaintMaster to the new layout
|
||||||
|
if in.NoTaintMaster {
|
||||||
|
out.NodeRegistration.Taints = []v1.Taint{}
|
||||||
|
} else {
|
||||||
|
out.NodeRegistration.Taints = []v1.Taint{constants.MasterTaint}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Downgrades below
|
||||||
|
|
||||||
|
func Convert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration(in *kubeadm.MasterConfiguration, out *MasterConfiguration, s conversion.Scope) error {
|
||||||
|
if err := autoConvert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration(in, out, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converting from newer API version to an older API version isn't supported. This is here only for the roundtrip tests meanwhile.
|
||||||
|
out.NodeName = in.NodeRegistration.Name
|
||||||
|
out.CRISocket = in.NodeRegistration.CRISocket
|
||||||
|
out.NoTaintMaster = in.NodeRegistration.Taints != nil && len(in.NodeRegistration.Taints) == 0
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Convert_kubeadm_NodeConfiguration_To_v1alpha1_NodeConfiguration(in *kubeadm.NodeConfiguration, out *NodeConfiguration, s conversion.Scope) error {
|
||||||
|
if err := autoConvert_kubeadm_NodeConfiguration_To_v1alpha1_NodeConfiguration(in, out, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converting from newer API version to an older API version isn't supported. This is here only for the roundtrip tests meanwhile.
|
||||||
|
out.NodeName = in.NodeRegistration.Name
|
||||||
|
out.CRISocket = in.NodeRegistration.CRISocket
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -103,10 +103,6 @@ func SetDefaults_MasterConfiguration(obj *MasterConfiguration) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj.CRISocket == "" {
|
|
||||||
obj.CRISocket = DefaultCRISocket
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(obj.TokenUsages) == 0 {
|
if len(obj.TokenUsages) == 0 {
|
||||||
obj.TokenUsages = constants.DefaultTokenUsages
|
obj.TokenUsages = constants.DefaultTokenUsages
|
||||||
}
|
}
|
||||||
@ -123,6 +119,7 @@ func SetDefaults_MasterConfiguration(obj *MasterConfiguration) {
|
|||||||
obj.ClusterName = DefaultClusterName
|
obj.ClusterName = DefaultClusterName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetDefaults_NodeRegistrationOptions(&obj.NodeRegistration)
|
||||||
SetDefaults_KubeletConfiguration(obj)
|
SetDefaults_KubeletConfiguration(obj)
|
||||||
SetDefaults_Etcd(obj)
|
SetDefaults_Etcd(obj)
|
||||||
SetDefaults_ProxyConfiguration(obj)
|
SetDefaults_ProxyConfiguration(obj)
|
||||||
@ -168,9 +165,6 @@ func SetDefaults_NodeConfiguration(obj *NodeConfiguration) {
|
|||||||
if len(obj.DiscoveryToken) == 0 && len(obj.DiscoveryFile) == 0 {
|
if len(obj.DiscoveryToken) == 0 && len(obj.DiscoveryFile) == 0 {
|
||||||
obj.DiscoveryToken = obj.Token
|
obj.DiscoveryToken = obj.Token
|
||||||
}
|
}
|
||||||
if obj.CRISocket == "" {
|
|
||||||
obj.CRISocket = DefaultCRISocket
|
|
||||||
}
|
|
||||||
// Make sure file URLs become paths
|
// Make sure file URLs become paths
|
||||||
if len(obj.DiscoveryFile) != 0 {
|
if len(obj.DiscoveryFile) != 0 {
|
||||||
u, err := url.Parse(obj.DiscoveryFile)
|
u, err := url.Parse(obj.DiscoveryFile)
|
||||||
@ -186,6 +180,8 @@ func SetDefaults_NodeConfiguration(obj *NodeConfiguration) {
|
|||||||
if obj.ClusterName == "" {
|
if obj.ClusterName == "" {
|
||||||
obj.ClusterName = DefaultClusterName
|
obj.ClusterName = DefaultClusterName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetDefaults_NodeRegistrationOptions(&obj.NodeRegistration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDefaults_KubeletConfiguration assigns default values to kubelet
|
// SetDefaults_KubeletConfiguration assigns default values to kubelet
|
||||||
@ -237,6 +233,12 @@ func SetDefaults_KubeletConfiguration(obj *MasterConfiguration) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetDefaults_NodeRegistrationOptions(obj *NodeRegistrationOptions) {
|
||||||
|
if obj.CRISocket == "" {
|
||||||
|
obj.CRISocket = DefaultCRISocket
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetDefaults_AuditPolicyConfiguration sets default values for the AuditPolicyConfiguration
|
// SetDefaults_AuditPolicyConfiguration sets default values for the AuditPolicyConfiguration
|
||||||
func SetDefaults_AuditPolicyConfiguration(obj *MasterConfiguration) {
|
func SetDefaults_AuditPolicyConfiguration(obj *MasterConfiguration) {
|
||||||
if obj.AuditPolicyConfiguration.LogDir == "" {
|
if obj.AuditPolicyConfiguration.LogDir == "" {
|
||||||
|
@ -40,15 +40,12 @@ type MasterConfiguration struct {
|
|||||||
KubeletConfiguration KubeletConfiguration `json:"kubeletConfiguration"`
|
KubeletConfiguration KubeletConfiguration `json:"kubeletConfiguration"`
|
||||||
// Networking holds configuration for the networking topology of the cluster.
|
// Networking holds configuration for the networking topology of the cluster.
|
||||||
Networking Networking `json:"networking"`
|
Networking Networking `json:"networking"`
|
||||||
|
|
||||||
|
// NodeRegistration holds fields that relate to registering the new master node to the cluster
|
||||||
|
NodeRegistration NodeRegistrationOptions `json:"nodeRegistration"`
|
||||||
|
|
||||||
// KubernetesVersion is the target version of the control plane.
|
// KubernetesVersion is the target version of the control plane.
|
||||||
KubernetesVersion string `json:"kubernetesVersion"`
|
KubernetesVersion string `json:"kubernetesVersion"`
|
||||||
// NodeName is the name of the node that will host the k8s control plane.
|
|
||||||
// Defaults to the hostname if not provided.
|
|
||||||
NodeName string `json:"nodeName"`
|
|
||||||
// NoTaintMaster will, if set, suppress the tainting of the
|
|
||||||
// master node allowing workloads to be run on it (e.g. in
|
|
||||||
// single node configurations).
|
|
||||||
NoTaintMaster bool `json:"noTaintMaster,omitempty"`
|
|
||||||
|
|
||||||
// Token is used for establishing bidirectional trust between nodes and masters.
|
// Token is used for establishing bidirectional trust between nodes and masters.
|
||||||
// Used for joining nodes in the cluster.
|
// Used for joining nodes in the cluster.
|
||||||
@ -60,9 +57,6 @@ type MasterConfiguration struct {
|
|||||||
// Extra groups that this token will authenticate as when used for authentication
|
// Extra groups that this token will authenticate as when used for authentication
|
||||||
TokenGroups []string `json:"tokenGroups,omitempty"`
|
TokenGroups []string `json:"tokenGroups,omitempty"`
|
||||||
|
|
||||||
// CRISocket is used to retrieve container runtime info.
|
|
||||||
CRISocket string `json:"criSocket,omitempty"`
|
|
||||||
|
|
||||||
// APIServerExtraArgs is a set of extra flags to pass to the API Server or override
|
// APIServerExtraArgs is a set of extra flags to pass to the API Server or override
|
||||||
// default ones in form of <flagname>=<value>.
|
// default ones in form of <flagname>=<value>.
|
||||||
// TODO: This is temporary and ideally we would like to switch all components to
|
// TODO: This is temporary and ideally we would like to switch all components to
|
||||||
@ -129,6 +123,28 @@ type API struct {
|
|||||||
BindPort int32 `json:"bindPort"`
|
BindPort int32 `json:"bindPort"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NodeRegistrationOptions holds fields that relate to registering a new master or node to the cluster, either via "kubeadm init" or "kubeadm join"
|
||||||
|
type NodeRegistrationOptions struct {
|
||||||
|
|
||||||
|
// Name is the `.Metadata.Name` field of the Node API object that will be created in this `kubeadm init` or `kubeadm joiń` operation.
|
||||||
|
// This field is also used in the CommonName field of the kubelet's client certificate to the API server.
|
||||||
|
// Defaults to the hostname of the node if not provided.
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// CRISocket is used to retrieve container runtime info. This information will be annotated to the Node API object, for later re-use
|
||||||
|
CRISocket string `json:"criSocket"`
|
||||||
|
|
||||||
|
// Taints specifies the taints the Node API object should be registered with. If this field is unset, i.e. nil, in the `kubeadm init` process
|
||||||
|
// it will be defaulted to []v1.Taint{'node-role.kubernetes.io/master=""'}. If you don't want to taint your master node, set this field to an
|
||||||
|
// empty slice, i.e. `taints: {}` in the YAML file. This field is solely used for Node registration.
|
||||||
|
Taints []v1.Taint `json:"taints,omitempty"`
|
||||||
|
|
||||||
|
// ExtraArgs passes through extra arguments to the kubelet. The arguments here are passed to the kubelet command line via the environment file
|
||||||
|
// kubeadm writes at runtime for the kubelet to source. This overrides the generic base-level configuration in the kubelet-config-1.X ConfigMap
|
||||||
|
// Flags have higher higher priority when parsing. These values are local and specific to the node kubeadm is executing on.
|
||||||
|
ExtraArgs map[string]string `json:"kubeletExtraArgs,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// TokenDiscovery contains elements needed for token discovery.
|
// TokenDiscovery contains elements needed for token discovery.
|
||||||
type TokenDiscovery struct {
|
type TokenDiscovery struct {
|
||||||
// ID is the first part of a bootstrap token. Considered public information.
|
// ID is the first part of a bootstrap token. Considered public information.
|
||||||
@ -206,6 +222,9 @@ type ExternalEtcd struct {
|
|||||||
type NodeConfiguration struct {
|
type NodeConfiguration struct {
|
||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
|
||||||
|
// NodeRegistration holds fields that relate to registering the new master node to the cluster
|
||||||
|
NodeRegistration NodeRegistrationOptions `json:"nodeRegistration"`
|
||||||
|
|
||||||
// CACertPath is the path to the SSL certificate authority used to
|
// CACertPath is the path to the SSL certificate authority used to
|
||||||
// secure comunications between node and master.
|
// secure comunications between node and master.
|
||||||
// Defaults to "/etc/kubernetes/pki/ca.crt".
|
// Defaults to "/etc/kubernetes/pki/ca.crt".
|
||||||
@ -222,16 +241,12 @@ type NodeConfiguration struct {
|
|||||||
DiscoveryTokenAPIServers []string `json:"discoveryTokenAPIServers,omitempty"`
|
DiscoveryTokenAPIServers []string `json:"discoveryTokenAPIServers,omitempty"`
|
||||||
// DiscoveryTimeout modifies the discovery timeout
|
// DiscoveryTimeout modifies the discovery timeout
|
||||||
DiscoveryTimeout *metav1.Duration `json:"discoveryTimeout,omitempty"`
|
DiscoveryTimeout *metav1.Duration `json:"discoveryTimeout,omitempty"`
|
||||||
// NodeName is the name of the node to join the cluster. Defaults
|
|
||||||
// to the name of the host.
|
|
||||||
NodeName string `json:"nodeName"`
|
|
||||||
// TLSBootstrapToken is a token used for TLS bootstrapping.
|
// TLSBootstrapToken is a token used for TLS bootstrapping.
|
||||||
// Defaults to Token.
|
// Defaults to Token.
|
||||||
TLSBootstrapToken string `json:"tlsBootstrapToken"`
|
TLSBootstrapToken string `json:"tlsBootstrapToken"`
|
||||||
// Token is used for both discovery and TLS bootstrapping.
|
// Token is used for both discovery and TLS bootstrapping.
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
// CRISocket is used to retrieve container runtime info.
|
|
||||||
CRISocket string `json:"criSocket,omitempty"`
|
|
||||||
// ClusterName is the name for the cluster in kubeconfig.
|
// ClusterName is the name for the cluster in kubeconfig.
|
||||||
ClusterName string `json:"clusterName,omitempty"`
|
ClusterName string `json:"clusterName,omitempty"`
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ func ValidateMasterConfiguration(c *kubeadm.MasterConfiguration) field.ErrorList
|
|||||||
allErrs = append(allErrs, ValidateNetworking(&c.Networking, field.NewPath("networking"))...)
|
allErrs = append(allErrs, ValidateNetworking(&c.Networking, field.NewPath("networking"))...)
|
||||||
allErrs = append(allErrs, ValidateCertSANs(c.APIServerCertSANs, field.NewPath("apiServerCertSANs"))...)
|
allErrs = append(allErrs, ValidateCertSANs(c.APIServerCertSANs, field.NewPath("apiServerCertSANs"))...)
|
||||||
allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificatesDir"))...)
|
allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificatesDir"))...)
|
||||||
allErrs = append(allErrs, ValidateNodeName(c.NodeName, field.NewPath("nodeName"))...)
|
allErrs = append(allErrs, ValidateNodeRegistrationOptions(&c.NodeRegistration, field.NewPath("nodeRegistration"))...)
|
||||||
allErrs = append(allErrs, ValidateToken(c.Token, field.NewPath("token"))...)
|
allErrs = append(allErrs, ValidateToken(c.Token, field.NewPath("token"))...)
|
||||||
allErrs = append(allErrs, ValidateTokenUsages(c.TokenUsages, field.NewPath("tokenUsages"))...)
|
allErrs = append(allErrs, ValidateTokenUsages(c.TokenUsages, field.NewPath("tokenUsages"))...)
|
||||||
allErrs = append(allErrs, ValidateTokenGroups(c.TokenUsages, c.TokenGroups, field.NewPath("tokenGroups"))...)
|
allErrs = append(allErrs, ValidateTokenGroups(c.TokenUsages, c.TokenGroups, field.NewPath("tokenGroups"))...)
|
||||||
@ -62,9 +62,7 @@ func ValidateMasterConfiguration(c *kubeadm.MasterConfiguration) field.ErrorList
|
|||||||
allErrs = append(allErrs, ValidateAPIEndpoint(&c.API, field.NewPath("api"))...)
|
allErrs = append(allErrs, ValidateAPIEndpoint(&c.API, field.NewPath("api"))...)
|
||||||
allErrs = append(allErrs, ValidateProxy(c.KubeProxy.Config, field.NewPath("kubeProxy").Child("config"))...)
|
allErrs = append(allErrs, ValidateProxy(c.KubeProxy.Config, field.NewPath("kubeProxy").Child("config"))...)
|
||||||
allErrs = append(allErrs, ValidateEtcd(&c.Etcd, field.NewPath("etcd"))...)
|
allErrs = append(allErrs, ValidateEtcd(&c.Etcd, field.NewPath("etcd"))...)
|
||||||
if features.Enabled(c.FeatureGates, features.DynamicKubeletConfig) {
|
allErrs = append(allErrs, ValidateKubeletConfiguration(&c.KubeletConfiguration, field.NewPath("kubeletConfiguration"))...)
|
||||||
allErrs = append(allErrs, ValidateKubeletConfiguration(&c.KubeletConfiguration, field.NewPath("kubeletConfiguration"))...)
|
|
||||||
}
|
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,6 +84,7 @@ func ValidateProxy(c *kubeproxyconfigv1alpha1.KubeProxyConfiguration, fldPath *f
|
|||||||
func ValidateNodeConfiguration(c *kubeadm.NodeConfiguration) field.ErrorList {
|
func ValidateNodeConfiguration(c *kubeadm.NodeConfiguration) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
allErrs = append(allErrs, ValidateDiscovery(c)...)
|
allErrs = append(allErrs, ValidateDiscovery(c)...)
|
||||||
|
allErrs = append(allErrs, ValidateNodeRegistrationOptions(&c.NodeRegistration, field.NewPath("nodeRegistration"))...)
|
||||||
|
|
||||||
if !filepath.IsAbs(c.CACertPath) || !strings.HasSuffix(c.CACertPath, ".crt") {
|
if !filepath.IsAbs(c.CACertPath) || !strings.HasSuffix(c.CACertPath, ".crt") {
|
||||||
allErrs = append(allErrs, field.Invalid(field.NewPath("caCertPath"), c.CACertPath, "the ca certificate path must be an absolute path"))
|
allErrs = append(allErrs, field.Invalid(field.NewPath("caCertPath"), c.CACertPath, "the ca certificate path must be an absolute path"))
|
||||||
@ -93,6 +92,15 @@ func ValidateNodeConfiguration(c *kubeadm.NodeConfiguration) field.ErrorList {
|
|||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateNodeRegistrationOptions validates the NodeRegistrationOptions object
|
||||||
|
func ValidateNodeRegistrationOptions(nro *kubeadm.NodeRegistrationOptions, fldPath *field.Path) field.ErrorList {
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
allErrs = append(allErrs, ValidateNodeName(nro.Name, fldPath.Child("name"))...)
|
||||||
|
allErrs = append(allErrs, ValidateAbsolutePath(nro.CRISocket, fldPath.Child("criSocket"))...)
|
||||||
|
// TODO: Maybe validate .Taints as well in the future using something like validateNodeTaints() in pkg/apis/core/validation
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
// ValidateDiscovery validates discovery related configuration and collects all encountered errors
|
// ValidateDiscovery validates discovery related configuration and collects all encountered errors
|
||||||
func ValidateDiscovery(c *kubeadm.NodeConfiguration) field.ErrorList {
|
func ValidateDiscovery(c *kubeadm.NodeConfiguration) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
@ -422,6 +430,10 @@ func ValidateIgnorePreflightErrors(ignorePreflightErrors []string, skipPreflight
|
|||||||
func ValidateKubeletConfiguration(c *kubeadm.KubeletConfiguration, fldPath *field.Path) field.ErrorList {
|
func ValidateKubeletConfiguration(c *kubeadm.KubeletConfiguration, fldPath *field.Path) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
|
if c.BaseConfig == nil {
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
scheme, _, err := kubeletscheme.NewSchemeAndCodecs()
|
scheme, _, err := kubeletscheme.NewSchemeAndCodecs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
allErrs = append(allErrs, field.Invalid(fldPath, "kubeletConfiguration", err.Error()))
|
allErrs = append(allErrs, field.Invalid(fldPath, "kubeletConfiguration", err.Error()))
|
||||||
|
@ -401,5 +401,5 @@ func AddImagesCommonConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1alpha2.M
|
|||||||
|
|
||||||
// AddImagesPullFlags adds flags related to the `kubeadm config images pull` command
|
// AddImagesPullFlags adds flags related to the `kubeadm config images pull` command
|
||||||
func AddImagesPullFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1alpha2.MasterConfiguration) {
|
func AddImagesPullFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1alpha2.MasterConfiguration) {
|
||||||
flagSet.StringVar(&cfg.CRISocket, "cri-socket-path", cfg.CRISocket, "Path to the CRI socket.")
|
flagSet.StringVar(&cfg.NodeRegistration.CRISocket, "cri-socket-path", cfg.NodeRegistration.CRISocket, "Path to the CRI socket.")
|
||||||
}
|
}
|
||||||
|
@ -189,7 +189,7 @@ func AddInitConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1alpha2.MasterCon
|
|||||||
`Optional extra Subject Alternative Names (SANs) to use for the API Server serving certificate. Can be both IP addresses and DNS names.`,
|
`Optional extra Subject Alternative Names (SANs) to use for the API Server serving certificate. Can be both IP addresses and DNS names.`,
|
||||||
)
|
)
|
||||||
flagSet.StringVar(
|
flagSet.StringVar(
|
||||||
&cfg.NodeName, "node-name", cfg.NodeName,
|
&cfg.NodeRegistration.Name, "node-name", cfg.NodeRegistration.Name,
|
||||||
`Specify the node name.`,
|
`Specify the node name.`,
|
||||||
)
|
)
|
||||||
flagSet.StringVar(
|
flagSet.StringVar(
|
||||||
@ -201,7 +201,7 @@ func AddInitConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1alpha2.MasterCon
|
|||||||
"The duration before the bootstrap token is automatically deleted. If set to '0', the token will never expire.",
|
"The duration before the bootstrap token is automatically deleted. If set to '0', the token will never expire.",
|
||||||
)
|
)
|
||||||
flagSet.StringVar(
|
flagSet.StringVar(
|
||||||
&cfg.CRISocket, "cri-socket", cfg.CRISocket,
|
&cfg.NodeRegistration.CRISocket, "cri-socket", cfg.NodeRegistration.CRISocket,
|
||||||
`Specify the CRI socket to connect to.`,
|
`Specify the CRI socket to connect to.`,
|
||||||
)
|
)
|
||||||
flagSet.StringVar(featureGatesString, "feature-gates", *featureGatesString, "A set of key=value pairs that describe feature gates for various features. "+
|
flagSet.StringVar(featureGatesString, "feature-gates", *featureGatesString, "A set of key=value pairs that describe feature gates for various features. "+
|
||||||
@ -276,8 +276,10 @@ type Init struct {
|
|||||||
// Run executes master node provisioning, including certificates, needed static pod manifests, etc.
|
// Run executes master node provisioning, including certificates, needed static pod manifests, etc.
|
||||||
func (i *Init) Run(out io.Writer) error {
|
func (i *Init) Run(out io.Writer) error {
|
||||||
|
|
||||||
// Write env file with flags for the kubelet to use
|
// Write env file with flags for the kubelet to use. We do not need to write the --register-with-taints for the master,
|
||||||
if err := kubeletphase.WriteKubeletDynamicEnvFile(i.cfg); err != nil {
|
// as we handle that ourselves in the markmaster phase
|
||||||
|
// TODO: Maybe we want to do that some time in the future, in order to remove some logic from the markmaster phase?
|
||||||
|
if err := kubeletphase.WriteKubeletDynamicEnvFile(&i.cfg.NodeRegistration, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,7 +364,7 @@ func (i *Init) Run(out io.Writer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write the kubelet configuration to disk.
|
// Write the kubelet configuration to disk.
|
||||||
if err := kubeletphase.WriteConfigToDisk(i.cfg.KubeletConfiguration.BaseConfig, kubeletVersion); err != nil {
|
if err := kubeletphase.WriteConfigToDisk(i.cfg.KubeletConfiguration.BaseConfig); err != nil {
|
||||||
return fmt.Errorf("error writing kubelet configuration to disk: %v", err)
|
return fmt.Errorf("error writing kubelet configuration to disk: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,7 +413,7 @@ func (i *Init) Run(out io.Writer) error {
|
|||||||
|
|
||||||
// PHASE 4: Mark the master with the right label/taint
|
// PHASE 4: Mark the master with the right label/taint
|
||||||
glog.V(1).Infof("[init] marking the master with right label")
|
glog.V(1).Infof("[init] marking the master with right label")
|
||||||
if err := markmasterphase.MarkMaster(client, i.cfg.NodeName, !i.cfg.NoTaintMaster); err != nil {
|
if err := markmasterphase.MarkMaster(client, i.cfg.NodeRegistration.Name, i.cfg.NodeRegistration.Taints); err != nil {
|
||||||
return fmt.Errorf("error marking master: %v", err)
|
return fmt.Errorf("error marking master: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,7 +421,7 @@ func (i *Init) Run(out io.Writer) error {
|
|||||||
// This feature is disabled by default, as it is alpha still
|
// This feature is disabled by default, as it is alpha still
|
||||||
if features.Enabled(i.cfg.FeatureGates, features.DynamicKubeletConfig) {
|
if features.Enabled(i.cfg.FeatureGates, features.DynamicKubeletConfig) {
|
||||||
// Enable dynamic kubelet configuration for the node.
|
// Enable dynamic kubelet configuration for the node.
|
||||||
if err := kubeletphase.EnableDynamicConfigForNode(client, i.cfg.NodeName, kubeletVersion); err != nil {
|
if err := kubeletphase.EnableDynamicConfigForNode(client, i.cfg.NodeRegistration.Name, kubeletVersion); err != nil {
|
||||||
return fmt.Errorf("error enabling dynamic kubelet configuration: %v", err)
|
return fmt.Errorf("error enabling dynamic kubelet configuration: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -507,7 +509,7 @@ func (i *Init) Run(out io.Writer) error {
|
|||||||
func createClient(cfg *kubeadmapi.MasterConfiguration, dryRun bool) (clientset.Interface, error) {
|
func createClient(cfg *kubeadmapi.MasterConfiguration, dryRun bool) (clientset.Interface, error) {
|
||||||
if dryRun {
|
if dryRun {
|
||||||
// If we're dry-running; we should create a faked client that answers some GETs in order to be able to do the full init flow and just logs the rest of requests
|
// If we're dry-running; we should create a faked client that answers some GETs in order to be able to do the full init flow and just logs the rest of requests
|
||||||
dryRunGetter := apiclient.NewInitDryRunGetter(cfg.NodeName, cfg.Networking.ServiceSubnet)
|
dryRunGetter := apiclient.NewInitDryRunGetter(cfg.NodeRegistration.Name, cfg.Networking.ServiceSubnet)
|
||||||
return apiclient.NewDryRunClient(dryRunGetter, os.Stdout), nil
|
return apiclient.NewDryRunClient(dryRunGetter, os.Stdout), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ func AddJoinConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1alpha2.NodeConfi
|
|||||||
&cfg.DiscoveryToken, "discovery-token", "",
|
&cfg.DiscoveryToken, "discovery-token", "",
|
||||||
"A token used to validate cluster information fetched from the master.")
|
"A token used to validate cluster information fetched from the master.")
|
||||||
flagSet.StringVar(
|
flagSet.StringVar(
|
||||||
&cfg.NodeName, "node-name", "",
|
&cfg.NodeRegistration.Name, "node-name", cfg.NodeRegistration.Name,
|
||||||
"Specify the node name.")
|
"Specify the node name.")
|
||||||
flagSet.StringVar(
|
flagSet.StringVar(
|
||||||
&cfg.TLSBootstrapToken, "tls-bootstrap-token", "",
|
&cfg.TLSBootstrapToken, "tls-bootstrap-token", "",
|
||||||
@ -174,7 +174,7 @@ func AddJoinConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1alpha2.NodeConfi
|
|||||||
"A set of key=value pairs that describe feature gates for various features. "+
|
"A set of key=value pairs that describe feature gates for various features. "+
|
||||||
"Options are:\n"+strings.Join(features.KnownFeatures(&features.InitFeatureGates), "\n"))
|
"Options are:\n"+strings.Join(features.KnownFeatures(&features.InitFeatureGates), "\n"))
|
||||||
flagSet.StringVar(
|
flagSet.StringVar(
|
||||||
&cfg.CRISocket, "cri-socket", cfg.CRISocket,
|
&cfg.NodeRegistration.CRISocket, "cri-socket", cfg.NodeRegistration.CRISocket,
|
||||||
`Specify the CRI socket to connect to.`,
|
`Specify the CRI socket to connect to.`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -204,7 +204,7 @@ type Join struct {
|
|||||||
// NewJoin instantiates Join struct with given arguments
|
// NewJoin instantiates Join struct with given arguments
|
||||||
func NewJoin(cfgPath string, args []string, defaultcfg *kubeadmapiv1alpha2.NodeConfiguration, ignorePreflightErrors sets.String) (*Join, error) {
|
func NewJoin(cfgPath string, args []string, defaultcfg *kubeadmapiv1alpha2.NodeConfiguration, ignorePreflightErrors sets.String) (*Join, error) {
|
||||||
|
|
||||||
if defaultcfg.NodeName == "" {
|
if defaultcfg.NodeRegistration.Name == "" {
|
||||||
glog.V(1).Infoln("[join] found NodeName empty")
|
glog.V(1).Infoln("[join] found NodeName empty")
|
||||||
glog.V(1).Infoln("[join] considered OS hostname as NodeName")
|
glog.V(1).Infoln("[join] considered OS hostname as NodeName")
|
||||||
}
|
}
|
||||||
@ -231,6 +231,12 @@ func NewJoin(cfgPath string, args []string, defaultcfg *kubeadmapiv1alpha2.NodeC
|
|||||||
|
|
||||||
// Run executes worker node provisioning and tries to join an existing cluster.
|
// Run executes worker node provisioning and tries to join an existing cluster.
|
||||||
func (j *Join) Run(out io.Writer) error {
|
func (j *Join) Run(out io.Writer) error {
|
||||||
|
|
||||||
|
// Write env file with flags for the kubelet to use. Also register taints
|
||||||
|
if err := kubeletphase.WriteKubeletDynamicEnvFile(&j.cfg.NodeRegistration, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
glog.V(1).Infoln("[join] retrieving KubeConfig objects")
|
glog.V(1).Infoln("[join] retrieving KubeConfig objects")
|
||||||
cfg, err := discovery.For(j.cfg)
|
cfg, err := discovery.For(j.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -273,7 +279,7 @@ func (j *Join) Run(out io.Writer) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := kubeletphase.EnableDynamicConfigForNode(client, j.cfg.NodeName, kubeletVersion); err != nil {
|
if err := kubeletphase.EnableDynamicConfigForNode(client, j.cfg.NodeRegistration.Name, kubeletVersion); err != nil {
|
||||||
return fmt.Errorf("error consuming base kubelet configuration: %v", err)
|
return fmt.Errorf("error consuming base kubelet configuration: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,7 @@ func getKubeConfigSubCommands(out io.Writer, outDir, defaultKubernetesVersion st
|
|||||||
cmd.Flags().Int32Var(&cfg.API.BindPort, "apiserver-bind-port", cfg.API.BindPort, "The port the API server is accessible on")
|
cmd.Flags().Int32Var(&cfg.API.BindPort, "apiserver-bind-port", cfg.API.BindPort, "The port the API server is accessible on")
|
||||||
cmd.Flags().StringVar(&outDir, "kubeconfig-dir", outDir, "The path where to save the kubeconfig file")
|
cmd.Flags().StringVar(&outDir, "kubeconfig-dir", outDir, "The path where to save the kubeconfig file")
|
||||||
if properties.use == "all" || properties.use == "kubelet" {
|
if properties.use == "all" || properties.use == "kubelet" {
|
||||||
cmd.Flags().StringVar(&cfg.NodeName, "node-name", cfg.NodeName, `The node name that should be used for the kubelet client certificate`)
|
cmd.Flags().StringVar(&cfg.NodeRegistration.Name, "node-name", cfg.NodeRegistration.Name, `The node name that should be used for the kubelet client certificate`)
|
||||||
}
|
}
|
||||||
if properties.use == "user" {
|
if properties.use == "user" {
|
||||||
cmd.Flags().StringVar(&token, "token", token, "The token that should be used as the authentication mechanism for this kubeconfig, instead of client certificates")
|
cmd.Flags().StringVar(&token, "token", token, "The token that should be used as the authentication mechanism for this kubeconfig, instead of client certificates")
|
||||||
|
@ -134,9 +134,6 @@ func NewCmdKubeletWriteConfigToDisk(kubeConfigFile *string) *cobra.Command {
|
|||||||
kubeadmutil.CheckErr(fmt.Errorf("The --kubelet-version argument is required"))
|
kubeadmutil.CheckErr(fmt.Errorf("The --kubelet-version argument is required"))
|
||||||
}
|
}
|
||||||
|
|
||||||
kubeletVersion, err := version.ParseSemantic(kubeletVersionStr)
|
|
||||||
kubeadmutil.CheckErr(err)
|
|
||||||
|
|
||||||
client, err := kubeconfigutil.ClientSetFromFile(*kubeConfigFile)
|
client, err := kubeconfigutil.ClientSetFromFile(*kubeConfigFile)
|
||||||
kubeadmutil.CheckErr(err)
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
@ -144,7 +141,7 @@ func NewCmdKubeletWriteConfigToDisk(kubeConfigFile *string) *cobra.Command {
|
|||||||
internalcfg, err := configutil.FetchConfigFromFileOrCluster(client, os.Stdout, "kubelet", cfgPath)
|
internalcfg, err := configutil.FetchConfigFromFileOrCluster(client, os.Stdout, "kubelet", cfgPath)
|
||||||
kubeadmutil.CheckErr(err)
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
err = kubeletphase.WriteConfigToDisk(internalcfg.KubeletConfiguration.BaseConfig, kubeletVersion)
|
err = kubeletphase.WriteConfigToDisk(internalcfg.KubeletConfiguration.BaseConfig)
|
||||||
kubeadmutil.CheckErr(err)
|
kubeadmutil.CheckErr(err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -75,14 +75,14 @@ func NewCmdMarkMaster() *cobra.Command {
|
|||||||
client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile)
|
client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile)
|
||||||
kubeadmutil.CheckErr(err)
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
err = markmasterphase.MarkMaster(client, internalcfg.NodeName, !internalcfg.NoTaintMaster)
|
err = markmasterphase.MarkMaster(client, internalcfg.NodeRegistration.Name, internalcfg.NodeRegistration.Taints)
|
||||||
kubeadmutil.CheckErr(err)
|
kubeadmutil.CheckErr(err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().StringVar(&kubeConfigFile, "kubeconfig", "/etc/kubernetes/admin.conf", "The KubeConfig file to use when talking to the cluster")
|
cmd.Flags().StringVar(&kubeConfigFile, "kubeconfig", "/etc/kubernetes/admin.conf", "The KubeConfig file to use when talking to the cluster")
|
||||||
cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file. WARNING: Usage of a configuration file is experimental")
|
cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file. WARNING: Usage of a configuration file is experimental")
|
||||||
cmd.Flags().StringVar(&cfg.NodeName, "node-name", cfg.NodeName, `The node name to which label and taints should apply`)
|
cmd.Flags().StringVar(&cfg.NodeRegistration.Name, "node-name", cfg.NodeRegistration.Name, `The node name to which label and taints should apply`)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
@ -165,8 +165,8 @@ const (
|
|||||||
APICallRetryInterval = 500 * time.Millisecond
|
APICallRetryInterval = 500 * time.Millisecond
|
||||||
// DiscoveryRetryInterval specifies how long kubeadm should wait before retrying to connect to the master when doing discovery
|
// DiscoveryRetryInterval specifies how long kubeadm should wait before retrying to connect to the master when doing discovery
|
||||||
DiscoveryRetryInterval = 5 * time.Second
|
DiscoveryRetryInterval = 5 * time.Second
|
||||||
// MarkMasterTimeout specifies how long kubeadm should wait for applying the label and taint on the master before timing out
|
// PatchNodeTimeout specifies how long kubeadm should wait for applying the label and taint on the master before timing out
|
||||||
MarkMasterTimeout = 2 * time.Minute
|
PatchNodeTimeout = 2 * time.Minute
|
||||||
// UpdateNodeTimeout specifies how long kubeadm should wait for updating node with the initial remote configuration of kubelet before timing out
|
// UpdateNodeTimeout specifies how long kubeadm should wait for updating node with the initial remote configuration of kubelet before timing out
|
||||||
UpdateNodeTimeout = 2 * time.Minute
|
UpdateNodeTimeout = 2 * time.Minute
|
||||||
|
|
||||||
@ -295,9 +295,6 @@ var (
|
|||||||
// MinimumKubeletVersion specifies the minimum version of kubelet which kubeadm supports
|
// MinimumKubeletVersion specifies the minimum version of kubelet which kubeadm supports
|
||||||
MinimumKubeletVersion = version.MustParseSemantic("v1.10.0")
|
MinimumKubeletVersion = version.MustParseSemantic("v1.10.0")
|
||||||
|
|
||||||
// MinimumKubeletConfigVersion specifies the minimum version of Kubernetes where kubeadm supports specifying --config to the kubelet
|
|
||||||
MinimumKubeletConfigVersion = version.MustParseSemantic("v1.11.0-alpha.1")
|
|
||||||
|
|
||||||
// SupportedEtcdVersion lists officially supported etcd versions with corresponding kubernetes releases
|
// SupportedEtcdVersion lists officially supported etcd versions with corresponding kubernetes releases
|
||||||
SupportedEtcdVersion = map[uint8]string{
|
SupportedEtcdVersion = map[uint8]string{
|
||||||
10: "3.1.12",
|
10: "3.1.12",
|
||||||
|
@ -275,7 +275,7 @@ func GetAPIServerAltNames(cfg *kubeadmapi.MasterConfiguration) (*certutil.AltNam
|
|||||||
// create AltNames with defaults DNSNames/IPs
|
// create AltNames with defaults DNSNames/IPs
|
||||||
altNames := &certutil.AltNames{
|
altNames := &certutil.AltNames{
|
||||||
DNSNames: []string{
|
DNSNames: []string{
|
||||||
cfg.NodeName,
|
cfg.NodeRegistration.Name,
|
||||||
"kubernetes",
|
"kubernetes",
|
||||||
"kubernetes.default",
|
"kubernetes.default",
|
||||||
"kubernetes.default.svc",
|
"kubernetes.default.svc",
|
||||||
@ -336,7 +336,7 @@ func GetEtcdPeerAltNames(cfg *kubeadmapi.MasterConfiguration) (*certutil.AltName
|
|||||||
|
|
||||||
// create AltNames with defaults DNSNames/IPs
|
// create AltNames with defaults DNSNames/IPs
|
||||||
altNames := &certutil.AltNames{
|
altNames := &certutil.AltNames{
|
||||||
DNSNames: []string{cfg.NodeName},
|
DNSNames: []string{cfg.NodeRegistration.Name},
|
||||||
IPs: []net.IP{advertiseAddress},
|
IPs: []net.IP{advertiseAddress},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ func getKubeConfigSpecs(cfg *kubeadmapi.MasterConfiguration) (map[string]*kubeCo
|
|||||||
kubeadmconstants.KubeletKubeConfigFileName: {
|
kubeadmconstants.KubeletKubeConfigFileName: {
|
||||||
CACert: caCert,
|
CACert: caCert,
|
||||||
APIServer: masterEndpoint,
|
APIServer: masterEndpoint,
|
||||||
ClientName: fmt.Sprintf("system:node:%s", cfg.NodeName),
|
ClientName: fmt.Sprintf("system:node:%s", cfg.NodeRegistration.Name),
|
||||||
ClientCertAuth: &clientCertAuth{
|
ClientCertAuth: &clientCertAuth{
|
||||||
CAKey: caKey,
|
CAKey: caKey,
|
||||||
Organizations: []string{kubeadmconstants.NodesGroup},
|
Organizations: []string{kubeadmconstants.NodesGroup},
|
||||||
|
@ -37,12 +37,7 @@ import (
|
|||||||
|
|
||||||
// WriteConfigToDisk writes the kubelet config object down to a file
|
// WriteConfigToDisk writes the kubelet config object down to a file
|
||||||
// Used at "kubeadm init" and "kubeadm upgrade" time
|
// Used at "kubeadm init" and "kubeadm upgrade" time
|
||||||
func WriteConfigToDisk(kubeletConfig *kubeletconfigv1beta1.KubeletConfiguration, kubeletVersion *version.Version) error {
|
func WriteConfigToDisk(kubeletConfig *kubeletconfigv1beta1.KubeletConfiguration) error {
|
||||||
|
|
||||||
// If the kubelet version is v1.10.x, exit
|
|
||||||
if kubeletVersion.LessThan(kubeadmconstants.MinimumKubeletConfigVersion) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
kubeletBytes, err := getConfigBytes(kubeletConfig)
|
kubeletBytes, err := getConfigBytes(kubeletConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -60,11 +55,6 @@ func CreateConfigMap(cfg *kubeadmapi.MasterConfiguration, client clientset.Inter
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If Kubernetes version is v1.10.x, exit
|
|
||||||
if k8sVersion.LessThan(kubeadmconstants.MinimumKubeletConfigVersion) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
configMapName := configMapName(k8sVersion)
|
configMapName := configMapName(k8sVersion)
|
||||||
fmt.Printf("[kubelet] Creating a ConfigMap %q in namespace %s with the configuration for the kubelets in the cluster\n", configMapName, metav1.NamespaceSystem)
|
fmt.Printf("[kubelet] Creating a ConfigMap %q in namespace %s with the configuration for the kubelets in the cluster\n", configMapName, metav1.NamespaceSystem)
|
||||||
|
|
||||||
@ -132,11 +122,6 @@ func createConfigMapRBACRules(client clientset.Interface, k8sVersion *version.Ve
|
|||||||
// Used at "kubeadm join" time
|
// Used at "kubeadm join" time
|
||||||
func DownloadConfig(kubeletKubeConfig string, kubeletVersion *version.Version) error {
|
func DownloadConfig(kubeletKubeConfig string, kubeletVersion *version.Version) error {
|
||||||
|
|
||||||
// If the kubelet version is v1.10.x, exit
|
|
||||||
if kubeletVersion.LessThan(kubeadmconstants.MinimumKubeletConfigVersion) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Download the ConfigMap from the cluster based on what version the kubelet is
|
// Download the ConfigMap from the cluster based on what version the kubelet is
|
||||||
configMapName := configMapName(kubeletVersion)
|
configMapName := configMapName(kubeletVersion)
|
||||||
|
|
||||||
|
@ -17,19 +17,17 @@ limitations under the License.
|
|||||||
package kubelet
|
package kubelet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
|
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||||
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
||||||
"k8s.io/kubernetes/pkg/util/version"
|
"k8s.io/kubernetes/pkg/util/version"
|
||||||
)
|
)
|
||||||
@ -39,64 +37,33 @@ import (
|
|||||||
// This func is ONLY run if the user enables the `DynamicKubeletConfig` feature gate, which is by default off
|
// This func is ONLY run if the user enables the `DynamicKubeletConfig` feature gate, which is by default off
|
||||||
func EnableDynamicConfigForNode(client clientset.Interface, nodeName string, kubeletVersion *version.Version) error {
|
func EnableDynamicConfigForNode(client clientset.Interface, nodeName string, kubeletVersion *version.Version) error {
|
||||||
|
|
||||||
// If the kubelet version is v1.10.x, exit
|
|
||||||
if kubeletVersion.LessThan(kubeadmconstants.MinimumKubeletConfigVersion) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
configMapName := configMapName(kubeletVersion)
|
configMapName := configMapName(kubeletVersion)
|
||||||
fmt.Printf("[kubelet] Enabling Dynamic Kubelet Config for Node %q; config sourced from ConfigMap %q in namespace %s\n",
|
fmt.Printf("[kubelet] Enabling Dynamic Kubelet Config for Node %q; config sourced from ConfigMap %q in namespace %s\n",
|
||||||
nodeName, configMapName, metav1.NamespaceSystem)
|
nodeName, configMapName, metav1.NamespaceSystem)
|
||||||
fmt.Println("[kubelet] WARNING: The Dynamic Kubelet Config feature is alpha and off by default. It hasn't been well-tested yet at this stage, use with caution.")
|
fmt.Println("[kubelet] WARNING: The Dynamic Kubelet Config feature is alpha and off by default. It hasn't been well-tested yet at this stage, use with caution.")
|
||||||
|
|
||||||
|
kubeletConfigMap, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(configMapName, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("couldn't get the kubelet configuration ConfigMap: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Loop on every falsy return. Return with an error if raised. Exit successfully if true is returned.
|
// Loop on every falsy return. Return with an error if raised. Exit successfully if true is returned.
|
||||||
return wait.Poll(kubeadmconstants.APICallRetryInterval, kubeadmconstants.UpdateNodeTimeout, func() (bool, error) {
|
return apiclient.PatchNode(client, nodeName, func(n *v1.Node) {
|
||||||
node, err := client.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{})
|
patchNodeForDynamicConfig(n, configMapName, kubeletConfigMap.UID)
|
||||||
if err != nil {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
oldData, err := json.Marshal(node)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
kubeletCfg, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(configMapName, metav1.GetOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
node.Spec.ConfigSource = &v1.NodeConfigSource{
|
|
||||||
ConfigMap: &v1.ConfigMapNodeConfigSource{
|
|
||||||
Name: configMapName,
|
|
||||||
Namespace: metav1.NamespaceSystem,
|
|
||||||
UID: kubeletCfg.UID,
|
|
||||||
KubeletConfigKey: kubeadmconstants.KubeletBaseConfigurationConfigMapKey,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
newData, err := json.Marshal(node)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{})
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := client.CoreV1().Nodes().Patch(node.Name, types.StrategicMergePatchType, patchBytes); err != nil {
|
|
||||||
if apierrs.IsConflict(err) {
|
|
||||||
fmt.Println("Temporarily unable to update node metadata due to conflict (will retry)")
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func patchNodeForDynamicConfig(n *v1.Node, configMapName string, configMapUID types.UID) {
|
||||||
|
n.Spec.ConfigSource = &v1.NodeConfigSource{
|
||||||
|
ConfigMap: &v1.ConfigMapNodeConfigSource{
|
||||||
|
Name: configMapName,
|
||||||
|
Namespace: metav1.NamespaceSystem,
|
||||||
|
UID: configMapUID,
|
||||||
|
KubeletConfigKey: kubeadmconstants.KubeletBaseConfigurationConfigMapKey,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetLocalNodeTLSBootstrappedClient 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
|
// and then creates a client from config file /etc/kubernetes/kubelet.conf
|
||||||
func GetLocalNodeTLSBootstrappedClient() (clientset.Interface, error) {
|
func GetLocalNodeTLSBootstrappedClient() (clientset.Interface, error) {
|
||||||
|
@ -31,10 +31,9 @@ import (
|
|||||||
|
|
||||||
// WriteKubeletDynamicEnvFile writes a environment file with dynamic flags to the kubelet.
|
// WriteKubeletDynamicEnvFile writes a environment file with dynamic flags to the kubelet.
|
||||||
// Used at "kubeadm init" and "kubeadm join" time.
|
// Used at "kubeadm init" and "kubeadm join" time.
|
||||||
func WriteKubeletDynamicEnvFile(cfg *kubeadmapi.MasterConfiguration) error {
|
func WriteKubeletDynamicEnvFile(nodeRegOpts *kubeadmapi.NodeRegistrationOptions, registerTaintsUsingFlags bool) error {
|
||||||
|
|
||||||
// TODO: Pass through extra arguments from the config file here in the future
|
argList := kubeadmutil.BuildArgumentListFromMap(buildKubeletArgMap(nodeRegOpts, registerTaintsUsingFlags), nodeRegOpts.ExtraArgs)
|
||||||
argList := kubeadmutil.BuildArgumentListFromMap(buildKubeletArgMap(cfg), map[string]string{})
|
|
||||||
envFileContent := fmt.Sprintf("%s=%s\n", constants.KubeletEnvFileVariableName, strings.Join(argList, " "))
|
envFileContent := fmt.Sprintf("%s=%s\n", constants.KubeletEnvFileVariableName, strings.Join(argList, " "))
|
||||||
|
|
||||||
return writeKubeletFlagBytesToDisk([]byte(envFileContent))
|
return writeKubeletFlagBytesToDisk([]byte(envFileContent))
|
||||||
@ -42,20 +41,28 @@ func WriteKubeletDynamicEnvFile(cfg *kubeadmapi.MasterConfiguration) error {
|
|||||||
|
|
||||||
// buildKubeletArgMap takes a MasterConfiguration object and builds based on that a string-string map with flags
|
// buildKubeletArgMap takes a MasterConfiguration object and builds based on that a string-string map with flags
|
||||||
// that should be given to the local kubelet daemon.
|
// that should be given to the local kubelet daemon.
|
||||||
func buildKubeletArgMap(cfg *kubeadmapi.MasterConfiguration) map[string]string {
|
func buildKubeletArgMap(nodeRegOpts *kubeadmapi.NodeRegistrationOptions, registerTaintsUsingFlags bool) map[string]string {
|
||||||
kubeletFlags := map[string]string{}
|
kubeletFlags := map[string]string{}
|
||||||
|
|
||||||
if cfg.CRISocket == kubeadmapiv1alpha2.DefaultCRISocket {
|
if nodeRegOpts.CRISocket == kubeadmapiv1alpha2.DefaultCRISocket {
|
||||||
// These flags should only be set when running docker
|
// These flags should only be set when running docker
|
||||||
kubeletFlags["network-plugin"] = "cni"
|
kubeletFlags["network-plugin"] = "cni"
|
||||||
kubeletFlags["cni-conf-dir"] = "/etc/cni/net.d"
|
kubeletFlags["cni-conf-dir"] = "/etc/cni/net.d"
|
||||||
kubeletFlags["cni-bin-dir"] = "/opt/cni/bin"
|
kubeletFlags["cni-bin-dir"] = "/opt/cni/bin"
|
||||||
} else {
|
} else {
|
||||||
kubeletFlags["container-runtime"] = "remote"
|
kubeletFlags["container-runtime"] = "remote"
|
||||||
kubeletFlags["container-runtime-endpoint"] = cfg.CRISocket
|
kubeletFlags["container-runtime-endpoint"] = nodeRegOpts.CRISocket
|
||||||
}
|
}
|
||||||
// TODO: Add support for registering custom Taints and Labels
|
|
||||||
// TODO: Add support for overriding flags with ExtraArgs
|
if registerTaintsUsingFlags && nodeRegOpts.Taints != nil && len(nodeRegOpts.Taints) > 0 {
|
||||||
|
taintStrs := []string{}
|
||||||
|
for _, taint := range nodeRegOpts.Taints {
|
||||||
|
taintStrs = append(taintStrs, taint.ToString())
|
||||||
|
}
|
||||||
|
|
||||||
|
kubeletFlags["register-with-taints"] = strings.Join(taintStrs, ",")
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Pass through --hostname-override if a custom name is used?
|
// TODO: Pass through --hostname-override if a custom name is used?
|
||||||
// TODO: Check if `systemd-resolved` is running, and set `--resolv-conf` based on that
|
// TODO: Check if `systemd-resolved` is running, and set `--resolv-conf` based on that
|
||||||
// TODO: Conditionally set `--cgroup-driver` to either `systemd` or `cgroupfs`
|
// TODO: Conditionally set `--cgroup-driver` to either `systemd` or `cgroupfs`
|
||||||
|
@ -17,107 +17,30 @@ limitations under the License.
|
|||||||
package markmaster
|
package markmaster
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MarkMaster taints the master and sets the master label
|
// MarkMaster taints the master and sets the master label
|
||||||
func MarkMaster(client clientset.Interface, masterName string, taint bool) error {
|
func MarkMaster(client clientset.Interface, masterName string, taints []v1.Taint) error {
|
||||||
|
|
||||||
if taint {
|
glog.Infof("[markmaster] Marking the node %s as master by adding the label \"%s=''\"\n", masterName, constants.LabelNodeRoleMaster)
|
||||||
glog.Infof("[markmaster] will mark node %s as master by adding a label and a taint\n", masterName)
|
|
||||||
} else {
|
if taints != nil && len(taints) > 0 {
|
||||||
glog.Infof("[markmaster] will mark node %s as master by adding a label\n", masterName)
|
glog.Infof("[markmaster] Marking the node %s as master by adding the taints %v\n", masterName, taints)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop on every falsy return. Return with an error if raised. Exit successfully if true is returned.
|
return apiclient.PatchNode(client, masterName, func(n *v1.Node) {
|
||||||
return wait.Poll(kubeadmconstants.APICallRetryInterval, kubeadmconstants.MarkMasterTimeout, func() (bool, error) {
|
markMasterNode(n, taints)
|
||||||
// First get the node object
|
|
||||||
n, err := client.CoreV1().Nodes().Get(masterName, metav1.GetOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// The node may appear to have no labels at first,
|
|
||||||
// so we wait for it to get hostname label.
|
|
||||||
if _, found := n.ObjectMeta.Labels[kubeletapis.LabelHostname]; !found {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
oldData, err := json.Marshal(n)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// The master node should be tainted and labelled accordingly
|
|
||||||
markMasterNode(n, taint)
|
|
||||||
|
|
||||||
newData, err := json.Marshal(n)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{})
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := client.CoreV1().Nodes().Patch(n.Name, types.StrategicMergePatchType, patchBytes); err != nil {
|
|
||||||
if apierrs.IsConflict(err) {
|
|
||||||
fmt.Println("[markmaster] Temporarily unable to update master node metadata due to conflict (will retry)")
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if taint {
|
|
||||||
fmt.Printf("[markmaster] Master %s tainted and labelled with key/value: %s=%q\n", masterName, kubeadmconstants.LabelNodeRoleMaster, "")
|
|
||||||
} else {
|
|
||||||
fmt.Printf("[markmaster] Master %s labelled with key/value: %s=%q\n", masterName, kubeadmconstants.LabelNodeRoleMaster, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func markMasterNode(n *v1.Node, taint bool) {
|
func markMasterNode(n *v1.Node, taints []v1.Taint) {
|
||||||
n.ObjectMeta.Labels[kubeadmconstants.LabelNodeRoleMaster] = ""
|
n.ObjectMeta.Labels[constants.LabelNodeRoleMaster] = ""
|
||||||
if taint {
|
// TODO: Append taints, don't override?
|
||||||
addTaintIfNotExists(n, kubeadmconstants.MasterTaint)
|
|
||||||
} else {
|
|
||||||
delTaintIfExists(n, kubeadmconstants.MasterTaint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func addTaintIfNotExists(n *v1.Node, t v1.Taint) {
|
|
||||||
for _, taint := range n.Spec.Taints {
|
|
||||||
if taint == t {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n.Spec.Taints = append(n.Spec.Taints, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func delTaintIfExists(n *v1.Node, t v1.Taint) {
|
|
||||||
var taints []v1.Taint
|
|
||||||
for _, taint := range n.Spec.Taints {
|
|
||||||
if taint == t {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
taints = append(taints, t)
|
|
||||||
}
|
|
||||||
n.Spec.Taints = taints
|
n.Spec.Taints = taints
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ func CreateSelfHostedControlPlane(manifestsDir, kubeConfigDir string, cfg *kubea
|
|||||||
// Wait for the mirror Pod hash to be removed; otherwise we'll run into race conditions here when the kubelet hasn't had time to
|
// Wait for the mirror Pod hash to be removed; otherwise we'll run into race conditions here when the kubelet hasn't had time to
|
||||||
// remove the Static Pod (or the mirror Pod respectively). This implicitly also tests that the API server endpoint is healthy,
|
// remove the Static Pod (or the mirror Pod respectively). This implicitly also tests that the API server endpoint is healthy,
|
||||||
// because this blocks until the API server returns a 404 Not Found when getting the Static Pod
|
// because this blocks until the API server returns a 404 Not Found when getting the Static Pod
|
||||||
staticPodName := fmt.Sprintf("%s-%s", componentName, cfg.NodeName)
|
staticPodName := fmt.Sprintf("%s-%s", componentName, cfg.NodeRegistration.Name)
|
||||||
if err := waiter.WaitForPodToDisappear(staticPodName); err != nil {
|
if err := waiter.WaitForPodToDisappear(staticPodName); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -206,7 +206,7 @@ func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticP
|
|||||||
// notice the removal of the Static Pod, leading to a false positive below where we check that the API endpoint is healthy
|
// notice the removal of the Static Pod, leading to a false positive below where we check that the API endpoint is healthy
|
||||||
// If we don't do this, there is a case where we remove the Static Pod manifest, kubelet is slow to react, kubeadm checks the
|
// If we don't do this, there is a case where we remove the Static Pod manifest, kubelet is slow to react, kubeadm checks the
|
||||||
// API endpoint below of the OLD Static Pod component and proceeds quickly enough, which might lead to unexpected results.
|
// API endpoint below of the OLD Static Pod component and proceeds quickly enough, which might lead to unexpected results.
|
||||||
if err := waiter.WaitForStaticPodHashChange(cfg.NodeName, component, beforePodHash); err != nil {
|
if err := waiter.WaitForStaticPodHashChange(cfg.NodeRegistration.Name, component, beforePodHash); err != nil {
|
||||||
return rollbackOldManifests(recoverManifests, err, pathMgr, recoverEtcd)
|
return rollbackOldManifests(recoverManifests, err, pathMgr, recoverEtcd)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +266,7 @@ func performEtcdStaticPodUpgrade(waiter apiclient.Waiter, pathMgr StaticPodPathM
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEtcdPodHash, err := waiter.WaitForStaticPodSingleHash(cfg.NodeName, constants.Etcd)
|
beforeEtcdPodHash, err := waiter.WaitForStaticPodSingleHash(cfg.NodeRegistration.Name, constants.Etcd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true, fmt.Errorf("failed to get etcd pod's hash: %v", err)
|
return true, fmt.Errorf("failed to get etcd pod's hash: %v", err)
|
||||||
}
|
}
|
||||||
@ -376,7 +376,7 @@ func StaticPodControlPlane(waiter apiclient.Waiter, pathMgr StaticPodPathManager
|
|||||||
var isTLSUpgrade bool
|
var isTLSUpgrade bool
|
||||||
var isExternalEtcd bool
|
var isExternalEtcd bool
|
||||||
|
|
||||||
beforePodHashMap, err := waiter.WaitForStaticPodControlPlaneHashes(cfg.NodeName)
|
beforePodHashMap, err := waiter.WaitForStaticPodControlPlaneHashes(cfg.NodeRegistration.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -906,7 +906,7 @@ func RunInitMasterChecks(execer utilsexec.Interface, cfg *kubeadmapi.MasterConfi
|
|||||||
checks = addCommonChecks(execer, cfg, checks)
|
checks = addCommonChecks(execer, cfg, checks)
|
||||||
|
|
||||||
// Check ipvs required kernel module once we use ipvs kube-proxy mode
|
// Check ipvs required kernel module once we use ipvs kube-proxy mode
|
||||||
if cfg.KubeProxy.Config.Mode == ipvsutil.IPVSProxyMode {
|
if cfg.KubeProxy.Config != nil && cfg.KubeProxy.Config.Mode == ipvsutil.IPVSProxyMode {
|
||||||
checks = append(checks,
|
checks = append(checks,
|
||||||
ipvsutil.RequiredIPVSKernelModulesAvailableCheck{Executor: execer},
|
ipvsutil.RequiredIPVSKernelModulesAvailableCheck{Executor: execer},
|
||||||
)
|
)
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package apiclient
|
package apiclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
apps "k8s.io/api/apps/v1"
|
apps "k8s.io/api/apps/v1"
|
||||||
@ -24,7 +25,12 @@ import (
|
|||||||
rbac "k8s.io/api/rbac/v1"
|
rbac "k8s.io/api/rbac/v1"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||||
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
|
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: We should invent a dynamic mechanism for this using the dynamic client instead of hard-coding these functions per-type
|
// TODO: We should invent a dynamic mechanism for this using the dynamic client instead of hard-coding these functions per-type
|
||||||
@ -186,3 +192,49 @@ func CreateOrUpdateClusterRoleBinding(client clientset.Interface, clusterRoleBin
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PatchNode tries to patch a node using the following client, executing patchFn for the actual mutating logic
|
||||||
|
func PatchNode(client clientset.Interface, nodeName string, patchFn func(*v1.Node)) error {
|
||||||
|
// Loop on every false return. Return with an error if raised. Exit successfully if true is returned.
|
||||||
|
return wait.Poll(constants.APICallRetryInterval, constants.PatchNodeTimeout, func() (bool, error) {
|
||||||
|
// First get the node object
|
||||||
|
n, err := client.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// The node may appear to have no labels at first,
|
||||||
|
// so we wait for it to get hostname label.
|
||||||
|
if _, found := n.ObjectMeta.Labels[kubeletapis.LabelHostname]; !found {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
oldData, err := json.Marshal(n)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the mutating function
|
||||||
|
patchFn(n)
|
||||||
|
|
||||||
|
newData, err := json.Marshal(n)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := client.CoreV1().Nodes().Patch(n.Name, types.StrategicMergePatchType, patchBytes); err != nil {
|
||||||
|
if apierrors.IsConflict(err) {
|
||||||
|
fmt.Println("[patchnode] Temporarily unable to update node metadata due to conflict (will retry)")
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
netutil "k8s.io/apimachinery/pkg/util/net"
|
netutil "k8s.io/apimachinery/pkg/util/net"
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
@ -72,7 +73,12 @@ func SetInitDynamicDefaults(cfg *kubeadmapi.MasterConfiguration) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.NodeName = node.GetHostname(cfg.NodeName)
|
cfg.NodeRegistration.Name = node.GetHostname(cfg.NodeRegistration.Name)
|
||||||
|
|
||||||
|
// Only if the slice is nil, we should append the master taint. This allows the user to specify an empty slice for no default master taint
|
||||||
|
if cfg.NodeRegistration.Taints == nil {
|
||||||
|
cfg.NodeRegistration.Taints = []v1.Taint{kubeadmconstants.MasterTaint}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ import (
|
|||||||
|
|
||||||
// SetJoinDynamicDefaults checks and sets configuration values for the NodeConfiguration object
|
// SetJoinDynamicDefaults checks and sets configuration values for the NodeConfiguration object
|
||||||
func SetJoinDynamicDefaults(cfg *kubeadmapi.NodeConfiguration) error {
|
func SetJoinDynamicDefaults(cfg *kubeadmapi.NodeConfiguration) error {
|
||||||
cfg.NodeName = node.GetHostname(cfg.NodeName)
|
cfg.NodeRegistration.Name = node.GetHostname(cfg.NodeRegistration.Name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,9 +57,10 @@ func SetupMasterConfigurationFile(t *testing.T, tmpdir string, cfg *kubeadmapi.M
|
|||||||
kind: MasterConfiguration
|
kind: MasterConfiguration
|
||||||
certificatesDir: {{.CertificatesDir}}
|
certificatesDir: {{.CertificatesDir}}
|
||||||
api:
|
api:
|
||||||
advertiseAddress: {{.API.AdvertiseAddress}}
|
advertiseAddress: {{.API.AdvertiseAddress}}
|
||||||
bindPort: {{.API.BindPort}}
|
bindPort: {{.API.BindPort}}
|
||||||
nodeName: {{.NodeName}}
|
nodeRegistration:
|
||||||
|
name: {{.NodeRegistration.Name}}
|
||||||
`)))
|
`)))
|
||||||
|
|
||||||
f, err := os.Create(cfgPath)
|
f, err := os.Create(cfgPath)
|
||||||
|
Loading…
Reference in New Issue
Block a user