mirror of https://github.com/k3s-io/k3s
kubeadm: add configuration option to not taint master
Although tainting the master is normally a good and proper thing to do in some
situations (docker for mac in our case, but I suppose minikube and such as
well) having a single host configuration is desirable.
In linuxkit we have a [workaround](443e47c408/projects/kubernetes/kubernetes/kubeadm-init.sh (L19...L22)
)
to remove the taint after initialisation. With the change here we could simply
populate /etc/kubeadm/kubeadm.yaml` with `noTaintMaster: true` instead and have
it never be tainted in the first place.
I have only added this to the config file and not to the CLI since AIUI the
latter is somewhat deprecated.
The code also arranges to _remove_ an existing taint if it is unwanted. I'm
unsure if this behaviour is correct or desirable, I think a reasonable argument
could be made for leaving an existing taint in place too.
Signed-off-by: Ian Campbell <ijc@docker.com>
pull/6/head
parent
117780b908
commit
a4e00ff3d8
|
@ -50,6 +50,10 @@ type MasterConfiguration struct {
|
||||||
// If not specified, defaults to Node and RBAC, meaning both the node
|
// If not specified, defaults to Node and RBAC, meaning both the node
|
||||||
// authorizer and RBAC are enabled.
|
// authorizer and RBAC are enabled.
|
||||||
AuthorizationModes []string
|
AuthorizationModes []string
|
||||||
|
// 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
|
||||||
|
|
||||||
// Mark the controller and api server pods as privileged as some cloud
|
// Mark the controller and api server pods as privileged as some cloud
|
||||||
// controllers like openstack need escalated privileges under some conditions
|
// controllers like openstack need escalated privileges under some conditions
|
||||||
|
|
|
@ -50,6 +50,10 @@ type MasterConfiguration struct {
|
||||||
// If not specified, defaults to Node and RBAC, meaning both the node
|
// If not specified, defaults to Node and RBAC, meaning both the node
|
||||||
// authorizer and RBAC are enabled.
|
// authorizer and RBAC are enabled.
|
||||||
AuthorizationModes []string `json:"authorizationModes,omitempty"`
|
AuthorizationModes []string `json:"authorizationModes,omitempty"`
|
||||||
|
// 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"`
|
||||||
|
|
||||||
// Mark the controller and api server pods as privileged as some cloud
|
// Mark the controller and api server pods as privileged as some cloud
|
||||||
// controllers like openstack need escalated privileges under some conditions
|
// controllers like openstack need escalated privileges under some conditions
|
||||||
|
|
|
@ -202,6 +202,7 @@ func autoConvert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in
|
||||||
out.CloudProvider = in.CloudProvider
|
out.CloudProvider = in.CloudProvider
|
||||||
out.NodeName = in.NodeName
|
out.NodeName = in.NodeName
|
||||||
out.AuthorizationModes = *(*[]string)(unsafe.Pointer(&in.AuthorizationModes))
|
out.AuthorizationModes = *(*[]string)(unsafe.Pointer(&in.AuthorizationModes))
|
||||||
|
out.NoTaintMaster = in.NoTaintMaster
|
||||||
out.PrivilegedPods = in.PrivilegedPods
|
out.PrivilegedPods = in.PrivilegedPods
|
||||||
out.Token = in.Token
|
out.Token = in.Token
|
||||||
out.TokenTTL = (*v1.Duration)(unsafe.Pointer(in.TokenTTL))
|
out.TokenTTL = (*v1.Duration)(unsafe.Pointer(in.TokenTTL))
|
||||||
|
@ -244,6 +245,7 @@ func autoConvert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration(in
|
||||||
out.CloudProvider = in.CloudProvider
|
out.CloudProvider = in.CloudProvider
|
||||||
out.NodeName = in.NodeName
|
out.NodeName = in.NodeName
|
||||||
out.AuthorizationModes = *(*[]string)(unsafe.Pointer(&in.AuthorizationModes))
|
out.AuthorizationModes = *(*[]string)(unsafe.Pointer(&in.AuthorizationModes))
|
||||||
|
out.NoTaintMaster = in.NoTaintMaster
|
||||||
out.PrivilegedPods = in.PrivilegedPods
|
out.PrivilegedPods = in.PrivilegedPods
|
||||||
out.Token = in.Token
|
out.Token = in.Token
|
||||||
out.TokenTTL = (*v1.Duration)(unsafe.Pointer(in.TokenTTL))
|
out.TokenTTL = (*v1.Duration)(unsafe.Pointer(in.TokenTTL))
|
||||||
|
|
|
@ -388,7 +388,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
|
||||||
if err := markmasterphase.MarkMaster(client, i.cfg.NodeName); err != nil {
|
if err := markmasterphase.MarkMaster(client, i.cfg.NodeName, !i.cfg.NoTaintMaster); err != nil {
|
||||||
return fmt.Errorf("error marking master: %v", err)
|
return fmt.Errorf("error marking master: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ 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)
|
err = markmasterphase.MarkMaster(client, internalcfg.NodeName, !internalcfg.NoTaintMaster)
|
||||||
kubeadmutil.CheckErr(err)
|
kubeadmutil.CheckErr(err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,9 +32,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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) error {
|
func MarkMaster(client clientset.Interface, masterName string, taint bool) error {
|
||||||
|
|
||||||
|
if taint {
|
||||||
fmt.Printf("[markmaster] Will mark node %s as master by adding a label and a taint\n", masterName)
|
fmt.Printf("[markmaster] Will mark node %s as master by adding a label and a taint\n", masterName)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("[markmaster] Will mark node %s as master by adding a label\n", masterName)
|
||||||
|
}
|
||||||
|
|
||||||
// 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.MarkMasterTimeout, func() (bool, error) {
|
return wait.Poll(kubeadmconstants.APICallRetryInterval, kubeadmconstants.MarkMasterTimeout, func() (bool, error) {
|
||||||
|
@ -56,7 +60,7 @@ func MarkMaster(client clientset.Interface, masterName string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The master node should be tainted and labelled accordingly
|
// The master node should be tainted and labelled accordingly
|
||||||
markMasterNode(n)
|
markMasterNode(n, taint)
|
||||||
|
|
||||||
newData, err := json.Marshal(n)
|
newData, err := json.Marshal(n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -76,15 +80,23 @@ func MarkMaster(client clientset.Interface, masterName string) error {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if taint {
|
||||||
fmt.Printf("[markmaster] Master %s tainted and labelled with key/value: %s=%q\n", masterName, kubeadmconstants.LabelNodeRoleMaster, "")
|
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
|
return true, nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func markMasterNode(n *v1.Node) {
|
func markMasterNode(n *v1.Node, taint bool) {
|
||||||
n.ObjectMeta.Labels[kubeadmconstants.LabelNodeRoleMaster] = ""
|
n.ObjectMeta.Labels[kubeadmconstants.LabelNodeRoleMaster] = ""
|
||||||
|
if taint {
|
||||||
addTaintIfNotExists(n, kubeadmconstants.MasterTaint)
|
addTaintIfNotExists(n, kubeadmconstants.MasterTaint)
|
||||||
|
} else {
|
||||||
|
delTaintIfExists(n, kubeadmconstants.MasterTaint)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addTaintIfNotExists(n *v1.Node, t v1.Taint) {
|
func addTaintIfNotExists(n *v1.Node, t v1.Taint) {
|
||||||
|
@ -96,3 +108,14 @@ func addTaintIfNotExists(n *v1.Node, t v1.Taint) {
|
||||||
|
|
||||||
n.Spec.Taints = append(n.Spec.Taints, t)
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -43,32 +43,51 @@ func TestMarkMaster(t *testing.T) {
|
||||||
name string
|
name string
|
||||||
existingLabel string
|
existingLabel string
|
||||||
existingTaint *v1.Taint
|
existingTaint *v1.Taint
|
||||||
|
wantTaint bool
|
||||||
expectedPatch string
|
expectedPatch string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"master label and taint missing",
|
"master label and taint missing",
|
||||||
"",
|
"",
|
||||||
nil,
|
nil,
|
||||||
|
true,
|
||||||
"{\"metadata\":{\"labels\":{\"node-role.kubernetes.io/master\":\"\"}},\"spec\":{\"taints\":[{\"effect\":\"NoSchedule\",\"key\":\"node-role.kubernetes.io/master\"}]}}",
|
"{\"metadata\":{\"labels\":{\"node-role.kubernetes.io/master\":\"\"}},\"spec\":{\"taints\":[{\"effect\":\"NoSchedule\",\"key\":\"node-role.kubernetes.io/master\"}]}}",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"master label and taint missing but taint not wanted",
|
||||||
|
"",
|
||||||
|
nil,
|
||||||
|
false,
|
||||||
|
"{\"metadata\":{\"labels\":{\"node-role.kubernetes.io/master\":\"\"}}}",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"master label missing",
|
"master label missing",
|
||||||
"",
|
"",
|
||||||
&kubeadmconstants.MasterTaint,
|
&kubeadmconstants.MasterTaint,
|
||||||
|
true,
|
||||||
"{\"metadata\":{\"labels\":{\"node-role.kubernetes.io/master\":\"\"}}}",
|
"{\"metadata\":{\"labels\":{\"node-role.kubernetes.io/master\":\"\"}}}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"master taint missing",
|
"master taint missing",
|
||||||
kubeadmconstants.LabelNodeRoleMaster,
|
kubeadmconstants.LabelNodeRoleMaster,
|
||||||
nil,
|
nil,
|
||||||
|
true,
|
||||||
"{\"spec\":{\"taints\":[{\"effect\":\"NoSchedule\",\"key\":\"node-role.kubernetes.io/master\"}]}}",
|
"{\"spec\":{\"taints\":[{\"effect\":\"NoSchedule\",\"key\":\"node-role.kubernetes.io/master\"}]}}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nothing missing",
|
"nothing missing",
|
||||||
kubeadmconstants.LabelNodeRoleMaster,
|
kubeadmconstants.LabelNodeRoleMaster,
|
||||||
&kubeadmconstants.MasterTaint,
|
&kubeadmconstants.MasterTaint,
|
||||||
|
true,
|
||||||
"{}",
|
"{}",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"nothing missing but taint unwanted",
|
||||||
|
kubeadmconstants.LabelNodeRoleMaster,
|
||||||
|
&kubeadmconstants.MasterTaint,
|
||||||
|
false,
|
||||||
|
"{\"spec\":{\"taints\":null}}",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
|
@ -125,7 +144,7 @@ func TestMarkMaster(t *testing.T) {
|
||||||
t.Fatalf("MarkMaster(%s): unexpected error building clientset: %v", tc.name, err)
|
t.Fatalf("MarkMaster(%s): unexpected error building clientset: %v", tc.name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = MarkMaster(cs, hostname)
|
err = MarkMaster(cs, hostname, tc.wantTaint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("MarkMaster(%s) returned unexpected error: %v", tc.name, err)
|
t.Errorf("MarkMaster(%s) returned unexpected error: %v", tc.name, err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue