Add support for external and optionally secured etcd cluster.

pull/6/head
Paulo Pires 2016-09-20 11:37:02 +01:00 committed by Ilya Dmitrichenko
parent 26aa32d32b
commit 389cb2c7cd
No known key found for this signature in database
GPG Key ID: E7889175A6C0CEB9
3 changed files with 88 additions and 20 deletions

View File

@ -40,6 +40,12 @@ type InitFlags struct {
API struct {
AdvertiseAddrs []net.IP
ExternalDNSNames []string
Etcd struct {
ExternalEndpoints []string
ExternalCAFile string
ExternalCertFile string
ExternalKeyFile string
}
}
Services struct {
CIDR net.IPNet

View File

@ -83,6 +83,25 @@ func NewCmdInit(out io.Writer, s *kubeadmapi.KubeadmConfig) *cobra.Command {
`(optional) allow to schedule workload to the node`,
)
// TODO (phase1+) @errordeveloper make the flags below not show up in --help but rather on --advanced-help
cmd.PersistentFlags().StringSliceVar(
&s.InitFlags.API.Etcd.ExternalEndpoints, "external-etcd-endpoints", []string{},
`(optional) etcd endpoints to use, in case you have an external cluster.`,
)
cmd.PersistentFlags().StringVar(
&s.InitFlags.API.Etcd.ExternalCAFile, "external-etcd-cafile", "",
`(optional) etcd certificate authority certificate file."`,
)
cmd.PersistentFlags().StringVar(
&s.InitFlags.API.Etcd.ExternalCertFile, "external-etcd-certfile", "",
`(optional) etcd client certificate file."`,
)
cmd.PersistentFlags().StringVar(
&s.InitFlags.API.Etcd.ExternalKeyFile, "external-etcd-keyfile", "",
`(optional) etcd client key file."`,
)
return cmd
}

View File

@ -22,6 +22,7 @@ import (
"fmt"
"os"
"path"
"strings"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/api"
"k8s.io/kubernetes/cmd/kubeadm/app/images"
@ -57,30 +58,38 @@ const (
// WriteStaticPodManifests builds manifest objects based on user provided configuration and then dumps it to disk
// where kubelet will pick and schedule them.
func WriteStaticPodManifests(s *kubeadmapi.KubeadmConfig) error {
// Placeholder for kube-apiserver pod spec command
apiServerCommand := getComponentCommand(apiServer, s)
// Check if the user decided to use an external etcd cluster
if len(s.InitFlags.API.Etcd.ExternalEndpoints) > 0 {
arg := fmt.Sprintf("--etcd-servers=%s", strings.Join(s.InitFlags.API.Etcd.ExternalEndpoints, ","))
apiServerCommand = append(apiServerCommand, arg)
} else {
apiServerCommand = append(apiServerCommand, "--etcd-servers=http://127.0.0.1:2379")
}
// Is etcd secured?
if s.InitFlags.API.Etcd.ExternalCAFile != "" {
etcdCAFileArg := fmt.Sprintf("--etcd-cafile=%s", s.InitFlags.API.Etcd.ExternalCAFile)
apiServerCommand = append(apiServerCommand, etcdCAFileArg)
}
if s.InitFlags.API.Etcd.ExternalCertFile != "" && s.InitFlags.API.Etcd.ExternalKeyFile != "" {
etcdClientFileArg := fmt.Sprintf("--etcd-certfile=%s", s.InitFlags.API.Etcd.ExternalCertFile)
etcdKeyFileArg := fmt.Sprintf("--etcd-keyfile=%s", s.InitFlags.API.Etcd.ExternalKeyFile)
apiServerCommand = append(apiServerCommand, etcdClientFileArg, etcdKeyFileArg)
}
// Prepare static pod specs
staticPodSpecs := map[string]api.Pod{
// TODO this needs a volume
etcd: componentPod(api.Container{
Command: []string{
"/usr/local/bin/etcd",
"--listen-client-urls=http://127.0.0.1:2379",
"--advertise-client-urls=http://127.0.0.1:2379",
"--data-dir=/var/etcd/data",
},
VolumeMounts: []api.VolumeMount{etcdVolumeMount()},
Image: images.GetCoreImage(images.KubeEtcdImage, s.EnvParams["etcd_image"]),
LivenessProbe: componentProbe(2379, "/health"),
Name: etcd,
Resources: componentResources("200m"),
}, etcdVolume(s)),
// TODO bind-mount certs in
kubeAPIServer: componentPod(api.Container{
Name: kubeAPIServer,
Image: images.GetCoreImage(images.KubeAPIServerImage, s.EnvParams["hyperkube_image"]),
Command: getComponentCommand(apiServer, s),
VolumeMounts: []api.VolumeMount{k8sVolumeMount()},
Command: apiServerCommand,
VolumeMounts: []api.VolumeMount{certsVolumeMount(), k8sVolumeMount()},
LivenessProbe: componentProbe(8080, "/healthz"),
Resources: componentResources("250m"),
}, k8sVolume(s)),
}, certsVolume(s), k8sVolume(s)),
kubeControllerManager: componentPod(api.Container{
Name: kubeControllerManager,
Image: images.GetCoreImage(images.KubeControllerManagerImage, s.EnvParams["hyperkube_image"]),
@ -98,6 +107,23 @@ func WriteStaticPodManifests(s *kubeadmapi.KubeadmConfig) error {
}),
}
// Add etcd static pod spec only if external etcd is not configured
if len(s.InitFlags.API.Etcd.ExternalEndpoints) == 0 {
staticPodSpecs[etcd] = componentPod(api.Container{
Name: etcd,
Command: []string{
"etcd",
"--listen-client-urls=http://127.0.0.1:2379",
"--advertise-client-urls=http://127.0.0.1:2379",
"--data-dir=/var/etcd/data",
},
VolumeMounts: []api.VolumeMount{certsVolumeMount(), etcdVolumeMount(), k8sVolumeMount()},
Image: images.GetCoreImage(images.KubeEtcdImage, s.EnvParams["etcd_image"]),
LivenessProbe: componentProbe(2379, "/health"),
Resources: componentResources("200m"),
}, certsVolume(s), etcdVolume(s), k8sVolume(s))
}
manifestsPath := path.Join(s.EnvParams["kubernetes_dir"], "manifests")
if err := os.MkdirAll(manifestsPath, 0700); err != nil {
return fmt.Errorf("<master/manifests> failed to create directory %q [%s]", manifestsPath, err)
@ -115,8 +141,7 @@ func WriteStaticPodManifests(s *kubeadmapi.KubeadmConfig) error {
return nil
}
// etcdVolume returns an host-path volume for storing etcd data.
// By using a host-path, the data will survive pod restart.
// etcdVolume exposes a path on the host in order to guarantee data survival during reboot.
func etcdVolume(s *kubeadmapi.KubeadmConfig) api.Volume {
return api.Volume{
Name: "etcd",
@ -133,6 +158,24 @@ func etcdVolumeMount() api.VolumeMount {
}
}
// certsVolume exposes host SSL certificates to pod containers.
func certsVolume(s *kubeadmapi.KubeadmConfig) api.Volume {
return api.Volume{
Name: "certs",
VolumeSource: api.VolumeSource{
// TODO make path configurable
HostPath: &api.HostPathVolumeSource{Path: "/etc/ssl/certs"},
},
}
}
func certsVolumeMount() api.VolumeMount {
return api.VolumeMount{
Name: "certs",
MountPath: "/etc/ssl/certs",
}
}
func k8sVolume(s *kubeadmapi.KubeadmConfig) api.Volume {
return api.Volume{
Name: "pki",