diff --git a/cmd/kubeadm/app/kubeadm.go b/cmd/kubeadm/app/kubeadm.go index b7249e995b..749948d5c3 100644 --- a/cmd/kubeadm/app/kubeadm.go +++ b/cmd/kubeadm/app/kubeadm.go @@ -20,7 +20,6 @@ import ( "fmt" "os" "path" - "runtime" "strings" "github.com/spf13/pflag" @@ -43,12 +42,11 @@ func getEnvParams() map[string]string { envParams := map[string]string{ "prefix": globalPrefix, "host_pki_path": path.Join(globalPrefix, "pki"), - "hyperkube_image": fmt.Sprintf("gcr.io/google_containers/hyperkube-%s:%s", runtime.GOARCH, "v1.4.0-alpha.3"), - "discovery_image": "dgoodwin/kubediscovery:latest", - "etcd_image": fmt.Sprintf("gcr.io/google_containers/etcd-%s:%s", runtime.GOARCH, "2.2.5"), + "hyperkube_image": "", + "discovery_image": "dgoodwin/kubediscovery:latest", // TODO(phase1): fmt.Sprintf("gcr.io/google_containers/kube-discovery-%s:%s", runtime.GOARCH, "1.0"), + "etcd_image": "", "component_loglevel": "--v=4", "dns_domain": "cluster.local", - "dns_replicas": "1", } for k := range envParams { @@ -65,6 +63,10 @@ func Run() error { logs.InitLogs() defer logs.FlushLogs() + // We do not want these flags to show up in --help + pflag.CommandLine.MarkHidden("google-json-key") + pflag.CommandLine.MarkHidden("log-flush-frequency") + cmd := cmd.NewKubeadmCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr, getEnvParams()) return cmd.Execute() } diff --git a/cmd/kubeadm/kubeadm.go b/cmd/kubeadm/kubeadm.go index 6aca5a18f3..f61297fc8f 100644 --- a/cmd/kubeadm/kubeadm.go +++ b/cmd/kubeadm/kubeadm.go @@ -22,6 +22,7 @@ import ( "k8s.io/kubernetes/cmd/kubeadm/app" ) +// TODO(phase1): check for root func main() { if err := app.Run(); err != nil { os.Exit(1) diff --git a/pkg/kubeadm/api/types.go b/pkg/kubeadm/api/types.go index 087a2d315d..dab8765e87 100644 --- a/pkg/kubeadm/api/types.go +++ b/pkg/kubeadm/api/types.go @@ -14,7 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubeadmapi +package api + +import ( + "net" +) type BootstrapParams struct { // TODO this is mostly out of date and bloated now, let's revisit this soon @@ -32,7 +36,8 @@ type OutOfBandDiscovery struct { BearerToken string // set based on Token // 'init-master' side ApiServerDNSName string // optional, used in master bootstrap - ListenIP string // optional IP for master to listen on, rather than autodetect + ListenIP net.IP // optional IP for master to listen on, rather than autodetect + UseHyperkubeImage bool } type ClusterInfo struct { diff --git a/pkg/kubeadm/cmd/init.go b/pkg/kubeadm/cmd/init.go index abfc4647ab..56422cf643 100644 --- a/pkg/kubeadm/cmd/init.go +++ b/pkg/kubeadm/cmd/init.go @@ -42,7 +42,7 @@ var ( func NewCmdInit(out io.Writer, params *kubeadmapi.BootstrapParams) *cobra.Command { cmd := &cobra.Command{ - Use: "init --token [--listen-ip ]", + Use: "init", Short: "Run this on the first server you deploy onto.", Run: func(cmd *cobra.Command, args []string) { err := RunInit(out, cmd, args, params) @@ -50,21 +50,25 @@ func NewCmdInit(out io.Writer, params *kubeadmapi.BootstrapParams) *cobra.Comman }, } - cmd.PersistentFlags().StringVarP(¶ms.Discovery.ListenIP, "listen-ip", "", "", + cmd.PersistentFlags().IPVar(¶ms.Discovery.ListenIP, "listen-ip", nil, `(optional) IP address to listen on, in case autodetection fails.`) - cmd.PersistentFlags().StringVarP(¶ms.Discovery.GivenToken, "token", "", "", + cmd.PersistentFlags().StringVar(¶ms.Discovery.GivenToken, "token", "", `(optional) Shared secret used to secure bootstrap. Will be generated and displayed if not provided.`) + cmd.PersistentFlags().BoolVar(¶ms.Discovery.UseHyperkubeImage, "use-hyperkube", false, + `(optional) Use the hyperkube image for running the apiserver, controller-manager, scheduler and proxy.`) return cmd } func RunInit(out io.Writer, cmd *cobra.Command, args []string, params *kubeadmapi.BootstrapParams) error { - if params.Discovery.ListenIP == "" { + + // Auto-detect the IP + if params.Discovery.ListenIP == nil { ip, err := netutil.ChooseHostInterface() if err != nil { return err } - params.Discovery.ListenIP = ip.String() + params.Discovery.ListenIP = ip } if err := kubemaster.CreateTokenAuthFile(params); err != nil { return err diff --git a/pkg/kubeadm/cmd/manual.go b/pkg/kubeadm/cmd/manual.go index 491ab06b25..49a611ced1 100644 --- a/pkg/kubeadm/cmd/manual.go +++ b/pkg/kubeadm/cmd/manual.go @@ -107,25 +107,27 @@ func NewCmdManualBootstrapInitMaster(out io.Writer, params *kubeadmapi.Bootstrap } params.Discovery.ApiServerURLs = "http://127.0.0.1:8080/" // On the master, assume you can talk to the API server - cmd.PersistentFlags().StringVarP(¶ms.Discovery.ApiServerDNSName, "api-dns-name", "", "", + cmd.PersistentFlags().StringVar(¶ms.Discovery.ApiServerDNSName, "api-dns-name", "", `(optional) DNS name for the API server, will be encoded into subjectAltName in the resulting (generated) TLS certificates`) - cmd.PersistentFlags().StringVarP(¶ms.Discovery.ListenIP, "listen-ip", "", "", + cmd.PersistentFlags().IPVar(¶ms.Discovery.ListenIP, "listen-ip", nil, `(optional) IP address to listen on, in case autodetection fails.`) - cmd.PersistentFlags().StringVarP(¶ms.Discovery.BearerToken, "token", "", "", + cmd.PersistentFlags().StringVar(¶ms.Discovery.BearerToken, "token", "", `(optional) Shared secret used to secure bootstrap. Will be generated and displayed if not provided.`) return cmd } func RunManualBootstrapInitMaster(out io.Writer, cmd *cobra.Command, args []string, params *kubeadmapi.BootstrapParams) error { - if params.Discovery.ListenIP == "" { + // Auto-detect the IP + if params.Discovery.ListenIP == nil { ip, err := netutil.ChooseHostInterface() if err != nil { - return fmt.Errorf(" unable to autodetect IP address [%s], please specify with --listen-ip", err) + return err } - params.Discovery.ListenIP = ip.String() + params.Discovery.ListenIP = ip } + if err := kubemaster.CreateTokenAuthFile(params); err != nil { return err } diff --git a/pkg/kubeadm/images/images.go b/pkg/kubeadm/images/images.go new file mode 100644 index 0000000000..27f3fb03a6 --- /dev/null +++ b/pkg/kubeadm/images/images.go @@ -0,0 +1,76 @@ +/* +Copyright 2016 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 images + +import ( + "fmt" + "runtime" +) + +const ( + KubeEtcdImage = "etcd" + + KubeApiServerImage = "apiserver" + KubeControllerManagerImage = "controller-manager" + KubeSchedulerImage = "scheduler" + KubeProxyImage = "proxy" + + KubeDnsImage = "kube-dns" + KubeDnsmasqImage = "dnsmasq" + KubeExechealthzImage = "exechealthz" + + + gcrPrefix = "gcr.io/google_containers" + etcdVersion = "2.2.5" + kubeVersion = "v1.4.0-alpha.3" + + kubeDnsVersion = "1.7" + dnsmasqVersion = "1.3" + exechealthzVersion = "1.1" +) + +func GetCoreImage(image string, overrideImage string, useHyperkube bool) string { + if overrideImage != "" { + return overrideImage + } + + if useHyperkube { + return map[string]string{ + KubeEtcdImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "etcd", runtime.GOARCH, etcdVersion), + KubeApiServerImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "hyperkube", runtime.GOARCH, kubeVersion), + KubeControllerManagerImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "hyperkube", runtime.GOARCH, kubeVersion), + KubeSchedulerImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "hyperkube", runtime.GOARCH, kubeVersion), + KubeProxyImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "hyperkube", runtime.GOARCH, kubeVersion), + }[image] + } + + return map[string]string{ + KubeEtcdImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "etcd", runtime.GOARCH, etcdVersion), + KubeApiServerImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-apiserver", runtime.GOARCH, kubeVersion), + KubeControllerManagerImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-controller-manager", runtime.GOARCH, kubeVersion), + KubeSchedulerImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-scheduler", runtime.GOARCH, kubeVersion), + KubeProxyImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-proxy", runtime.GOARCH, kubeVersion), + }[image] +} + +func GetAddonImage(image string) string { + return map[string]string{ + KubeDnsImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-dns", runtime.GOARCH, kubeDnsVersion), + KubeDnsmasqImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-dnsmasq", runtime.GOARCH, dnsmasqVersion), + KubeExechealthzImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "exechealthz", runtime.GOARCH, exechealthzVersion), + }[image] +} diff --git a/pkg/kubeadm/master/addons.go b/pkg/kubeadm/master/addons.go index a37ba373d4..add2674d3f 100644 --- a/pkg/kubeadm/master/addons.go +++ b/pkg/kubeadm/master/addons.go @@ -14,18 +14,17 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubemaster +package master import ( "fmt" "path" - "runtime" - "strconv" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/resource" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" kubeadmapi "k8s.io/kubernetes/pkg/kubeadm/api" + "k8s.io/kubernetes/pkg/kubeadm/images" "k8s.io/kubernetes/pkg/util/intstr" ) @@ -35,13 +34,11 @@ func createKubeProxyPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec { SecurityContext: &api.PodSecurityContext{HostNetwork: true}, Containers: []api.Container{{ Name: "kube-proxy", - Image: params.EnvParams["hyperkube_image"], - Command: []string{ - "/hyperkube", - "proxy", + Image: images.GetCoreImage(images.KubeProxyImage, params.EnvParams["hyperkube_image"], params.Discovery.UseHyperkubeImage), + Command: append(getImageEntrypoint("proxy", params.Discovery.UseHyperkubeImage), []string{ "--kubeconfig=/run/kubeconfig", params.EnvParams["component_loglevel"], - }, + }...), SecurityContext: &api.SecurityContext{Privileged: &privilegedTrue}, VolumeMounts: []api.VolumeMount{ { @@ -83,6 +80,7 @@ func createKubeProxyPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec { } } +// TODO(phase1): Create the DNS service as well func createKubeDNSPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec { dnsPodResources := api.ResourceList{ @@ -100,7 +98,7 @@ func createKubeDNSPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec { // DNS server { Name: "kube-dns", - Image: "gcr.io/google_containers/kubedns-" + runtime.GOARCH + ":1.7", + Image: images.GetAddonImage(images.KubeDnsImage), Resources: api.ResourceRequirements{ Limits: dnsPodResources, Requests: dnsPodResources, @@ -152,7 +150,7 @@ func createKubeDNSPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec { // dnsmasq { Name: "dnsmasq", - Image: "gcr.io/google_containers/kube-dnsmasq-" + runtime.GOARCH + ":1.3", + Image: images.GetAddonImage(images.KubeDnsmasqImage), Resources: api.ResourceRequirements{ Limits: dnsPodResources, Requests: dnsPodResources, @@ -178,7 +176,7 @@ func createKubeDNSPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec { // healthz { Name: "healthz", - Image: "gcr.io/google_containers/exechealthz-" + runtime.GOARCH + ":1.1", + Image: images.GetAddonImage(images.KubeExechealthzImage), Resources: api.ResourceRequirements{ Limits: healthzPodResources, Requests: healthzPodResources, @@ -219,14 +217,7 @@ func CreateEssentialAddons(params *kubeadmapi.BootstrapParams, client *clientset fmt.Println(" created essential addon: kube-proxy") - // TODO should we wait for it to become ready at least on the master? - - dnsReplicas, err := strconv.Atoi(params.EnvParams["dns_replicas"]) - if err != nil { - dnsReplicas = 1 - } - - kubeDNSDeployment := NewDeployment("kube-dns", int32(dnsReplicas), createKubeDNSPodSpec(params)) + kubeDNSDeployment := NewDeployment("kube-dns", 1, createKubeDNSPodSpec(params)) SetMasterTaintTolerations(&kubeDNSDeployment.Spec.Template.ObjectMeta) if _, err := client.Extensions().Deployments(api.NamespaceSystem).Create(kubeDNSDeployment); err != nil { diff --git a/pkg/kubeadm/master/apiclient.go b/pkg/kubeadm/master/apiclient.go index b2e22c895e..97654cbab5 100644 --- a/pkg/kubeadm/master/apiclient.go +++ b/pkg/kubeadm/master/apiclient.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubemaster +package master import ( "encoding/json" diff --git a/pkg/kubeadm/master/discovery.go b/pkg/kubeadm/master/discovery.go index 51fc65bde8..15ae71e996 100644 --- a/pkg/kubeadm/master/discovery.go +++ b/pkg/kubeadm/master/discovery.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubemaster +package master import ( "crypto/x509" diff --git a/pkg/kubeadm/master/kubeconfig.go b/pkg/kubeadm/master/kubeconfig.go index 9cd9506310..ea76c3849b 100644 --- a/pkg/kubeadm/master/kubeconfig.go +++ b/pkg/kubeadm/master/kubeconfig.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubemaster +package master import ( "crypto/rsa" diff --git a/pkg/kubeadm/master/manifests.go b/pkg/kubeadm/master/manifests.go index b104889655..385813dffe 100644 --- a/pkg/kubeadm/master/manifests.go +++ b/pkg/kubeadm/master/manifests.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubemaster +package master import ( "bytes" @@ -27,6 +27,7 @@ import ( "k8s.io/kubernetes/pkg/api/unversioned" api "k8s.io/kubernetes/pkg/api/v1" kubeadmapi "k8s.io/kubernetes/pkg/kubeadm/api" + "k8s.io/kubernetes/pkg/kubeadm/images" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/util/intstr" ) @@ -50,11 +51,11 @@ func WriteStaticPodManifests(params *kubeadmapi.BootstrapParams) error { "etcd": componentPod(api.Container{ Command: []string{ "/usr/local/bin/etcd", - "--listen-client-urls=http://127.0.0.1:2379,http://127.0.0.1:4001", - "--advertise-client-urls=http://127.0.0.1:2379,http://127.0.0.1:4001", + "--listen-client-urls=http://127.0.0.1:2379", + "--advertise-client-urls=http://127.0.0.1:2379", "--data-dir=/var/etcd/data", }, - Image: params.EnvParams["etcd_image"], + Image: images.GetCoreImage(images.KubeEtcdImage, params.EnvParams["etcd_image"], params.Discovery.UseHyperkubeImage), LivenessProbe: componentProbe(2379, "/health"), Name: "etcd-server", Resources: componentResources("200m"), @@ -62,10 +63,8 @@ func WriteStaticPodManifests(params *kubeadmapi.BootstrapParams) error { // TODO bind-mount certs in "kube-apiserver": componentPod(api.Container{ Name: "kube-apiserver", - Image: params.EnvParams["hyperkube_image"], - Command: []string{ - "/hyperkube", - "apiserver", + Image: images.GetCoreImage(images.KubeApiServerImage, params.EnvParams["hyperkube_image"], params.Discovery.UseHyperkubeImage), + Command: append(getImageEntrypoint("apiserver", params.Discovery.UseHyperkubeImage), []string{ "--address=127.0.0.1", "--etcd-servers=http://127.0.0.1:2379", "--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota", @@ -78,17 +77,15 @@ func WriteStaticPodManifests(params *kubeadmapi.BootstrapParams) error { "--allow-privileged", params.EnvParams["component_loglevel"], "--token-auth-file=/etc/kubernetes/pki/tokens.csv", - }, + }...), VolumeMounts: []api.VolumeMount{pkiVolumeMount()}, LivenessProbe: componentProbe(8080, "/healthz"), Resources: componentResources("250m"), }, pkiVolume(params)), "kube-controller-manager": componentPod(api.Container{ Name: "kube-controller-manager", - Image: params.EnvParams["hyperkube_image"], - Command: []string{ - "/hyperkube", - "controller-manager", + Image: images.GetCoreImage(images.KubeControllerManagerImage, params.EnvParams["hyperkube_image"], params.Discovery.UseHyperkubeImage), + Command: append(getImageEntrypoint("controller-manager", params.Discovery.UseHyperkubeImage), []string{ "--leader-elect", MASTER, CLUSTER_NAME, @@ -97,22 +94,21 @@ func WriteStaticPodManifests(params *kubeadmapi.BootstrapParams) error { "--cluster-signing-cert-file=/etc/kubernetes/pki/ca.pem", "--cluster-signing-key-file=/etc/kubernetes/pki/ca-key.pem", "--insecure-experimental-approve-all-kubelet-csrs-for-group=system:kubelet-bootstrap", + "--cluster-cidr=10.2.0.0/16", params.EnvParams["component_loglevel"], - }, + }...), VolumeMounts: []api.VolumeMount{pkiVolumeMount()}, LivenessProbe: componentProbe(10252, "/healthz"), Resources: componentResources("200m"), }, pkiVolume(params)), "kube-scheduler": componentPod(api.Container{ Name: "kube-scheduler", - Image: params.EnvParams["hyperkube_image"], - Command: []string{ - "/hyperkube", - "scheduler", + Image: images.GetCoreImage(images.KubeSchedulerImage, params.EnvParams["hyperkube_image"], params.Discovery.UseHyperkubeImage), + Command: append(getImageEntrypoint("scheduler", params.Discovery.UseHyperkubeImage), []string{ "--leader-elect", MASTER, params.EnvParams["component_loglevel"], - }, + }...), LivenessProbe: componentProbe(10251, "/healthz"), Resources: componentResources("100m"), }), @@ -192,3 +188,11 @@ func componentPod(container api.Container, volumes ...api.Volume) api.Pod { }, } } + +func getImageEntrypoint(component string, useHyperkube bool) []string { + if useHyperkube { + return []string{"/hyperkube", component} + } + + return []string{"/usr/local/bin/kube-" + component} +} diff --git a/pkg/kubeadm/master/pki.go b/pkg/kubeadm/master/pki.go index e908c65f6c..bbff5ad919 100644 --- a/pkg/kubeadm/master/pki.go +++ b/pkg/kubeadm/master/pki.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubemaster +package master import ( "crypto/rsa" @@ -137,8 +137,8 @@ func CreatePKIAssets(params *kubeadmapi.BootstrapParams) (*rsa.PrivateKey, *x509 altNames certutil.AltNames // TODO actual SANs ) - if params.Discovery.ListenIP != "" { - altNames.IPs = append(altNames.IPs, net.ParseIP(params.Discovery.ListenIP)) + if params.Discovery.ListenIP != nil { + altNames.IPs = append(altNames.IPs, params.Discovery.ListenIP) } if params.Discovery.ApiServerDNSName != "" { diff --git a/pkg/kubeadm/master/tokens.go b/pkg/kubeadm/master/tokens.go index ff052575a7..844e5ffaaf 100644 --- a/pkg/kubeadm/master/tokens.go +++ b/pkg/kubeadm/master/tokens.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubemaster +package master import ( "bytes" diff --git a/pkg/kubeadm/node/csr.go b/pkg/kubeadm/node/csr.go index e1da517d59..0580bc3791 100644 --- a/pkg/kubeadm/node/csr.go +++ b/pkg/kubeadm/node/csr.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubenode +package node import ( "fmt" diff --git a/pkg/kubeadm/node/discovery.go b/pkg/kubeadm/node/discovery.go index 3b41cdf0b2..62e43b8c4d 100644 --- a/pkg/kubeadm/node/discovery.go +++ b/pkg/kubeadm/node/discovery.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubenode +package node import ( "bytes" @@ -25,7 +25,7 @@ import ( "net/url" "strings" - "github.com/square/go-jose" + jose "github.com/square/go-jose" clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" kubeadmapi "k8s.io/kubernetes/pkg/kubeadm/api" ) diff --git a/pkg/kubeadm/util/kubeconfig.go b/pkg/kubeadm/util/kubeconfig.go index 041021bf9c..dd6cd32835 100644 --- a/pkg/kubeadm/util/kubeconfig.go +++ b/pkg/kubeadm/util/kubeconfig.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubeadmutil +package util import ( "fmt" diff --git a/pkg/kubeadm/util/tokens.go b/pkg/kubeadm/util/tokens.go index 5d643dcf6e..658044a306 100644 --- a/pkg/kubeadm/util/tokens.go +++ b/pkg/kubeadm/util/tokens.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubeadmutil +package util import ( "crypto/rand"