mirror of https://github.com/k3s-io/k3s
Add support for external and optionally secured etcd cluster.
parent
26aa32d32b
commit
389cb2c7cd
|
@ -40,6 +40,12 @@ type InitFlags struct {
|
||||||
API struct {
|
API struct {
|
||||||
AdvertiseAddrs []net.IP
|
AdvertiseAddrs []net.IP
|
||||||
ExternalDNSNames []string
|
ExternalDNSNames []string
|
||||||
|
Etcd struct {
|
||||||
|
ExternalEndpoints []string
|
||||||
|
ExternalCAFile string
|
||||||
|
ExternalCertFile string
|
||||||
|
ExternalKeyFile string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Services struct {
|
Services struct {
|
||||||
CIDR net.IPNet
|
CIDR net.IPNet
|
||||||
|
|
|
@ -83,6 +83,25 @@ func NewCmdInit(out io.Writer, s *kubeadmapi.KubeadmConfig) *cobra.Command {
|
||||||
`(optional) allow to schedule workload to the node`,
|
`(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
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/api"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/api"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
"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
|
// 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(s *kubeadmapi.KubeadmConfig) error {
|
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{
|
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{
|
kubeAPIServer: componentPod(api.Container{
|
||||||
Name: kubeAPIServer,
|
Name: kubeAPIServer,
|
||||||
Image: images.GetCoreImage(images.KubeAPIServerImage, s.EnvParams["hyperkube_image"]),
|
Image: images.GetCoreImage(images.KubeAPIServerImage, s.EnvParams["hyperkube_image"]),
|
||||||
Command: getComponentCommand(apiServer, s),
|
Command: apiServerCommand,
|
||||||
VolumeMounts: []api.VolumeMount{k8sVolumeMount()},
|
VolumeMounts: []api.VolumeMount{certsVolumeMount(), k8sVolumeMount()},
|
||||||
LivenessProbe: componentProbe(8080, "/healthz"),
|
LivenessProbe: componentProbe(8080, "/healthz"),
|
||||||
Resources: componentResources("250m"),
|
Resources: componentResources("250m"),
|
||||||
}, k8sVolume(s)),
|
}, certsVolume(s), k8sVolume(s)),
|
||||||
kubeControllerManager: componentPod(api.Container{
|
kubeControllerManager: componentPod(api.Container{
|
||||||
Name: kubeControllerManager,
|
Name: kubeControllerManager,
|
||||||
Image: images.GetCoreImage(images.KubeControllerManagerImage, s.EnvParams["hyperkube_image"]),
|
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")
|
manifestsPath := path.Join(s.EnvParams["kubernetes_dir"], "manifests")
|
||||||
if err := os.MkdirAll(manifestsPath, 0700); err != nil {
|
if err := os.MkdirAll(manifestsPath, 0700); err != nil {
|
||||||
return fmt.Errorf("<master/manifests> failed to create directory %q [%s]", manifestsPath, err)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// etcdVolume returns an host-path volume for storing etcd data.
|
// etcdVolume exposes a path on the host in order to guarantee data survival during reboot.
|
||||||
// By using a host-path, the data will survive pod restart.
|
|
||||||
func etcdVolume(s *kubeadmapi.KubeadmConfig) api.Volume {
|
func etcdVolume(s *kubeadmapi.KubeadmConfig) api.Volume {
|
||||||
return api.Volume{
|
return api.Volume{
|
||||||
Name: "etcd",
|
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 {
|
func k8sVolume(s *kubeadmapi.KubeadmConfig) api.Volume {
|
||||||
return api.Volume{
|
return api.Volume{
|
||||||
Name: "pki",
|
Name: "pki",
|
||||||
|
|
Loading…
Reference in New Issue