kubeadm: Centralize commonly used paths/constants to the constants pkg

This commit is contained in:
Lucas Käldström 2017-08-08 15:07:21 +03:00
parent d37f2f1a5d
commit 9a6ef9677a
No known key found for this signature in database
GPG Key ID: 3FA3783D77751514
15 changed files with 273 additions and 166 deletions

View File

@ -221,25 +221,27 @@ func (i *Init) Validate(cmd *cobra.Command) error {
// 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 {
// PHASE 1: Generate certificates k8sVersion, err := version.ParseSemantic(i.cfg.KubernetesVersion)
err := cmdphases.CreatePKIAssets(i.cfg)
if err != nil { if err != nil {
return fmt.Errorf("couldn't parse kubernetes version %q: %v", i.cfg.KubernetesVersion, err)
}
// PHASE 1: Generate certificates
if err := cmdphases.CreatePKIAssets(i.cfg); err != nil {
return err return err
} }
// PHASE 2: Generate kubeconfig files for the admin and the kubelet // PHASE 2: Generate kubeconfig files for the admin and the kubelet
err = kubeconfigphase.CreateInitKubeConfigFiles(kubeadmconstants.KubernetesDir, i.cfg) if err := kubeconfigphase.CreateInitKubeConfigFiles(kubeadmconstants.KubernetesDir, i.cfg); err != nil {
if err != nil {
return err return err
} }
// PHASE 3: Bootstrap the control plane // PHASE 3: Bootstrap the control plane
if err := controlplanephase.WriteStaticPodManifests(i.cfg); err != nil { if err := controlplanephase.WriteStaticPodManifests(i.cfg, k8sVersion, kubeadmconstants.GetStaticPodDirectory()); err != nil {
return err return err
} }
adminKubeConfigPath := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.AdminKubeConfigFileName) client, err := kubeadmutil.CreateClientAndWaitForAPI(kubeadmconstants.GetAdminKubeConfigPath())
client, err := kubeadmutil.CreateClientAndWaitForAPI(adminKubeConfigPath)
if err != nil { if err != nil {
return err return err
} }
@ -258,25 +260,18 @@ func (i *Init) Run(out io.Writer) error {
return err return err
} }
if err := tokenphase.CreateBootstrapConfigMapIfNotExists(client, adminKubeConfigPath); err != nil { if err := tokenphase.CreateBootstrapConfigMapIfNotExists(client, kubeadmconstants.GetAdminKubeConfigPath()); err != nil {
return err return err
} }
// PHASE 5: Install and deploy all addons, and configure things as necessary // PHASE 5: Install and deploy all addons, and configure things as necessary
k8sVersion, err := version.ParseSemantic(i.cfg.KubernetesVersion)
if err != nil {
return fmt.Errorf("couldn't parse kubernetes version %q: %v", i.cfg.KubernetesVersion, err)
}
// Create the necessary ServiceAccounts // Create the necessary ServiceAccounts
err = apiconfigphase.CreateServiceAccounts(client) if err := apiconfigphase.CreateServiceAccounts(client); err != nil {
if err != nil {
return err return err
} }
err = apiconfigphase.CreateRBACRules(client, k8sVersion) if err := apiconfigphase.CreateRBACRules(client, k8sVersion); err != nil {
if err != nil {
return err return err
} }

View File

@ -5,6 +5,7 @@ licenses(["notice"])
load( load(
"@io_bazel_rules_go//go:def.bzl", "@io_bazel_rules_go//go:def.bzl",
"go_library", "go_library",
"go_test",
) )
go_library( go_library(
@ -29,3 +30,10 @@ filegroup(
srcs = [":package-srcs"], srcs = [":package-srcs"],
tags = ["automanaged"], tags = ["automanaged"],
) )
go_test(
name = "go_default_test",
srcs = ["constants_test.go"],
library = ":go_default_library",
tags = ["automanaged"],
)

View File

@ -17,6 +17,7 @@ limitations under the License.
package constants package constants
import ( import (
"fmt"
"path/filepath" "path/filepath"
"time" "time"
@ -97,6 +98,18 @@ const (
// MinExternalEtcdVersion indicates minimum external etcd version which kubeadm supports // MinExternalEtcdVersion indicates minimum external etcd version which kubeadm supports
MinExternalEtcdVersion = "3.0.14" MinExternalEtcdVersion = "3.0.14"
// DefaultEtcdVersion indicates the default etcd version that kubeadm uses
DefaultEtcdVersion = "3.0.17"
Etcd = "etcd"
KubeAPIServer = "kube-apiserver"
KubeControllerManager = "kube-controller-manager"
KubeScheduler = "kube-scheduler"
KubeProxy = "kube-proxy"
// SelfHostingPrefix describes the prefix workloads that are self-hosted by kubeadm has
SelfHostingPrefix = "self-hosted-"
) )
var ( var (
@ -119,11 +132,29 @@ var (
// DefaultTokenUsages specifies the default functions a token will get // DefaultTokenUsages specifies the default functions a token will get
DefaultTokenUsages = []string{"signing", "authentication"} DefaultTokenUsages = []string{"signing", "authentication"}
// MasterComponents defines the master component names
MasterComponents = []string{KubeAPIServer, KubeControllerManager, KubeScheduler}
// MinimumControlPlaneVersion specifies the minimum control plane version kubeadm can deploy // MinimumControlPlaneVersion specifies the minimum control plane version kubeadm can deploy
MinimumControlPlaneVersion = version.MustParseSemantic("v1.7.0") MinimumControlPlaneVersion = version.MustParseSemantic("v1.7.0")
) )
// BuildStaticManifestFilepath returns the location on the disk where the Static Pod should be present // GetStaticPodDirectory returns the location on the disk where the Static Pod should be present
func BuildStaticManifestFilepath(componentName string) string { func GetStaticPodDirectory() string {
return filepath.Join(KubernetesDir, ManifestsSubDirName, componentName+".yaml") return filepath.Join(KubernetesDir, ManifestsSubDirName)
}
// GetStaticPodFilepath returns the location on the disk where the Static Pod should be present
func GetStaticPodFilepath(componentName, manifestsDir string) string {
return filepath.Join(manifestsDir, componentName+".yaml")
}
// GetAdminKubeConfigPath returns the location on the disk where admin kubeconfig is located by default
func GetAdminKubeConfigPath() string {
return filepath.Join(KubernetesDir, AdminKubeConfigFileName)
}
// AddSelfHostedPrefix adds the self-hosted- prefix to the component name
func AddSelfHostedPrefix(componentName string) string {
return fmt.Sprintf("%s%s", SelfHostingPrefix, componentName)
} }

View File

@ -0,0 +1,112 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package constants
import (
"testing"
)
func TestGetStaticPodDirectory(t *testing.T) {
expected := "/etc/kubernetes/manifests"
actual := GetStaticPodDirectory()
if actual != expected {
t.Errorf(
"failed GetStaticPodDirectory:\n\texpected: %s\n\t actual: %s",
expected,
actual,
)
}
}
func TestGetAdminKubeConfigPath(t *testing.T) {
expected := "/etc/kubernetes/admin.conf"
actual := GetAdminKubeConfigPath()
if actual != expected {
t.Errorf(
"failed GetAdminKubeConfigPath:\n\texpected: %s\n\t actual: %s",
expected,
actual,
)
}
}
func TestGetStaticPodFilepath(t *testing.T) {
var tests = []struct {
componentName, manifestsDir, expected string
}{
{
componentName: "kube-apiserver",
manifestsDir: "/etc/kubernetes/manifests",
expected: "/etc/kubernetes/manifests/kube-apiserver.yaml",
},
{
componentName: "kube-controller-manager",
manifestsDir: "/etc/kubernetes/manifests/",
expected: "/etc/kubernetes/manifests/kube-controller-manager.yaml",
},
{
componentName: "foo",
manifestsDir: "/etc/bar/",
expected: "/etc/bar/foo.yaml",
},
}
for _, rt := range tests {
actual := GetStaticPodFilepath(rt.componentName, rt.manifestsDir)
if actual != rt.expected {
t.Errorf(
"failed GetStaticPodFilepath:\n\texpected: %s\n\t actual: %s",
rt.expected,
actual,
)
}
}
}
func TestAddSelfHostedPrefix(t *testing.T) {
var tests = []struct {
componentName, expected string
}{
{
componentName: "kube-apiserver",
expected: "self-hosted-kube-apiserver",
},
{
componentName: "kube-controller-manager",
expected: "self-hosted-kube-controller-manager",
},
{
componentName: "kube-scheduler",
expected: "self-hosted-kube-scheduler",
},
{
componentName: "foo",
expected: "self-hosted-foo",
},
}
for _, rt := range tests {
actual := AddSelfHostedPrefix(rt.componentName)
if actual != rt.expected {
t.Errorf(
"failed AddSelfHostedPrefix:\n\texpected: %s\n\t actual: %s",
rt.expected,
actual,
)
}
}
}

View File

@ -13,7 +13,7 @@ go_library(
srcs = ["images.go"], srcs = ["images.go"],
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library", "//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/util:go_default_library", "//cmd/kubeadm/app/util:go_default_library",
], ],
) )
@ -23,7 +23,7 @@ go_test(
srcs = ["images_test.go"], srcs = ["images_test.go"],
library = ":go_default_library", library = ":go_default_library",
tags = ["automanaged"], tags = ["automanaged"],
deps = ["//cmd/kubeadm/app/apis/kubeadm:go_default_library"], deps = ["//cmd/kubeadm/app/constants:go_default_library"],
) )
filegroup( filegroup(

View File

@ -20,29 +20,19 @@ import (
"fmt" "fmt"
"runtime" "runtime"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" "k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
) )
const ( func GetCoreImage(image, repoPrefix, k8sVersion, overrideImage string) string {
KubeEtcdImage = "etcd"
KubeAPIServerImage = "apiserver"
KubeControllerManagerImage = "controller-manager"
KubeSchedulerImage = "scheduler"
etcdVersion = "3.0.17"
)
func GetCoreImage(image string, cfg *kubeadmapi.MasterConfiguration, overrideImage string) string {
if overrideImage != "" { if overrideImage != "" {
return overrideImage return overrideImage
} }
repoPrefix := cfg.ImageRepository kubernetesImageTag := kubeadmutil.KubernetesVersionToImageTag(k8sVersion)
kubernetesImageTag := kubeadmutil.KubernetesVersionToImageTag(cfg.KubernetesVersion)
return map[string]string{ return map[string]string{
KubeEtcdImage: fmt.Sprintf("%s/%s-%s:%s", repoPrefix, "etcd", runtime.GOARCH, etcdVersion), constants.Etcd: fmt.Sprintf("%s/%s-%s:%s", repoPrefix, "etcd", runtime.GOARCH, constants.DefaultEtcdVersion),
KubeAPIServerImage: fmt.Sprintf("%s/%s-%s:%s", repoPrefix, "kube-apiserver", runtime.GOARCH, kubernetesImageTag), constants.KubeAPIServer: fmt.Sprintf("%s/%s-%s:%s", repoPrefix, "kube-apiserver", runtime.GOARCH, kubernetesImageTag),
KubeControllerManagerImage: fmt.Sprintf("%s/%s-%s:%s", repoPrefix, "kube-controller-manager", runtime.GOARCH, kubernetesImageTag), constants.KubeControllerManager: fmt.Sprintf("%s/%s-%s:%s", repoPrefix, "kube-controller-manager", runtime.GOARCH, kubernetesImageTag),
KubeSchedulerImage: fmt.Sprintf("%s/%s-%s:%s", repoPrefix, "kube-scheduler", runtime.GOARCH, kubernetesImageTag), constants.KubeScheduler: fmt.Sprintf("%s/%s-%s:%s", repoPrefix, "kube-scheduler", runtime.GOARCH, kubernetesImageTag),
}[image] }[image]
} }

View File

@ -21,15 +21,9 @@ import (
"runtime" "runtime"
"testing" "testing"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" "k8s.io/kubernetes/cmd/kubeadm/app/constants"
) )
type getCoreImageTest struct {
i string
c *kubeadmapi.MasterConfiguration
o string
}
const ( const (
testversion = "v10.1.2-alpha.1.100+0123456789abcdef+SOMETHING" testversion = "v10.1.2-alpha.1.100+0123456789abcdef+SOMETHING"
expected = "v10.1.2-alpha.1.100_0123456789abcdef_SOMETHING" expected = "v10.1.2-alpha.1.100_0123456789abcdef_SOMETHING"
@ -37,38 +31,43 @@ const (
) )
func TestGetCoreImage(t *testing.T) { func TestGetCoreImage(t *testing.T) {
var imageTest = []struct { var tests = []struct {
t getCoreImageTest image, repo, version, override, expected string
expected string
}{ }{
{getCoreImageTest{o: "override"}, "override"}, {
{getCoreImageTest{ override: "override",
i: KubeEtcdImage, expected: "override",
c: &kubeadmapi.MasterConfiguration{ImageRepository: gcrPrefix}},
fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "etcd", runtime.GOARCH, etcdVersion),
}, },
{getCoreImageTest{ {
i: KubeAPIServerImage, image: constants.Etcd,
c: &kubeadmapi.MasterConfiguration{ImageRepository: gcrPrefix, KubernetesVersion: testversion}}, repo: gcrPrefix,
fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-apiserver", runtime.GOARCH, expected), expected: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "etcd", runtime.GOARCH, constants.DefaultEtcdVersion),
}, },
{getCoreImageTest{ {
i: KubeControllerManagerImage, image: constants.KubeAPIServer,
c: &kubeadmapi.MasterConfiguration{ImageRepository: gcrPrefix, KubernetesVersion: testversion}}, repo: gcrPrefix,
fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-controller-manager", runtime.GOARCH, expected), version: testversion,
expected: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-apiserver", runtime.GOARCH, expected),
}, },
{getCoreImageTest{ {
i: KubeSchedulerImage, image: constants.KubeControllerManager,
c: &kubeadmapi.MasterConfiguration{ImageRepository: gcrPrefix, KubernetesVersion: testversion}}, repo: gcrPrefix,
fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-scheduler", runtime.GOARCH, expected), version: testversion,
expected: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-controller-manager", runtime.GOARCH, expected),
},
{
image: constants.KubeScheduler,
repo: gcrPrefix,
version: testversion,
expected: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-scheduler", runtime.GOARCH, expected),
}, },
} }
for _, it := range imageTest { for _, rt := range tests {
actual := GetCoreImage(it.t.i, it.t.c, it.t.o) actual := GetCoreImage(rt.image, rt.repo, rt.version, rt.override)
if actual != it.expected { if actual != rt.expected {
t.Errorf( t.Errorf(
"failed GetCoreImage:\n\texpected: %s\n\t actual: %s", "failed GetCoreImage:\n\texpected: %s\n\t actual: %s",
it.expected, rt.expected,
actual, actual,
) )
} }

View File

@ -45,78 +45,66 @@ const (
DefaultCloudConfigPath = "/etc/kubernetes/cloud-config" DefaultCloudConfigPath = "/etc/kubernetes/cloud-config"
defaultv17AdmissionControl = "Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota" defaultv17AdmissionControl = "Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota"
etcd = "etcd"
kubeAPIServer = "kube-apiserver"
kubeControllerManager = "kube-controller-manager"
kubeScheduler = "kube-scheduler"
) )
// WriteStaticPodManifests builds manifest objects based on user provided configuration and then dumps it to disk // WriteStaticPodManifests builds manifest objects based on user provided configuration and then dumps it to disk
// where kubelet will pick and schedule them. // where kubelet will pick and schedule them.
func WriteStaticPodManifests(cfg *kubeadmapi.MasterConfiguration) error { func WriteStaticPodManifests(cfg *kubeadmapi.MasterConfiguration, k8sVersion *version.Version, manifestsDir string) error {
// TODO: Move the "pkg/util/version".Version object into the internal API instead of always parsing the string
k8sVersion, err := version.ParseSemantic(cfg.KubernetesVersion)
if err != nil {
return err
}
// Get the required hostpath mounts // Get the required hostpath mounts
mounts := getHostPathVolumesForTheControlPlane(cfg) mounts := getHostPathVolumesForTheControlPlane(cfg)
// Prepare static pod specs // Prepare static pod specs
staticPodSpecs := map[string]v1.Pod{ staticPodSpecs := map[string]v1.Pod{
kubeAPIServer: componentPod(v1.Container{ kubeadmconstants.KubeAPIServer: componentPod(v1.Container{
Name: kubeAPIServer, Name: kubeadmconstants.KubeAPIServer,
Image: images.GetCoreImage(images.KubeAPIServerImage, cfg, cfg.UnifiedControlPlaneImage), Image: images.GetCoreImage(kubeadmconstants.KubeAPIServer, cfg.ImageRepository, cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
Command: getAPIServerCommand(cfg, k8sVersion), Command: getAPIServerCommand(cfg, k8sVersion),
VolumeMounts: mounts.GetVolumeMounts(kubeAPIServer), VolumeMounts: mounts.GetVolumeMounts(kubeadmconstants.KubeAPIServer),
LivenessProbe: componentProbe(int(cfg.API.BindPort), "/healthz", v1.URISchemeHTTPS), LivenessProbe: componentProbe(int(cfg.API.BindPort), "/healthz", v1.URISchemeHTTPS),
Resources: componentResources("250m"), Resources: componentResources("250m"),
Env: getProxyEnvVars(), Env: getProxyEnvVars(),
}, mounts.GetVolumes(kubeAPIServer)), }, mounts.GetVolumes(kubeadmconstants.KubeAPIServer)),
kubeControllerManager: componentPod(v1.Container{ kubeadmconstants.KubeControllerManager: componentPod(v1.Container{
Name: kubeControllerManager, Name: kubeadmconstants.KubeControllerManager,
Image: images.GetCoreImage(images.KubeControllerManagerImage, cfg, cfg.UnifiedControlPlaneImage), Image: images.GetCoreImage(kubeadmconstants.KubeControllerManager, cfg.ImageRepository, cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
Command: getControllerManagerCommand(cfg, k8sVersion), Command: getControllerManagerCommand(cfg, k8sVersion),
VolumeMounts: mounts.GetVolumeMounts(kubeControllerManager), VolumeMounts: mounts.GetVolumeMounts(kubeadmconstants.KubeControllerManager),
LivenessProbe: componentProbe(10252, "/healthz", v1.URISchemeHTTP), LivenessProbe: componentProbe(10252, "/healthz", v1.URISchemeHTTP),
Resources: componentResources("200m"), Resources: componentResources("200m"),
Env: getProxyEnvVars(), Env: getProxyEnvVars(),
}, mounts.GetVolumes(kubeControllerManager)), }, mounts.GetVolumes(kubeadmconstants.KubeControllerManager)),
kubeScheduler: componentPod(v1.Container{ kubeadmconstants.KubeScheduler: componentPod(v1.Container{
Name: kubeScheduler, Name: kubeadmconstants.KubeScheduler,
Image: images.GetCoreImage(images.KubeSchedulerImage, cfg, cfg.UnifiedControlPlaneImage), Image: images.GetCoreImage(kubeadmconstants.KubeScheduler, cfg.ImageRepository, cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
Command: getSchedulerCommand(cfg), Command: getSchedulerCommand(cfg),
VolumeMounts: mounts.GetVolumeMounts(kubeScheduler), VolumeMounts: mounts.GetVolumeMounts(kubeadmconstants.KubeScheduler),
LivenessProbe: componentProbe(10251, "/healthz", v1.URISchemeHTTP), LivenessProbe: componentProbe(10251, "/healthz", v1.URISchemeHTTP),
Resources: componentResources("100m"), Resources: componentResources("100m"),
Env: getProxyEnvVars(), Env: getProxyEnvVars(),
}, mounts.GetVolumes(kubeScheduler)), }, mounts.GetVolumes(kubeadmconstants.KubeScheduler)),
} }
// Add etcd static pod spec only if external etcd is not configured // Add etcd static pod spec only if external etcd is not configured
if len(cfg.Etcd.Endpoints) == 0 { if len(cfg.Etcd.Endpoints) == 0 {
etcdPod := componentPod(v1.Container{ etcdPod := componentPod(v1.Container{
Name: etcd, Name: kubeadmconstants.Etcd,
Command: getEtcdCommand(cfg), Command: getEtcdCommand(cfg),
Image: images.GetCoreImage(images.KubeEtcdImage, cfg, cfg.Etcd.Image), Image: images.GetCoreImage(kubeadmconstants.Etcd, cfg.ImageRepository, "", cfg.Etcd.Image),
// Mount the etcd datadir path read-write so etcd can store data in a more persistent manner // Mount the etcd datadir path read-write so etcd can store data in a more persistent manner
VolumeMounts: []v1.VolumeMount{newVolumeMount(etcdVolumeName, cfg.Etcd.DataDir, false)}, VolumeMounts: []v1.VolumeMount{newVolumeMount(etcdVolumeName, cfg.Etcd.DataDir, false)},
LivenessProbe: componentProbe(2379, "/health", v1.URISchemeHTTP), LivenessProbe: componentProbe(2379, "/health", v1.URISchemeHTTP),
}, []v1.Volume{newVolume(etcdVolumeName, cfg.Etcd.DataDir)}) }, []v1.Volume{newVolume(etcdVolumeName, cfg.Etcd.DataDir)})
staticPodSpecs[etcd] = etcdPod staticPodSpecs[kubeadmconstants.Etcd] = etcdPod
} }
manifestsPath := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ManifestsSubDirName) if err := os.MkdirAll(manifestsDir, 0700); err != nil {
if err := os.MkdirAll(manifestsPath, 0700); err != nil { return fmt.Errorf("failed to create directory %q [%v]", manifestsDir, err)
return fmt.Errorf("failed to create directory %q [%v]", manifestsPath, err)
} }
for name, spec := range staticPodSpecs { for name, spec := range staticPodSpecs {
filename := filepath.Join(manifestsPath, name+".yaml") filename := kubeadmconstants.GetStaticPodFilepath(name, manifestsDir)
serialized, err := yaml.Marshal(spec) serialized, err := yaml.Marshal(spec)
if err != nil { if err != nil {
return fmt.Errorf("failed to marshal manifest for %q to YAML [%v]", name, err) return fmt.Errorf("failed to marshal manifest for %q to YAML [%v]", name, err)

View File

@ -55,21 +55,25 @@ func TestWriteStaticPodManifests(t *testing.T) {
expectedAPIProbePort int32 expectedAPIProbePort int32
}{ }{
{ {
cfg: &kubeadmapi.MasterConfiguration{}, cfg: &kubeadmapi.MasterConfiguration{
expectErr: true, KubernetesVersion: "v1.7.0",
},
expectErr: false,
}, },
{ {
cfg: &kubeadmapi.MasterConfiguration{ cfg: &kubeadmapi.MasterConfiguration{
API: kubeadmapi.API{ API: kubeadmapi.API{
BindPort: 443, BindPort: 443,
}, },
KubernetesVersion: "v1.7.0",
}, },
expectErr: true, expectErr: false,
expectedAPIProbePort: 443, expectedAPIProbePort: 443,
}, },
} }
for _, rt := range tests { for _, rt := range tests {
actual := WriteStaticPodManifests(rt.cfg)
actual := WriteStaticPodManifests(rt.cfg, version.MustParseSemantic(rt.cfg.KubernetesVersion), fmt.Sprintf("%s/etc/kubernetes/manifests", tmpdir))
if (actual == nil) && rt.expectErr { if (actual == nil) && rt.expectErr {
t.Error("expected an error from WriteStaticPodManifests but got none") t.Error("expected an error from WriteStaticPodManifests but got none")
continue continue

View File

@ -49,36 +49,36 @@ func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.MasterConfiguration) c
// HostPath volumes for the API Server // HostPath volumes for the API Server
// Read-only mount for the certificates directory // Read-only mount for the certificates directory
// TODO: Always mount the K8s Certificates directory to a static path inside of the container // TODO: Always mount the K8s Certificates directory to a static path inside of the container
mounts.NewHostPathMount(kubeAPIServer, k8sCertsVolumeName, cfg.CertificatesDir, cfg.CertificatesDir, true) mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, k8sCertsVolumeName, cfg.CertificatesDir, cfg.CertificatesDir, true)
// Read-only mount for the ca certs (/etc/ssl/certs) directory // Read-only mount for the ca certs (/etc/ssl/certs) directory
mounts.NewHostPathMount(kubeAPIServer, caCertsVolumeName, caCertsVolumePath, caCertsVolumePath, true) mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, caCertsVolumeName, caCertsVolumePath, caCertsVolumePath, true)
// If external etcd is specified, mount the directories needed for accessing the CA/serving certs and the private key // If external etcd is specified, mount the directories needed for accessing the CA/serving certs and the private key
if len(cfg.Etcd.Endpoints) != 0 { if len(cfg.Etcd.Endpoints) != 0 {
etcdVols, etcdVolMounts := getEtcdCertVolumes(cfg.Etcd) etcdVols, etcdVolMounts := getEtcdCertVolumes(cfg.Etcd)
mounts.AddHostPathMounts(kubeAPIServer, etcdVols, etcdVolMounts) mounts.AddHostPathMounts(kubeadmconstants.KubeAPIServer, etcdVols, etcdVolMounts)
} }
// HostPath volumes for the controller manager // HostPath volumes for the controller manager
// Read-only mount for the certificates directory // Read-only mount for the certificates directory
// TODO: Always mount the K8s Certificates directory to a static path inside of the container // TODO: Always mount the K8s Certificates directory to a static path inside of the container
mounts.NewHostPathMount(kubeControllerManager, k8sCertsVolumeName, cfg.CertificatesDir, cfg.CertificatesDir, true) mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, k8sCertsVolumeName, cfg.CertificatesDir, cfg.CertificatesDir, true)
// Read-only mount for the ca certs (/etc/ssl/certs) directory // Read-only mount for the ca certs (/etc/ssl/certs) directory
mounts.NewHostPathMount(kubeControllerManager, caCertsVolumeName, caCertsVolumePath, caCertsVolumePath, true) mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, caCertsVolumeName, caCertsVolumePath, caCertsVolumePath, true)
// Read-only mount for the controller manager kubeconfig file // Read-only mount for the controller manager kubeconfig file
controllerManagerKubeConfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName) controllerManagerKubeConfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName)
mounts.NewHostPathMount(kubeControllerManager, kubeConfigVolumeName, controllerManagerKubeConfigFile, controllerManagerKubeConfigFile, true) mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, kubeConfigVolumeName, controllerManagerKubeConfigFile, controllerManagerKubeConfigFile, true)
// HostPath volumes for the scheduler // HostPath volumes for the scheduler
// Read-only mount for the scheduler kubeconfig file // Read-only mount for the scheduler kubeconfig file
schedulerKubeConfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.SchedulerKubeConfigFileName) schedulerKubeConfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.SchedulerKubeConfigFileName)
mounts.NewHostPathMount(kubeScheduler, kubeConfigVolumeName, schedulerKubeConfigFile, schedulerKubeConfigFile, true) mounts.NewHostPathMount(kubeadmconstants.KubeScheduler, kubeConfigVolumeName, schedulerKubeConfigFile, schedulerKubeConfigFile, true)
// On some systems were we host-mount /etc/ssl/certs, it is also required to mount /etc/pki. This is needed // On some systems were we host-mount /etc/ssl/certs, it is also required to mount /etc/pki. This is needed
// due to symlinks pointing from files in /etc/ssl/certs into /etc/pki/ // due to symlinks pointing from files in /etc/ssl/certs into /etc/pki/
if isPkiVolumeMountNeeded() { if isPkiVolumeMountNeeded() {
mounts.NewHostPathMount(kubeAPIServer, caCertsPkiVolumeName, caCertsPkiVolumePath, caCertsPkiVolumePath, true) mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, caCertsPkiVolumeName, caCertsPkiVolumePath, caCertsPkiVolumePath, true)
mounts.NewHostPathMount(kubeControllerManager, caCertsPkiVolumeName, caCertsPkiVolumePath, caCertsPkiVolumePath, true) mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, caCertsPkiVolumeName, caCertsPkiVolumePath, caCertsPkiVolumePath, true)
} }
return mounts return mounts

View File

@ -25,6 +25,7 @@ import (
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
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"
) )
func TestNewVolume(t *testing.T) { func TestNewVolume(t *testing.T) {
@ -304,7 +305,7 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
Etcd: kubeadmapi.Etcd{}, Etcd: kubeadmapi.Etcd{},
}, },
vol: map[string][]v1.Volume{ vol: map[string][]v1.Volume{
kubeAPIServer: { kubeadmconstants.KubeAPIServer: {
{ {
Name: "k8s-certs", Name: "k8s-certs",
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
@ -318,7 +319,7 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
}, },
}, },
}, },
kubeControllerManager: { kubeadmconstants.KubeControllerManager: {
{ {
Name: "k8s-certs", Name: "k8s-certs",
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
@ -338,7 +339,7 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
}, },
}, },
}, },
kubeScheduler: { kubeadmconstants.KubeScheduler: {
{ {
Name: "kubeconfig", Name: "kubeconfig",
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
@ -348,7 +349,7 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
}, },
}, },
volMount: map[string][]v1.VolumeMount{ volMount: map[string][]v1.VolumeMount{
kubeAPIServer: { kubeadmconstants.KubeAPIServer: {
{ {
Name: "k8s-certs", Name: "k8s-certs",
MountPath: testCertsDir, MountPath: testCertsDir,
@ -360,7 +361,7 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
ReadOnly: true, ReadOnly: true,
}, },
}, },
kubeControllerManager: { kubeadmconstants.KubeControllerManager: {
{ {
Name: "k8s-certs", Name: "k8s-certs",
MountPath: testCertsDir, MountPath: testCertsDir,
@ -377,7 +378,7 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
ReadOnly: true, ReadOnly: true,
}, },
}, },
kubeScheduler: { kubeadmconstants.KubeScheduler: {
{ {
Name: "kubeconfig", Name: "kubeconfig",
MountPath: "/etc/kubernetes/scheduler.conf", MountPath: "/etc/kubernetes/scheduler.conf",
@ -398,7 +399,7 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
}, },
}, },
vol: map[string][]v1.Volume{ vol: map[string][]v1.Volume{
kubeAPIServer: { kubeadmconstants.KubeAPIServer: {
{ {
Name: "k8s-certs", Name: "k8s-certs",
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
@ -424,7 +425,7 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
}, },
}, },
}, },
kubeControllerManager: { kubeadmconstants.KubeControllerManager: {
{ {
Name: "k8s-certs", Name: "k8s-certs",
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
@ -444,7 +445,7 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
}, },
}, },
}, },
kubeScheduler: { kubeadmconstants.KubeScheduler: {
{ {
Name: "kubeconfig", Name: "kubeconfig",
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
@ -454,7 +455,7 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
}, },
}, },
volMount: map[string][]v1.VolumeMount{ volMount: map[string][]v1.VolumeMount{
kubeAPIServer: { kubeadmconstants.KubeAPIServer: {
{ {
Name: "k8s-certs", Name: "k8s-certs",
MountPath: testCertsDir, MountPath: testCertsDir,
@ -476,7 +477,7 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
ReadOnly: true, ReadOnly: true,
}, },
}, },
kubeControllerManager: { kubeadmconstants.KubeControllerManager: {
{ {
Name: "k8s-certs", Name: "k8s-certs",
MountPath: testCertsDir, MountPath: testCertsDir,
@ -493,7 +494,7 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
ReadOnly: true, ReadOnly: true,
}, },
}, },
kubeScheduler: { kubeadmconstants.KubeScheduler: {
{ {
Name: "kubeconfig", Name: "kubeconfig",
MountPath: "/etc/kubernetes/scheduler.conf", MountPath: "/etc/kubernetes/scheduler.conf",

View File

@ -25,19 +25,19 @@ import (
// mutatePodSpec makes a Static Pod-hosted PodSpec suitable for self-hosting // mutatePodSpec makes a Static Pod-hosted PodSpec suitable for self-hosting
func mutatePodSpec(cfg *kubeadmapi.MasterConfiguration, name string, podSpec *v1.PodSpec) { func mutatePodSpec(cfg *kubeadmapi.MasterConfiguration, name string, podSpec *v1.PodSpec) {
mutators := map[string][]func(*kubeadmapi.MasterConfiguration, *v1.PodSpec){ mutators := map[string][]func(*kubeadmapi.MasterConfiguration, *v1.PodSpec){
kubeAPIServer: { kubeadmconstants.KubeAPIServer: {
addNodeSelectorToPodSpec, addNodeSelectorToPodSpec,
setMasterTolerationOnPodSpec, setMasterTolerationOnPodSpec,
setRightDNSPolicyOnPodSpec, setRightDNSPolicyOnPodSpec,
setVolumesOnKubeAPIServerPodSpec, setVolumesOnKubeAPIServerPodSpec,
}, },
kubeControllerManager: { kubeadmconstants.KubeControllerManager: {
addNodeSelectorToPodSpec, addNodeSelectorToPodSpec,
setMasterTolerationOnPodSpec, setMasterTolerationOnPodSpec,
setRightDNSPolicyOnPodSpec, setRightDNSPolicyOnPodSpec,
setVolumesOnKubeControllerManagerPodSpec, setVolumesOnKubeControllerManagerPodSpec,
}, },
kubeScheduler: { kubeadmconstants.KubeScheduler: {
addNodeSelectorToPodSpec, addNodeSelectorToPodSpec,
setMasterTolerationOnPodSpec, setMasterTolerationOnPodSpec,
setRightDNSPolicyOnPodSpec, setRightDNSPolicyOnPodSpec,

View File

@ -32,7 +32,7 @@ func TestMutatePodSpec(t *testing.T) {
expected v1.PodSpec expected v1.PodSpec
}{ }{
{ {
component: kubeAPIServer, component: kubeadmconstants.KubeAPIServer,
podSpec: &v1.PodSpec{}, podSpec: &v1.PodSpec{},
expected: v1.PodSpec{ expected: v1.PodSpec{
NodeSelector: map[string]string{ NodeSelector: map[string]string{
@ -45,7 +45,7 @@ func TestMutatePodSpec(t *testing.T) {
}, },
}, },
{ {
component: kubeControllerManager, component: kubeadmconstants.KubeControllerManager,
podSpec: &v1.PodSpec{}, podSpec: &v1.PodSpec{},
expected: v1.PodSpec{ expected: v1.PodSpec{
NodeSelector: map[string]string{ NodeSelector: map[string]string{
@ -58,7 +58,7 @@ func TestMutatePodSpec(t *testing.T) {
}, },
}, },
{ {
component: kubeScheduler, component: kubeadmconstants.KubeScheduler,
podSpec: &v1.PodSpec{}, podSpec: &v1.PodSpec{},
expected: v1.PodSpec{ expected: v1.PodSpec{
NodeSelector: map[string]string{ NodeSelector: map[string]string{

View File

@ -20,7 +20,6 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath"
"time" "time"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
@ -35,14 +34,6 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
) )
const (
kubeAPIServer = "kube-apiserver"
kubeControllerManager = "kube-controller-manager"
kubeScheduler = "kube-scheduler"
selfHostingPrefix = "self-hosted-"
)
// CreateSelfHostedControlPlane is responsible for turning a Static Pod-hosted control plane to a self-hosted one // CreateSelfHostedControlPlane is responsible for turning a Static Pod-hosted control plane to a self-hosted one
// It achieves that task this way: // It achieves that task this way:
// 1. Load the Static Pod specification from disk (from /etc/kubernetes/manifests) // 1. Load the Static Pod specification from disk (from /etc/kubernetes/manifests)
@ -64,12 +55,9 @@ func CreateSelfHostedControlPlane(cfg *kubeadmapi.MasterConfiguration, client cl
return err return err
} }
// The sequence here isn't set in stone, but seems to work well to start with the API server for _, componentName := range kubeadmconstants.MasterComponents {
components := []string{kubeAPIServer, kubeControllerManager, kubeScheduler}
for _, componentName := range components {
start := time.Now() start := time.Now()
manifestPath := buildStaticManifestFilepath(componentName) manifestPath := kubeadmconstants.GetStaticPodFilepath(componentName, kubeadmconstants.GetStaticPodDirectory())
// Load the Static Pod file in order to be able to create a self-hosted variant of that file // Load the Static Pod file in order to be able to create a self-hosted variant of that file
podSpec, err := loadPodSpecFromFile(manifestPath) podSpec, err := loadPodSpecFromFile(manifestPath)
@ -116,17 +104,17 @@ func buildDaemonSet(cfg *kubeadmapi.MasterConfiguration, name string, podSpec *v
// Return a DaemonSet based on that Spec // Return a DaemonSet based on that Spec
return &extensions.DaemonSet{ return &extensions.DaemonSet{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: addSelfHostedPrefix(name), Name: kubeadmconstants.AddSelfHostedPrefix(name),
Namespace: metav1.NamespaceSystem, Namespace: metav1.NamespaceSystem,
Labels: map[string]string{ Labels: map[string]string{
"k8s-app": addSelfHostedPrefix(name), "k8s-app": kubeadmconstants.AddSelfHostedPrefix(name),
}, },
}, },
Spec: extensions.DaemonSetSpec{ Spec: extensions.DaemonSetSpec{
Template: v1.PodTemplateSpec{ Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{ Labels: map[string]string{
"k8s-app": addSelfHostedPrefix(name), "k8s-app": kubeadmconstants.AddSelfHostedPrefix(name),
}, },
}, },
Spec: *podSpec, Spec: *podSpec,
@ -151,17 +139,7 @@ func loadPodSpecFromFile(manifestPath string) (*v1.PodSpec, error) {
return &staticPod.Spec, nil return &staticPod.Spec, nil
} }
// buildStaticManifestFilepath returns the location on the disk where the Static Pod should be present
func buildStaticManifestFilepath(componentName string) string {
return filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ManifestsSubDirName, componentName+".yaml")
}
// buildSelfHostedWorkloadLabelQuery creates the right query for matching a self-hosted Pod // buildSelfHostedWorkloadLabelQuery creates the right query for matching a self-hosted Pod
func buildSelfHostedWorkloadLabelQuery(componentName string) string { func buildSelfHostedWorkloadLabelQuery(componentName string) string {
return fmt.Sprintf("k8s-app=%s", addSelfHostedPrefix(componentName)) return fmt.Sprintf("k8s-app=%s", kubeadmconstants.AddSelfHostedPrefix(componentName))
}
// addSelfHostedPrefix adds the self-hosted- prefix to the component name
func addSelfHostedPrefix(componentName string) string {
return fmt.Sprintf("%s%s", selfHostingPrefix, componentName)
} }

View File

@ -25,6 +25,7 @@ import (
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
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"
) )
const ( const (
@ -543,17 +544,17 @@ func TestBuildDaemonSet(t *testing.T) {
dsBytes []byte dsBytes []byte
}{ }{
{ {
component: kubeAPIServer, component: kubeadmconstants.KubeAPIServer,
podBytes: []byte(testAPIServerPod), podBytes: []byte(testAPIServerPod),
dsBytes: []byte(testAPIServerDaemonSet), dsBytes: []byte(testAPIServerDaemonSet),
}, },
{ {
component: kubeControllerManager, component: kubeadmconstants.KubeControllerManager,
podBytes: []byte(testControllerManagerPod), podBytes: []byte(testControllerManagerPod),
dsBytes: []byte(testControllerManagerDaemonSet), dsBytes: []byte(testControllerManagerDaemonSet),
}, },
{ {
component: kubeScheduler, component: kubeadmconstants.KubeScheduler,
podBytes: []byte(testSchedulerPod), podBytes: []byte(testSchedulerPod),
dsBytes: []byte(testSchedulerDaemonSet), dsBytes: []byte(testSchedulerDaemonSet),
}, },