mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-12 21:36:24 +00:00
kubeadm: Use a new label for marking and tainting the master node
This commit is contained in:
parent
17375fc59f
commit
0b16999e50
@ -11,6 +11,7 @@ go_library(
|
|||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = ["constants.go"],
|
srcs = ["constants.go"],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
|
deps = ["//vendor:k8s.io/client-go/pkg/api/v1"],
|
||||||
)
|
)
|
||||||
|
|
||||||
filegroup(
|
filegroup(
|
||||||
|
@ -19,6 +19,8 @@ package constants
|
|||||||
import (
|
import (
|
||||||
"path"
|
"path"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/client-go/pkg/api/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -69,6 +71,10 @@ const (
|
|||||||
// DefaultTokenDuration specifies the default amount of time that a bootstrap token will be valid
|
// DefaultTokenDuration specifies the default amount of time that a bootstrap token will be valid
|
||||||
DefaultTokenDuration = time.Duration(8) * time.Hour
|
DefaultTokenDuration = time.Duration(8) * time.Hour
|
||||||
|
|
||||||
|
// LabelNodeRoleMaster specifies that a node is a master
|
||||||
|
// It's copied over to kubeadm until it's merged in core: https://github.com/kubernetes/kubernetes/pull/39112
|
||||||
|
LabelNodeRoleMaster = "node-role.kubernetes.io/master"
|
||||||
|
|
||||||
// CSVTokenBootstrapUser is currently the user the bootstrap token in the .csv file
|
// CSVTokenBootstrapUser is currently the user the bootstrap token in the .csv file
|
||||||
// TODO: This should change to something more official and supported
|
// TODO: This should change to something more official and supported
|
||||||
// TODO: Prefix with kubeadm prefix
|
// TODO: Prefix with kubeadm prefix
|
||||||
@ -80,6 +86,13 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
||||||
|
// MasterToleration is the toleration to apply on the PodSpec for being able to run that Pod on the master
|
||||||
|
MasterToleration = v1.Toleration{
|
||||||
|
Key: LabelNodeRoleMaster,
|
||||||
|
Effect: v1.TaintEffectNoSchedule,
|
||||||
|
}
|
||||||
|
|
||||||
AuthorizationPolicyPath = path.Join(KubernetesDir, "abac_policy.json")
|
AuthorizationPolicyPath = path.Join(KubernetesDir, "abac_policy.json")
|
||||||
AuthorizationWebhookConfigPath = path.Join(KubernetesDir, "webhook_authz.conf")
|
AuthorizationWebhookConfigPath = path.Join(KubernetesDir, "webhook_authz.conf")
|
||||||
)
|
)
|
||||||
|
@ -107,9 +107,10 @@ func CreateDiscoveryDeploymentAndSecret(cfg *kubeadmapi.MasterConfiguration, cli
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createDiscoveryDeployment(client *clientset.Clientset) error {
|
func createDiscoveryDeployment(client *clientset.Clientset) error {
|
||||||
discoveryBytes, err := kubeadmutil.ParseTemplate(KubeDiscoveryDeployment, struct{ ImageRepository, Arch string }{
|
discoveryBytes, err := kubeadmutil.ParseTemplate(KubeDiscoveryDeployment, struct{ ImageRepository, Arch, MasterTaintKey string }{
|
||||||
ImageRepository: kubeadmapi.GlobalEnvParams.RepositoryPrefix,
|
ImageRepository: kubeadmapi.GlobalEnvParams.RepositoryPrefix,
|
||||||
Arch: runtime.GOARCH,
|
Arch: runtime.GOARCH,
|
||||||
|
MasterTaintKey: kubeadmconstants.LabelNodeRoleMaster,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error when parsing kube-discovery template: %v", err)
|
return fmt.Errorf("error when parsing kube-discovery template: %v", err)
|
||||||
@ -119,6 +120,10 @@ func createDiscoveryDeployment(client *clientset.Clientset) error {
|
|||||||
if err := kuberuntime.DecodeInto(api.Codecs.UniversalDecoder(), discoveryBytes, discoveryDeployment); err != nil {
|
if err := kuberuntime.DecodeInto(api.Codecs.UniversalDecoder(), discoveryBytes, discoveryDeployment); err != nil {
|
||||||
return fmt.Errorf("unable to decode kube-discovery deployment %v", err)
|
return fmt.Errorf("unable to decode kube-discovery deployment %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Set this in the yaml spec instead
|
||||||
|
discoveryDeployment.Spec.Template.Spec.Tolerations = []v1.Toleration{kubeadmconstants.MasterToleration}
|
||||||
|
|
||||||
if _, err := client.ExtensionsV1beta1().Deployments(metav1.NamespaceSystem).Create(discoveryDeployment); err != nil {
|
if _, err := client.ExtensionsV1beta1().Deployments(metav1.NamespaceSystem).Create(discoveryDeployment); err != nil {
|
||||||
return fmt.Errorf("unable to create a new discovery deployment: %v", err)
|
return fmt.Errorf("unable to create a new discovery deployment: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -218,7 +218,7 @@ func getAPIServerDS(cfg *kubeadmapi.MasterConfiguration, volumes []v1.Volume, vo
|
|||||||
Resources: componentResources("250m"),
|
Resources: componentResources("250m"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Tolerations: getMasterToleration(),
|
Tolerations: []v1.Toleration{kubeadmconstants.MasterToleration},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -269,7 +269,7 @@ func getControllerManagerDeployment(cfg *kubeadmapi.MasterConfiguration, volumes
|
|||||||
Env: getProxyEnvVars(),
|
Env: getProxyEnvVars(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Tolerations: getMasterToleration(),
|
Tolerations: []v1.Toleration{kubeadmconstants.MasterToleration},
|
||||||
DNSPolicy: v1.DNSDefault,
|
DNSPolicy: v1.DNSDefault,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -319,7 +319,7 @@ func getSchedulerDeployment(cfg *kubeadmapi.MasterConfiguration) ext.Deployment
|
|||||||
Env: getProxyEnvVars(),
|
Env: getProxyEnvVars(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Tolerations: getMasterToleration(),
|
Tolerations: []v1.Toleration{kubeadmconstants.MasterToleration},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -330,15 +330,3 @@ func getSchedulerDeployment(cfg *kubeadmapi.MasterConfiguration) ext.Deployment
|
|||||||
func buildStaticManifestFilepath(name string) string {
|
func buildStaticManifestFilepath(name string) string {
|
||||||
return path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "manifests", name+".yaml")
|
return path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "manifests", name+".yaml")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMasterToleration() []v1.Toleration {
|
|
||||||
// Tolerate the master taint we add to our master nodes, as this can and should
|
|
||||||
// run there.
|
|
||||||
// TODO: Duplicated above
|
|
||||||
return []v1.Toleration{{
|
|
||||||
Key: "dedicated",
|
|
||||||
Value: "master",
|
|
||||||
Operator: v1.TolerationOpEqual,
|
|
||||||
Effect: v1.TaintEffectNoSchedule,
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
@ -75,10 +75,10 @@ spec:
|
|||||||
name: clusterinfo
|
name: clusterinfo
|
||||||
readOnly: true
|
readOnly: true
|
||||||
hostNetwork: true
|
hostNetwork: true
|
||||||
tolerations:
|
# TODO: Why doesn't the Decoder recognize this new field and decode it properly? Right now it's ignored
|
||||||
- key: "dedicated"
|
# tolerations:
|
||||||
value: "master"
|
# - key: {{ .MasterTaintKey }}
|
||||||
effect: "NoSchedule"
|
# effect: NoSchedule
|
||||||
securityContext:
|
securityContext:
|
||||||
seLinuxOptions:
|
seLinuxOptions:
|
||||||
type: spc_t
|
type: spc_t
|
||||||
|
@ -17,6 +17,7 @@ go_library(
|
|||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||||
|
"//cmd/kubeadm/app/constants:go_default_library",
|
||||||
"//cmd/kubeadm/app/images:go_default_library",
|
"//cmd/kubeadm/app/images:go_default_library",
|
||||||
"//cmd/kubeadm/app/util:go_default_library",
|
"//cmd/kubeadm/app/util:go_default_library",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
@ -46,4 +47,5 @@ go_test(
|
|||||||
srcs = ["addons_test.go"],
|
srcs = ["addons_test.go"],
|
||||||
library = ":go_default_library",
|
library = ":go_default_library",
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
|
deps = ["//cmd/kubeadm/app/util:go_default_library"],
|
||||||
)
|
)
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
"k8s.io/client-go/pkg/api/v1"
|
"k8s.io/client-go/pkg/api/v1"
|
||||||
extensions "k8s.io/client-go/pkg/apis/extensions/v1beta1"
|
extensions "k8s.io/client-go/pkg/apis/extensions/v1beta1"
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
|
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
||||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||||
)
|
)
|
||||||
@ -43,19 +44,21 @@ func CreateEssentialAddons(cfg *kubeadmapi.MasterConfiguration, client *clientse
|
|||||||
return fmt.Errorf("error when parsing kube-proxy configmap template: %v", err)
|
return fmt.Errorf("error when parsing kube-proxy configmap template: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
proxyDaemonSetBytes, err := kubeadmutil.ParseTemplate(KubeProxyDaemonSet, struct{ Image, ClusterCIDR string }{
|
proxyDaemonSetBytes, err := kubeadmutil.ParseTemplate(KubeProxyDaemonSet, struct{ Image, ClusterCIDR, MasterTaintKey string }{
|
||||||
Image: images.GetCoreImage("proxy", cfg, kubeadmapi.GlobalEnvParams.HyperkubeImage),
|
Image: images.GetCoreImage("proxy", cfg, kubeadmapi.GlobalEnvParams.HyperkubeImage),
|
||||||
ClusterCIDR: getClusterCIDR(cfg.Networking.PodSubnet),
|
ClusterCIDR: getClusterCIDR(cfg.Networking.PodSubnet),
|
||||||
|
MasterTaintKey: kubeadmconstants.LabelNodeRoleMaster,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error when parsing kube-proxy daemonset template: %v", err)
|
return fmt.Errorf("error when parsing kube-proxy daemonset template: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dnsDeploymentBytes, err := kubeadmutil.ParseTemplate(KubeDNSDeployment, struct{ ImageRepository, Arch, Version, DNSDomain string }{
|
dnsDeploymentBytes, err := kubeadmutil.ParseTemplate(KubeDNSDeployment, struct{ ImageRepository, Arch, Version, DNSDomain, MasterTaintKey string }{
|
||||||
ImageRepository: kubeadmapi.GlobalEnvParams.RepositoryPrefix,
|
ImageRepository: kubeadmapi.GlobalEnvParams.RepositoryPrefix,
|
||||||
Arch: runtime.GOARCH,
|
Arch: runtime.GOARCH,
|
||||||
Version: KubeDNSVersion,
|
Version: KubeDNSVersion,
|
||||||
DNSDomain: cfg.Networking.DNSDomain,
|
DNSDomain: cfg.Networking.DNSDomain,
|
||||||
|
MasterTaintKey: kubeadmconstants.LabelNodeRoleMaster,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error when parsing kube-dns deployment template: %v", err)
|
return fmt.Errorf("error when parsing kube-dns deployment template: %v", err)
|
||||||
@ -101,6 +104,7 @@ func CreateKubeProxyAddon(configMapBytes, daemonSetbytes []byte, client *clients
|
|||||||
if err := kuberuntime.DecodeInto(api.Codecs.UniversalDecoder(), daemonSetbytes, kubeproxyDaemonSet); err != nil {
|
if err := kuberuntime.DecodeInto(api.Codecs.UniversalDecoder(), daemonSetbytes, kubeproxyDaemonSet); err != nil {
|
||||||
return fmt.Errorf("unable to decode kube-proxy daemonset %v", err)
|
return fmt.Errorf("unable to decode kube-proxy daemonset %v", err)
|
||||||
}
|
}
|
||||||
|
kubeproxyDaemonSet.Spec.Template.Spec.Tolerations = []v1.Toleration{kubeadmconstants.MasterToleration}
|
||||||
|
|
||||||
if _, err := client.ExtensionsV1beta1().DaemonSets(metav1.NamespaceSystem).Create(kubeproxyDaemonSet); err != nil {
|
if _, err := client.ExtensionsV1beta1().DaemonSets(metav1.NamespaceSystem).Create(kubeproxyDaemonSet); err != nil {
|
||||||
return fmt.Errorf("unable to create a new kube-proxy daemonset: %v", err)
|
return fmt.Errorf("unable to create a new kube-proxy daemonset: %v", err)
|
||||||
@ -113,6 +117,13 @@ func CreateKubeDNSAddon(deploymentBytes, serviceBytes []byte, client *clientset.
|
|||||||
if err := kuberuntime.DecodeInto(api.Codecs.UniversalDecoder(), deploymentBytes, kubednsDeployment); err != nil {
|
if err := kuberuntime.DecodeInto(api.Codecs.UniversalDecoder(), deploymentBytes, kubednsDeployment); err != nil {
|
||||||
return fmt.Errorf("unable to decode kube-dns deployment %v", err)
|
return fmt.Errorf("unable to decode kube-dns deployment %v", err)
|
||||||
}
|
}
|
||||||
|
kubednsDeployment.Spec.Template.Spec.Tolerations = []v1.Toleration{
|
||||||
|
kubeadmconstants.MasterToleration,
|
||||||
|
{
|
||||||
|
Key: "CriticalAddonsOnly",
|
||||||
|
Operator: "Exists",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: All these .Create(foo) calls should instead be more like "kubectl apply -f" commands; they should not fail if there are existing objects with the same name
|
// TODO: All these .Create(foo) calls should instead be more like "kubectl apply -f" commands; they should not fail if there are existing objects with the same name
|
||||||
if _, err := client.ExtensionsV1beta1().Deployments(metav1.NamespaceSystem).Create(kubednsDeployment); err != nil {
|
if _, err := client.ExtensionsV1beta1().Deployments(metav1.NamespaceSystem).Create(kubednsDeployment); err != nil {
|
||||||
|
@ -16,7 +16,11 @@ limitations under the License.
|
|||||||
|
|
||||||
package addons
|
package addons
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||||
|
)
|
||||||
|
|
||||||
func TestGetClusterCIDR(t *testing.T) {
|
func TestGetClusterCIDR(t *testing.T) {
|
||||||
emptyClusterCIDR := getClusterCIDR("")
|
emptyClusterCIDR := getClusterCIDR("")
|
||||||
@ -29,3 +33,56 @@ func TestGetClusterCIDR(t *testing.T) {
|
|||||||
t.Errorf("Invalid format: %s", clusterCIDR)
|
t.Errorf("Invalid format: %s", clusterCIDR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCompileManifests(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
manifest string
|
||||||
|
data interface{}
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
manifest: KubeProxyConfigMap,
|
||||||
|
data: struct{ MasterEndpoint string }{
|
||||||
|
MasterEndpoint: "foo",
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
manifest: KubeProxyDaemonSet,
|
||||||
|
data: struct{ Image, ClusterCIDR, MasterTaintKey string }{
|
||||||
|
Image: "foo",
|
||||||
|
ClusterCIDR: "foo",
|
||||||
|
MasterTaintKey: "foo",
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
manifest: KubeDNSDeployment,
|
||||||
|
data: struct{ ImageRepository, Arch, Version, DNSDomain, MasterTaintKey string }{
|
||||||
|
ImageRepository: "foo",
|
||||||
|
Arch: "foo",
|
||||||
|
Version: "foo",
|
||||||
|
DNSDomain: "foo",
|
||||||
|
MasterTaintKey: "foo",
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
manifest: KubeDNSService,
|
||||||
|
data: struct{ DNSIP string }{
|
||||||
|
DNSIP: "foo",
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, rt := range tests {
|
||||||
|
_, actual := kubeadmutil.ParseTemplate(rt.manifest, rt.data)
|
||||||
|
if (actual == nil) != rt.expected {
|
||||||
|
t.Errorf(
|
||||||
|
"failed CompileManifests:\n\texpected: %t\n\t actual: %t",
|
||||||
|
rt.expected,
|
||||||
|
(actual == nil),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -79,10 +79,10 @@ spec:
|
|||||||
name: kube-proxy
|
name: kube-proxy
|
||||||
hostNetwork: true
|
hostNetwork: true
|
||||||
serviceAccountName: kube-proxy
|
serviceAccountName: kube-proxy
|
||||||
tolerations:
|
# TODO: Why doesn't the Decoder recognize this new field and decode it properly? Right now it's ignored
|
||||||
- key: dedicated
|
# tolerations:
|
||||||
value: master
|
# - key: {{ .MasterTaintKey }}
|
||||||
effect: NoSchedule
|
# effect: NoSchedule
|
||||||
volumes:
|
volumes:
|
||||||
- name: kube-proxy
|
- name: kube-proxy
|
||||||
configMap:
|
configMap:
|
||||||
@ -235,12 +235,12 @@ spec:
|
|||||||
cpu: 10m
|
cpu: 10m
|
||||||
dnsPolicy: Default # Don't use cluster DNS.
|
dnsPolicy: Default # Don't use cluster DNS.
|
||||||
serviceAccountName: kube-dns
|
serviceAccountName: kube-dns
|
||||||
tolerations:
|
# TODO: Why doesn't the Decoder recognize this new field and decode it properly? Right now it's ignored
|
||||||
- key: "CriticalAddonsOnly"
|
# tolerations:
|
||||||
operator: "Exists"
|
# - key: CriticalAddonsOnly
|
||||||
- key: "dedicated"
|
# operator: Exists
|
||||||
value: "master"
|
# - key: {{ .MasterTaintKey }}
|
||||||
effect: "NoSchedule"
|
# effect: NoSchedule
|
||||||
# TODO: Remove this affinity field as soon as we are using manifest lists
|
# TODO: Remove this affinity field as soon as we are using manifest lists
|
||||||
affinity:
|
affinity:
|
||||||
nodeAffinity:
|
nodeAffinity:
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/pkg/api/v1"
|
"k8s.io/client-go/pkg/api/v1"
|
||||||
|
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
const apiCallRetryInterval = 500 * time.Millisecond
|
const apiCallRetryInterval = 500 * time.Millisecond
|
||||||
@ -58,10 +59,9 @@ func attemptToUpdateMasterRoleLabelsAndTaints(client *clientset.Clientset) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Switch to the new master label defined in https://github.com/kubernetes/kubernetes/pull/39112
|
// The master node is tainted and labelled accordingly
|
||||||
n.ObjectMeta.Labels[metav1.NodeLabelKubeadmAlphaRole] = metav1.NodeLabelRoleMaster
|
n.ObjectMeta.Labels[kubeadmconstants.LabelNodeRoleMaster] = ""
|
||||||
|
n.Spec.Taints = []v1.Taint{{Key: kubeadmconstants.LabelNodeRoleMaster, Value: "", Effect: "NoSchedule"}}
|
||||||
n.Spec.Taints = []v1.Taint{{Key: "dedicated", Value: "master", Effect: "NoSchedule"}}
|
|
||||||
|
|
||||||
newData, err := json.Marshal(n)
|
newData, err := json.Marshal(n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user