mirror of https://github.com/k3s-io/k3s
Refactoring improtant parts and start on docs
parent
26c4f593aa
commit
b9fd31ff7e
|
@ -46,7 +46,6 @@ func getEnvParams() map[string]string {
|
||||||
"discovery_image": "dgoodwin/kubediscovery:latest", // TODO(phase1): fmt.Sprintf("gcr.io/google_containers/kube-discovery-%s:%s", runtime.GOARCH, "1.0"),
|
"discovery_image": "dgoodwin/kubediscovery:latest", // TODO(phase1): fmt.Sprintf("gcr.io/google_containers/kube-discovery-%s:%s", runtime.GOARCH, "1.0"),
|
||||||
"etcd_image": "",
|
"etcd_image": "",
|
||||||
"component_loglevel": "--v=4",
|
"component_loglevel": "--v=4",
|
||||||
"dns_domain": "cluster.local",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for k := range envParams {
|
for k := range envParams {
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
# Kubernetes Cluster Boostrap Made Easy
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### `kubeadm init`
|
||||||
|
|
||||||
|
It's usually enough to run `kubeadm init`, but in some case you might like to override the
|
||||||
|
default behaviour.
|
||||||
|
|
||||||
|
- `--token=<str>`
|
||||||
|
|
||||||
|
By default, a token is generated, but if you are to automate cluster deployment, you want to
|
||||||
|
set the token ahead of time. Read the docs for more information on the token format.
|
||||||
|
|
||||||
|
- `--api-advertise-addr=<ip>` (multiple values allowed)
|
||||||
|
- `--api-external-dns-name=<domain>` (multiple values allowed)
|
||||||
|
|
||||||
|
By default, `kubeadm` will auto detect IP address and use that to generate API server certificates.
|
||||||
|
If you would like to access the API via any external IPs and/or DNS, which it might not be able
|
||||||
|
to detect, you can use `--api-advertise-addr` and `--api-external-dns-name` to add multiple
|
||||||
|
different IP addresses and DNS names.
|
||||||
|
|
||||||
|
- `--service-cidr=<cidr>` (default: "100.64/12")
|
||||||
|
- `--service-dns-domain=<domain>` (default: "cluster.local")
|
||||||
|
|
||||||
|
- `--use-hyperkube=<bool>` (default: "false")
|
||||||
|
|
||||||
|
***TODO(phase1+)***
|
||||||
|
|
||||||
|
- `--api-bind-addr=<ip>`
|
||||||
|
- `--api-bind-port=<port>`
|
||||||
|
|
||||||
|
***TODO(phase2)***
|
||||||
|
|
||||||
|
- `--api-bind-loopback-unsecure=<bool>`
|
||||||
|
|
||||||
|
***TODO(pahse2)***
|
||||||
|
|
||||||
|
- `--prefer-private-network=<bool>`
|
||||||
|
- `--prefer-public-network=<bool>`
|
||||||
|
|
||||||
|
### `kubeadm join`
|
||||||
|
|
||||||
|
# User Experience Considerations
|
||||||
|
|
||||||
|
> ***TODO*** _Move this into the design document
|
||||||
|
|
||||||
|
a) `kube-apiserver` will listen on `0.0.0.0:443` and `127.0.0.1:8080`, which is not configurable right now and make things a bit easier for the MVP
|
||||||
|
b) there is `kube-discovery`, which will listen on `0.0.0.0:9898`
|
||||||
|
|
||||||
|
|
||||||
|
from the point of view of `kubeadm init`, we need to have
|
||||||
|
a) a primary IP address as will be seen by the nodes and needs to go into the cert and `kube-discovery` configuration secret
|
||||||
|
b) some other names and addresses API server may be known by (e.g. external DNS and/or LB and/or NAT)
|
||||||
|
|
||||||
|
from that perspective we don’t can assume default ports for now, but for all the address we really only care about two ports (i.e. 443 and 9898)
|
||||||
|
|
||||||
|
we should make ports configurable and expose some way of making API server bind to a specific address/interface
|
||||||
|
|
||||||
|
but I think for the MVP we need solve the issue with hardcode IPs and DNS names in the certs
|
||||||
|
|
||||||
|
so it sounds rather simple enough to introduce `--api-advertise-addr=<ip>` and `--api-external-dns-name=<domain>`, and allowing multiple of those sounds also simple enough
|
||||||
|
|
||||||
|
from the `kubeadm join` perspective, it cares about the two ports we mentioned, and we can make those configurable too
|
||||||
|
|
||||||
|
but for now it’s easier to pass just the IP address
|
||||||
|
|
||||||
|
plust it’s also require, so passing it without a named flag sounds convenient, and it’s something users are familiar with
|
||||||
|
|
||||||
|
that’s what Consul does, what what Weave does, and now Docker SwarmKit does the same thing also (edited)
|
||||||
|
|
||||||
|
flags will differ, as there are some Kubernetes-specifics aspects to what join does, but basic join semantics will remain _familiar_
|
||||||
|
|
||||||
|
if we do marry `kube-discovery` with the API, we might do `kubeadm join host:port`, as we’d end-up with a single port to care about
|
||||||
|
|
||||||
|
but we haven’t yet
|
|
@ -20,29 +20,76 @@ import (
|
||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BootstrapParams struct {
|
type KubeadmConfig struct {
|
||||||
// TODO this is mostly out of date and bloated now, let's revisit this soon
|
InitFlags
|
||||||
Discovery *OutOfBandDiscovery
|
JoinFlags
|
||||||
EnvParams map[string]string
|
ManualFlags
|
||||||
}
|
Secrets struct {
|
||||||
|
|
||||||
type OutOfBandDiscovery struct {
|
|
||||||
// 'join-node' side
|
|
||||||
ApiServerURLs string // comma separated
|
|
||||||
CaCertFile string
|
|
||||||
GivenToken string // dot-separated `<TokenID>.<Token>` set by the user
|
GivenToken string // dot-separated `<TokenID>.<Token>` set by the user
|
||||||
TokenID string // optional on master side, will be generated if not specified
|
TokenID string // optional on master side, will be generated if not specified
|
||||||
Token []byte // optional on master side, will be generated if not specified
|
Token []byte // optional on master side, will be generated if not specified
|
||||||
BearerToken string // set based on Token
|
BearerToken string // set based on Token
|
||||||
// 'init-master' side
|
}
|
||||||
ApiServerDNSName string // optional, used in master bootstrap
|
EnvParams map[string]string // TODO(phase2) this is likely to be come componentconfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(phase2) should we add validatin funcs on these structs?
|
||||||
|
|
||||||
|
type InitFlags struct {
|
||||||
|
API struct {
|
||||||
|
AdvertiseAddrs []net.IP
|
||||||
|
ExternalDNSName []string
|
||||||
|
}
|
||||||
|
Services struct {
|
||||||
|
CIDR net.IPNet
|
||||||
|
DNSDomain string
|
||||||
|
}
|
||||||
|
CloudProvider string
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultServiceDNSDomain = "cluster.local"
|
||||||
|
DefaultServicesCIDRString = "100.64.0.0/12"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DefaultServicesCIDR *net.IPNet
|
||||||
|
ListOfCloudProviders = []string{
|
||||||
|
"aws",
|
||||||
|
"azure",
|
||||||
|
"cloudstack",
|
||||||
|
"gce",
|
||||||
|
"mesos",
|
||||||
|
"openstack",
|
||||||
|
"ovirt",
|
||||||
|
"rackspace",
|
||||||
|
"vsphere",
|
||||||
|
}
|
||||||
|
SupportedCloudProviders map[string]bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
_, DefaultServicesCIDR, _ = net.ParseCIDR(DefaultServicesCIDRString)
|
||||||
|
SupportedCloudProviders = make(map[string]bool, len(ListOfCloudProviders))
|
||||||
|
for _, v := range ListOfCloudProviders {
|
||||||
|
SupportedCloudProviders[v] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type JoinFlags struct {
|
||||||
|
MasterAddrs []net.IP
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(phase1?) we haven't decided whether manual sub commands should get merged into main commands...
|
||||||
|
type ManualFlags struct {
|
||||||
|
ApiServerURLs string // comma separated
|
||||||
|
CaCertFile string
|
||||||
|
BearerToken string // set based on Token
|
||||||
ListenIP net.IP // 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 {
|
type ClusterInfo struct {
|
||||||
// TODO Kind, apiVersion
|
// TODO(pahse1?) this may become simply `api.Config`
|
||||||
// TODO clusterId, fetchedTime, expiredTime
|
|
||||||
CertificateAuthorities []string `json:"certificateAuthorities"`
|
CertificateAuthorities []string `json:"certificateAuthorities"`
|
||||||
Endpoints []string `json:"endpoints"`
|
Endpoints []string `json:"endpoints"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,25 +73,25 @@ func NewKubeadmCommand(f *cmdutil.Factory, in io.Reader, out, err io.Writer, env
|
||||||
// TODO(phase2) detect interactive vs non-interactive use and adjust output accordingly
|
// TODO(phase2) detect interactive vs non-interactive use and adjust output accordingly
|
||||||
// i.e. make it automation friendly
|
// i.e. make it automation friendly
|
||||||
//
|
//
|
||||||
// TODO(phase2) create an bastraction that defines files and the content that needs to
|
// TODO(phase2) create an abstraction that defines files and the content that needs to
|
||||||
// be written to disc and write it all in one go at the end as we have a lot of
|
// be written to disc and write it all in one go at the end as we have a lot of
|
||||||
// crapy little files written from different parts of this code; this could also
|
// crapy little files written from different parts of this code; this could also
|
||||||
// be useful for testing
|
// be useful for testing
|
||||||
|
|
||||||
bootstrapParams := &kubeadmapi.BootstrapParams{
|
s := new(kubeadmapi.KubeadmConfig)
|
||||||
Discovery: &kubeadmapi.OutOfBandDiscovery{
|
s.EnvParams = envParams
|
||||||
// TODO(phase1) this type no longer makes sense here
|
|
||||||
},
|
//s.InitFlags, s.JoinFlags = new(kubeadmapi.InitFlags), new(kubeadmapi.JoinFlags)
|
||||||
EnvParams: envParams,
|
|
||||||
}
|
//s.ManualFlags = new(kubeadmapi.ManualFlags)
|
||||||
|
|
||||||
cmds.ResetFlags()
|
cmds.ResetFlags()
|
||||||
cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc)
|
cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc)
|
||||||
|
|
||||||
cmds.AddCommand(NewCmdInit(out, bootstrapParams))
|
cmds.AddCommand(NewCmdInit(out, s))
|
||||||
cmds.AddCommand(NewCmdJoin(out, bootstrapParams))
|
cmds.AddCommand(NewCmdJoin(out, s))
|
||||||
cmds.AddCommand(NewCmdUser(out, bootstrapParams))
|
cmds.AddCommand(NewCmdUser(out, s))
|
||||||
cmds.AddCommand(NewCmdManual(out, bootstrapParams))
|
cmds.AddCommand(NewCmdManual(out, s))
|
||||||
|
|
||||||
return cmds
|
return cmds
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
|
|
||||||
"github.com/renstrom/dedent"
|
"github.com/renstrom/dedent"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -40,52 +41,91 @@ var (
|
||||||
`)
|
`)
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCmdInit(out io.Writer, params *kubeadmapi.BootstrapParams) *cobra.Command {
|
func NewCmdInit(out io.Writer, s *kubeadmapi.KubeadmConfig) *cobra.Command {
|
||||||
|
advertiseAddrs := &[]string{}
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "init",
|
Use: "init",
|
||||||
Short: "Run this on the first server you deploy onto.",
|
Short: "Run this on the first server you deploy onto.",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
err := RunInit(out, cmd, args, params)
|
err := RunInit(out, cmd, args, s, advertiseAddrs)
|
||||||
cmdutil.CheckErr(err)
|
cmdutil.CheckErr(err) // TODO(phase1+) append alpha warning with bugs URL etc
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.PersistentFlags().IPVar(¶ms.Discovery.ListenIP, "listen-ip", nil,
|
cmd.PersistentFlags().StringVar(
|
||||||
`(optional) IP address to listen on, in case autodetection fails.`)
|
&s.Secrets.GivenToken, "token", "",
|
||||||
cmd.PersistentFlags().StringVar(¶ms.Discovery.GivenToken, "token", "",
|
`(optional) Shared secret used to secure bootstrap. Will be generated and displayed if not provided.`,
|
||||||
`(optional) Shared secret used to secure bootstrap. Will be generated and displayed if not provided.`)
|
)
|
||||||
cmd.PersistentFlags().BoolVar(¶ms.Discovery.UseHyperkubeImage, "use-hyperkube", false,
|
cmd.PersistentFlags().StringSliceVar(
|
||||||
`(optional) Use the hyperkube image for running the apiserver, controller-manager, scheduler and proxy.`)
|
advertiseAddrs, "api-advertise-addr", []string{},
|
||||||
|
`(optional) IP address to advertise, in case autodetection fails.`,
|
||||||
|
)
|
||||||
|
cmd.PersistentFlags().StringSliceVar(
|
||||||
|
&s.InitFlags.API.ExternalDNSName, "api-external-dns-name", []string{},
|
||||||
|
`(optional) DNS name to advertise, in case you have configured one yourself.`,
|
||||||
|
)
|
||||||
|
|
||||||
|
cmd.PersistentFlags().IPNetVar(
|
||||||
|
&s.InitFlags.Services.CIDR, "service-cidr", *kubeadmapi.DefaultServicesCIDR,
|
||||||
|
`(optional) use alterantive range of IP address for service VIPs, e.g. "10.16.0.0/12"`,
|
||||||
|
)
|
||||||
|
cmd.PersistentFlags().StringVar(
|
||||||
|
&s.InitFlags.Services.DNSDomain, "service-dns-domain", kubeadmapi.DefaultServiceDNSDomain,
|
||||||
|
`(optional) use alterantive domain name for services, e.g. "myorg.internal"`,
|
||||||
|
)
|
||||||
|
cmd.PersistentFlags().StringVar(
|
||||||
|
&s.InitFlags.CloudProvider, "cloud-provider", "",
|
||||||
|
`(optional) enable cloud proiver features (external load-balancers, storage, etc)`,
|
||||||
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunInit(out io.Writer, cmd *cobra.Command, args []string, params *kubeadmapi.BootstrapParams) error {
|
func RunInit(out io.Writer, cmd *cobra.Command, args []string, s *kubeadmapi.KubeadmConfig, advertiseAddrs *[]string) error {
|
||||||
|
|
||||||
// Auto-detect the IP
|
// Auto-detect the IP
|
||||||
if params.Discovery.ListenIP == nil {
|
if len(*advertiseAddrs) == 0 {
|
||||||
|
// TODO(phase1+) perhaps we could actually grab eth0 and eth1
|
||||||
ip, err := netutil.ChooseHostInterface()
|
ip, err := netutil.ChooseHostInterface()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
params.Discovery.ListenIP = ip
|
s.InitFlags.API.AdvertiseAddrs = []net.IP{ip}
|
||||||
|
} else {
|
||||||
|
for _, i := range *advertiseAddrs {
|
||||||
|
addr := net.ParseIP(i)
|
||||||
|
if addr == nil {
|
||||||
|
return fmt.Errorf("<cmd/init> failed to parse flag (%q) as an IP address", "--api-advertise-addr="+i)
|
||||||
}
|
}
|
||||||
if err := kubemaster.CreateTokenAuthFile(params); err != nil {
|
s.InitFlags.API.AdvertiseAddrs = append(s.InitFlags.API.AdvertiseAddrs, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.InitFlags.CloudProvider != "" {
|
||||||
|
// TODO(phase2) we should be able to auto-detect it and check whether things like IAM roles are correct
|
||||||
|
if _, ok := kubeadmapi.SupportedCloudProviders[s.InitFlags.CloudProvider]; !ok {
|
||||||
|
return fmt.Errorf("<cmd/init> cloud provider %q is not supported, you can use any of %v, or leave it unset", s.InitFlags.CloudProvider, kubeadmapi.ListOfCloudProviders)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := kubemaster.CreateTokenAuthFile(s); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := kubemaster.WriteStaticPodManifests(params); err != nil {
|
|
||||||
|
if err := kubemaster.WriteStaticPodManifests(s); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
caKey, caCert, err := kubemaster.CreatePKIAssets(params)
|
|
||||||
|
caKey, caCert, err := kubemaster.CreatePKIAssets(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
kubeconfigs, err := kubemaster.CreateCertsAndConfigForClients(params, []string{"kubelet", "admin"}, caKey, caCert)
|
|
||||||
|
kubeconfigs, err := kubemaster.CreateCertsAndConfigForClients(s, []string{"kubelet", "admin"}, caKey, caCert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for name, kubeconfig := range kubeconfigs {
|
for name, kubeconfig := range kubeconfigs {
|
||||||
if err := kubeadmutil.WriteKubeconfigIfNotExists(params, name, kubeconfig); err != nil {
|
if err := kubeadmutil.WriteKubeconfigIfNotExists(s, name, kubeconfig); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,18 +139,18 @@ func RunInit(out io.Writer, cmd *cobra.Command, args []string, params *kubeadmap
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := kubemaster.CreateDiscoveryDeploymentAndSecret(params, client, caCert); err != nil {
|
if err := kubemaster.CreateDiscoveryDeploymentAndSecret(s, client, caCert); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := kubemaster.CreateEssentialAddons(params, client); err != nil {
|
if err := kubemaster.CreateEssentialAddons(s, client); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO use templates to reference struct fields directly as order of args is fragile
|
// TODO(phase1+) use templates to reference struct fields directly as order of args is fragile
|
||||||
fmt.Fprintf(out, init_done_msgf,
|
fmt.Fprintf(out, init_done_msgf,
|
||||||
params.Discovery.GivenToken,
|
s.Secrets.GivenToken,
|
||||||
params.Discovery.ListenIP,
|
s.InitFlags.API.AdvertiseAddrs[0].String(),
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -19,6 +19,7 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
|
|
||||||
"github.com/renstrom/dedent"
|
"github.com/renstrom/dedent"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -40,44 +41,52 @@ var (
|
||||||
`)
|
`)
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCmdJoin(out io.Writer, params *kubeadmapi.BootstrapParams) *cobra.Command {
|
func NewCmdJoin(out io.Writer, s *kubeadmapi.KubeadmConfig) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "join",
|
Use: "join",
|
||||||
Short: "Run this on other servers to join an existing cluster.",
|
Short: "Run this on other servers to join an existing cluster.",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
err := RunJoin(out, cmd, args, params)
|
err := RunJoin(out, cmd, args, s)
|
||||||
cmdutil.CheckErr(err)
|
cmdutil.CheckErr(err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this should become `kubeadm join --token=<...> <master-ip-addr>`
|
// TODO this should become `kubeadm join --token=<...> <master-ip-addr>`
|
||||||
cmd.PersistentFlags().StringVarP(¶ms.Discovery.ApiServerURLs, "api-server-urls", "", "",
|
cmd.PersistentFlags().StringVarP(
|
||||||
`Comma separated list of API server URLs. Typically this might be just
|
&s.Secrets.GivenToken, "token", "", "",
|
||||||
https://<address-of-master>:8080/`)
|
`Shared secret used to secure bootstrap. Must match output of 'init-master'.`,
|
||||||
cmd.PersistentFlags().StringVarP(¶ms.Discovery.GivenToken, "token", "", "",
|
)
|
||||||
`Shared secret used to secure bootstrap. Must match output of 'init-master'.`)
|
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunJoin(out io.Writer, cmd *cobra.Command, args []string, params *kubeadmapi.BootstrapParams) error {
|
func RunJoin(out io.Writer, cmd *cobra.Command, args []string, s *kubeadmapi.KubeadmConfig) error {
|
||||||
ok, err := kubeadmutil.UseGivenTokenIfValid(params)
|
// TODO this we are missing args from the help text, there should be a way to tell cobra about it
|
||||||
|
if len(args) == 0 {
|
||||||
|
return fmt.Errorf("<cmd/join> must specify master IP address (see --help)")
|
||||||
|
}
|
||||||
|
for _, i := range args {
|
||||||
|
addr := net.ParseIP(i) // TODO(phase1+) should allow resolvable names too
|
||||||
|
if addr == nil {
|
||||||
|
return fmt.Errorf("<cmd/join> failed parse argument (%q) as an IP address", i)
|
||||||
|
}
|
||||||
|
s.JoinFlags.MasterAddrs = append(s.JoinFlags.MasterAddrs, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err := kubeadmutil.UseGivenTokenIfValid(s)
|
||||||
if !ok {
|
if !ok {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s (see --help)\n", err)
|
return fmt.Errorf("<cmd/join> %s (see --help)\n", err)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("Must specify --token (see --help)\n")
|
return fmt.Errorf("Must specify --token (see --help)\n")
|
||||||
}
|
}
|
||||||
if params.Discovery.ApiServerURLs == "" {
|
|
||||||
return fmt.Errorf("Must specify --api-server-urls (see --help)\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
kubeconfig, err := kubenode.RetrieveTrustedClusterInfo(params)
|
kubeconfig, err := kubenode.RetrieveTrustedClusterInfo(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = kubeadmutil.WriteKubeconfigIfNotExists(params, "kubelet", kubeconfig)
|
err = kubeadmutil.WriteKubeconfigIfNotExists(s, "kubelet", kubeconfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
|
|
||||||
"github.com/renstrom/dedent"
|
"github.com/renstrom/dedent"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -58,23 +59,23 @@ var (
|
||||||
`)
|
`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO --token here becomes Discovery.BearerToken and not Discovery.GivenToken
|
// TODO --token here becomes `s.Secrets.BearerToken` and not `s.Secrets.GivenToken`
|
||||||
// may be we should make it the same and ask user to pass dot-separated tokens
|
// may be we should make it the same and ask user to pass dot-separated tokens
|
||||||
// in any of the modes; we could also enable discovery API in the manual mode just
|
// in any of the modes; we could also enable discovery API in the manual mode just
|
||||||
// as well, there is no reason we shouldn't let user mix and match modes, unless
|
// as well, there is no reason we shouldn't let user mix and match modes, unless
|
||||||
// it is too difficult to support
|
// it is too difficult to support
|
||||||
|
|
||||||
func NewCmdManual(out io.Writer, params *kubeadmapi.BootstrapParams) *cobra.Command {
|
func NewCmdManual(out io.Writer, s *kubeadmapi.KubeadmConfig) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "manual",
|
Use: "manual",
|
||||||
Short: "Advanced, less-automated functionality, for power users.",
|
Short: "Advanced, less-automated functionality, for power users.",
|
||||||
// TODO put example usage in the Long description here
|
// TODO put example usage in the Long description here
|
||||||
}
|
}
|
||||||
cmd.AddCommand(NewCmdManualBootstrap(out, params))
|
cmd.AddCommand(NewCmdManualBootstrap(out, s))
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCmdManualBootstrap(out io.Writer, params *kubeadmapi.BootstrapParams) *cobra.Command {
|
func NewCmdManualBootstrap(out io.Writer, s *kubeadmapi.KubeadmConfig) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "bootstrap",
|
Use: "bootstrap",
|
||||||
Short: "Manually bootstrap a cluster 'out-of-band'",
|
Short: "Manually bootstrap a cluster 'out-of-band'",
|
||||||
|
@ -85,13 +86,14 @@ func NewCmdManualBootstrap(out io.Writer, params *kubeadmapi.BootstrapParams) *c
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.AddCommand(NewCmdManualBootstrapInitMaster(out, params))
|
cmd.AddCommand(NewCmdManualBootstrapInitMaster(out, s))
|
||||||
cmd.AddCommand(NewCmdManualBootstrapJoinNode(out, params))
|
cmd.AddCommand(NewCmdManualBootstrapJoinNode(out, s))
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCmdManualBootstrapInitMaster(out io.Writer, params *kubeadmapi.BootstrapParams) *cobra.Command {
|
func NewCmdManualBootstrapInitMaster(out io.Writer, s *kubeadmapi.KubeadmConfig) *cobra.Command {
|
||||||
|
advertiseAddrs := &[]string{}
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "init-master",
|
Use: "init-master",
|
||||||
Short: "Manually bootstrap a master 'out-of-band'",
|
Short: "Manually bootstrap a master 'out-of-band'",
|
||||||
|
@ -101,101 +103,140 @@ func NewCmdManualBootstrapInitMaster(out io.Writer, params *kubeadmapi.Bootstrap
|
||||||
components.
|
components.
|
||||||
`),
|
`),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
err := RunManualBootstrapInitMaster(out, cmd, args, params)
|
err := RunManualBootstrapInitMaster(out, cmd, args, s, advertiseAddrs)
|
||||||
cmdutil.CheckErr(err)
|
cmdutil.CheckErr(err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
params.Discovery.ApiServerURLs = "http://127.0.0.1:8080/" // On the master, assume you can talk to the API server
|
cmd.PersistentFlags().StringVar(
|
||||||
cmd.PersistentFlags().StringVar(¶ms.Discovery.ApiServerDNSName, "api-dns-name", "",
|
&s.Secrets.BearerToken, "token", "",
|
||||||
`(optional) DNS name for the API server, will be encoded into
|
`(optional) Shared secret used to secure bootstrap. Will be generated and displayed if not provided.`,
|
||||||
subjectAltName in the resulting (generated) TLS certificates`)
|
)
|
||||||
cmd.PersistentFlags().IPVar(¶ms.Discovery.ListenIP, "listen-ip", nil,
|
cmd.PersistentFlags().StringSliceVar(
|
||||||
`(optional) IP address to listen on, in case autodetection fails.`)
|
advertiseAddrs, "api-advertise-addr", nil,
|
||||||
cmd.PersistentFlags().StringVar(¶ms.Discovery.BearerToken, "token", "",
|
`(optional) IP address to advertise, in case autodetection fails.`,
|
||||||
`(optional) Shared secret used to secure bootstrap. Will be generated and displayed if not provided.`)
|
)
|
||||||
|
cmd.PersistentFlags().StringSliceVar(
|
||||||
|
&s.InitFlags.API.ExternalDNSName, "api-external-dns-name", []string{},
|
||||||
|
`(optional) DNS name to advertise, in case you have configured one yourself.`,
|
||||||
|
)
|
||||||
|
_, defaultServicesCIDR, _ := net.ParseCIDR("100.64.0.0/12")
|
||||||
|
cmd.PersistentFlags().IPNetVar(
|
||||||
|
&s.InitFlags.Services.CIDR, "service-cidr", *defaultServicesCIDR,
|
||||||
|
`(optional) use alterantive range of IP address for service VIPs, e.g. "10.16.0.0/12"`,
|
||||||
|
)
|
||||||
|
cmd.PersistentFlags().StringVar(
|
||||||
|
&s.InitFlags.Services.DNSDomain, "service-dns-domain", "cluster.local",
|
||||||
|
`(optional) use alterantive domain name for services, e.g. "myorg.internal"`,
|
||||||
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunManualBootstrapInitMaster(out io.Writer, cmd *cobra.Command, args []string, params *kubeadmapi.BootstrapParams) error {
|
func RunManualBootstrapInitMaster(out io.Writer, cmd *cobra.Command, args []string, s *kubeadmapi.KubeadmConfig, advertiseAddrs *[]string) error {
|
||||||
// Auto-detect the IP
|
// Auto-detect the IP
|
||||||
if params.Discovery.ListenIP == nil {
|
if len(*advertiseAddrs) == 0 {
|
||||||
|
// TODO(phase1+) perhaps we could actually grab eth0 and eth1
|
||||||
ip, err := netutil.ChooseHostInterface()
|
ip, err := netutil.ChooseHostInterface()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
params.Discovery.ListenIP = ip
|
s.InitFlags.API.AdvertiseAddrs = []net.IP{ip}
|
||||||
|
} else {
|
||||||
|
for _, i := range *advertiseAddrs {
|
||||||
|
addr := net.ParseIP(i)
|
||||||
|
if addr == nil {
|
||||||
|
return fmt.Errorf("<cmd/init> failed to parse flag (%q) as an IP address", "--api-advertise-addr="+i)
|
||||||
|
}
|
||||||
|
s.InitFlags.API.AdvertiseAddrs = append(s.InitFlags.API.AdvertiseAddrs, addr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := kubemaster.CreateTokenAuthFile(params); err != nil {
|
if err := kubemaster.CreateTokenAuthFile(s); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := kubemaster.WriteStaticPodManifests(params); err != nil {
|
if err := kubemaster.WriteStaticPodManifests(s); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
caKey, caCert, err := kubemaster.CreatePKIAssets(params)
|
caKey, caCert, err := kubemaster.CreatePKIAssets(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
kubeconfigs, err := kubemaster.CreateCertsAndConfigForClients(params, []string{"kubelet", "admin"}, caKey, caCert)
|
kubeconfigs, err := kubemaster.CreateCertsAndConfigForClients(s, []string{"kubelet", "admin"}, caKey, caCert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for name, kubeconfig := range kubeconfigs {
|
for name, kubeconfig := range kubeconfigs {
|
||||||
if err := kubeadmutil.WriteKubeconfigIfNotExists(params, name, kubeconfig); err != nil {
|
if err := kubeadmutil.WriteKubeconfigIfNotExists(s, name, kubeconfig); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO we have most of cmd/init functionality here, except for `CreateDiscoveryDeploymentAndSecret()`
|
||||||
|
// it may be a good idea to just merge the two commands into one, and it's something we have started talking
|
||||||
|
// about, the only question is where disco service should be an opt-out...
|
||||||
|
|
||||||
|
client, err := kubemaster.CreateClientAndWaitForAPI(kubeconfigs["admin"])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := kubemaster.UpdateMasterRoleLabelsAndTaints(client); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := kubemaster.CreateEssentialAddons(s, client); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// TODO use templates to reference struct fields directly as order of args is fragile
|
// TODO use templates to reference struct fields directly as order of args is fragile
|
||||||
fmt.Fprintf(out, manual_init_done_msgf,
|
fmt.Fprintf(out, manual_init_done_msgf,
|
||||||
params.Discovery.BearerToken,
|
s.Secrets.BearerToken,
|
||||||
params.Discovery.ListenIP,
|
s.InitFlags.API.AdvertiseAddrs[0].String(),
|
||||||
)
|
)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCmdManualBootstrapJoinNode(out io.Writer, params *kubeadmapi.BootstrapParams) *cobra.Command {
|
func NewCmdManualBootstrapJoinNode(out io.Writer, s *kubeadmapi.KubeadmConfig) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "join-node",
|
Use: "join-node",
|
||||||
Short: "Manually bootstrap a node 'out-of-band', joining it into a cluster with extant control plane",
|
Short: "Manually bootstrap a node 'out-of-band', joining it into a cluster with extant control plane",
|
||||||
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
err := RunManualBootstrapJoinNode(out, cmd, args, params)
|
err := RunManualBootstrapJoinNode(out, cmd, args, s)
|
||||||
cmdutil.CheckErr(err)
|
cmdutil.CheckErr(err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.PersistentFlags().StringVarP(¶ms.Discovery.CaCertFile, "ca-cert-file", "", "",
|
cmd.PersistentFlags().StringVarP(&s.ManualFlags.CaCertFile, "ca-cert-file", "", "",
|
||||||
`Path to a CA cert file in PEM format. The same CA cert must be distributed to
|
`Path to a CA cert file in PEM format. The same CA cert must be distributed to
|
||||||
all servers.`)
|
all servers.`)
|
||||||
cmd.PersistentFlags().StringVarP(¶ms.Discovery.ApiServerURLs, "api-server-urls", "", "",
|
cmd.PersistentFlags().StringVarP(&s.ManualFlags.ApiServerURLs, "api-server-urls", "", "",
|
||||||
`Comma separated list of API server URLs. Typically this might be just
|
`Comma separated list of API server URLs. Typically this might be just
|
||||||
https://<address-of-master>:8080/`)
|
https://<address-of-master>:8080/`)
|
||||||
cmd.PersistentFlags().StringVarP(¶ms.Discovery.BearerToken, "token", "", "",
|
cmd.PersistentFlags().StringVarP(&s.ManualFlags.BearerToken, "token", "", "",
|
||||||
`Shared secret used to secure bootstrap. Must match output of 'init-master'.`)
|
`Shared secret used to secure bootstrap. Must match output of 'init-master'.`)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunManualBootstrapJoinNode(out io.Writer, cmd *cobra.Command, args []string, params *kubeadmapi.BootstrapParams) error {
|
func RunManualBootstrapJoinNode(out io.Writer, cmd *cobra.Command, args []string, s *kubeadmapi.KubeadmConfig) error {
|
||||||
if params.Discovery.CaCertFile == "" {
|
if s.ManualFlags.CaCertFile == "" {
|
||||||
fmt.Fprintf(out, "Must specify --ca-cert-file (see --help)\n")
|
fmt.Fprintf(out, "Must specify --ca-cert-file (see --help)\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.Discovery.ApiServerURLs == "" {
|
if s.ManualFlags.ApiServerURLs == "" {
|
||||||
fmt.Fprintf(out, "Must specify --api-server-urls (see --help)\n")
|
fmt.Fprintf(out, "Must specify --api-server-urls (see --help)\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
kubeconfig, err := kubenode.PerformTLSBootstrapFromParams(params)
|
kubeconfig, err := kubenode.PerformTLSBootstrapFromConfig(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(out, "Failed to perform TLS bootstrap: %s\n", err)
|
fmt.Fprintf(out, "Failed to perform TLS bootstrap: %s\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = kubeadmutil.WriteKubeconfigIfNotExists(params, "kubelet", kubeconfig)
|
err = kubeadmutil.WriteKubeconfigIfNotExists(s, "kubelet", kubeconfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(out, "Unable to write config for node:\n%s\n", err)
|
fmt.Fprintf(out, "Unable to write config for node:\n%s\n", err)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
kubeadmapi "k8s.io/kubernetes/pkg/kubeadm/api"
|
kubeadmapi "k8s.io/kubernetes/pkg/kubeadm/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCmdUser(out io.Writer, params *kubeadmapi.BootstrapParams) *cobra.Command {
|
func NewCmdUser(out io.Writer, s *kubeadmapi.KubeadmConfig) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "user",
|
Use: "user",
|
||||||
Short: "Get initial admin credentials for a cluster.", // using TLS bootstrap
|
Short: "Get initial admin credentials for a cluster.", // using TLS bootstrap
|
||||||
|
|
|
@ -33,7 +33,6 @@ const (
|
||||||
KubeDnsmasqImage = "dnsmasq"
|
KubeDnsmasqImage = "dnsmasq"
|
||||||
KubeExechealthzImage = "exechealthz"
|
KubeExechealthzImage = "exechealthz"
|
||||||
|
|
||||||
|
|
||||||
gcrPrefix = "gcr.io/google_containers"
|
gcrPrefix = "gcr.io/google_containers"
|
||||||
etcdVersion = "2.2.5"
|
etcdVersion = "2.2.5"
|
||||||
kubeVersion = "v1.4.0-alpha.3"
|
kubeVersion = "v1.4.0-alpha.3"
|
||||||
|
@ -43,21 +42,11 @@ const (
|
||||||
exechealthzVersion = "1.1"
|
exechealthzVersion = "1.1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetCoreImage(image string, overrideImage string, useHyperkube bool) string {
|
func GetCoreImage(image string, overrideImage string) string {
|
||||||
if overrideImage != "" {
|
if overrideImage != "" {
|
||||||
return 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{
|
return map[string]string{
|
||||||
KubeEtcdImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "etcd", runtime.GOARCH, etcdVersion),
|
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),
|
KubeApiServerImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-apiserver", runtime.GOARCH, kubeVersion),
|
||||||
|
@ -69,7 +58,7 @@ func GetCoreImage(image string, overrideImage string, useHyperkube bool) string
|
||||||
|
|
||||||
func GetAddonImage(image string) string {
|
func GetAddonImage(image string) string {
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
KubeDnsImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-dns", runtime.GOARCH, kubeDnsVersion),
|
KubeDnsImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kubedns", runtime.GOARCH, kubeDnsVersion),
|
||||||
KubeDnsmasqImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-dnsmasq", runtime.GOARCH, dnsmasqVersion),
|
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),
|
KubeExechealthzImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "exechealthz", runtime.GOARCH, exechealthzVersion),
|
||||||
}[image]
|
}[image]
|
||||||
|
|
|
@ -25,20 +25,18 @@ import (
|
||||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
kubeadmapi "k8s.io/kubernetes/pkg/kubeadm/api"
|
kubeadmapi "k8s.io/kubernetes/pkg/kubeadm/api"
|
||||||
"k8s.io/kubernetes/pkg/kubeadm/images"
|
"k8s.io/kubernetes/pkg/kubeadm/images"
|
||||||
|
ipallocator "k8s.io/kubernetes/pkg/registry/service/ipallocator"
|
||||||
"k8s.io/kubernetes/pkg/util/intstr"
|
"k8s.io/kubernetes/pkg/util/intstr"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createKubeProxyPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec {
|
func createKubeProxyPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec {
|
||||||
privilegedTrue := true
|
privilegedTrue := true
|
||||||
return api.PodSpec{
|
return api.PodSpec{
|
||||||
SecurityContext: &api.PodSecurityContext{HostNetwork: true},
|
SecurityContext: &api.PodSecurityContext{HostNetwork: true},
|
||||||
Containers: []api.Container{{
|
Containers: []api.Container{{
|
||||||
Name: "kube-proxy",
|
Name: kubeProxy,
|
||||||
Image: images.GetCoreImage(images.KubeProxyImage, params.EnvParams["hyperkube_image"], params.Discovery.UseHyperkubeImage),
|
Image: images.GetCoreImage(images.KubeProxyImage, s.EnvParams["hyperkube_image"]),
|
||||||
Command: append(getImageEntrypoint("proxy", params.Discovery.UseHyperkubeImage), []string{
|
Command: append(getComponentCommand("proxy", s), "--kubeconfig=/run/kubeconfig"),
|
||||||
"--kubeconfig=/run/kubeconfig",
|
|
||||||
params.EnvParams["component_loglevel"],
|
|
||||||
}...),
|
|
||||||
SecurityContext: &api.SecurityContext{Privileged: &privilegedTrue},
|
SecurityContext: &api.SecurityContext{Privileged: &privilegedTrue},
|
||||||
VolumeMounts: []api.VolumeMount{
|
VolumeMounts: []api.VolumeMount{
|
||||||
{
|
{
|
||||||
|
@ -67,7 +65,7 @@ func createKubeProxyPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec {
|
||||||
{
|
{
|
||||||
Name: "kubeconfig",
|
Name: "kubeconfig",
|
||||||
VolumeSource: api.VolumeSource{
|
VolumeSource: api.VolumeSource{
|
||||||
HostPath: &api.HostPathVolumeSource{Path: path.Join(params.EnvParams["prefix"], "kubelet.conf")},
|
HostPath: &api.HostPathVolumeSource{Path: path.Join(s.EnvParams["prefix"], "kubelet.conf")},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -80,8 +78,7 @@ func createKubeProxyPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(phase1): Create the DNS service as well
|
func createKubeDNSPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec {
|
||||||
func createKubeDNSPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec {
|
|
||||||
|
|
||||||
dnsPodResources := api.ResourceList{
|
dnsPodResources := api.ResourceList{
|
||||||
api.ResourceName(api.ResourceCPU): resource.MustParse("100m"),
|
api.ResourceName(api.ResourceCPU): resource.MustParse("100m"),
|
||||||
|
@ -93,6 +90,16 @@ func createKubeDNSPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec {
|
||||||
api.ResourceName(api.ResourceMemory): resource.MustParse("50Mi"),
|
api.ResourceName(api.ResourceMemory): resource.MustParse("50Mi"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kubeDNSPort := int32(10053)
|
||||||
|
dnsmasqPort := int32(53)
|
||||||
|
|
||||||
|
nslookup := fmt.Sprintf("nslookup kubernetes.default.svc.%s 127.0.0.1", s.InitFlags.Services.DNSDomain)
|
||||||
|
|
||||||
|
nslookup = fmt.Sprintf("-cmd=%s:%d >/dev/null && %s:%d >/dev/null",
|
||||||
|
nslookup, dnsmasqPort,
|
||||||
|
nslookup, kubeDNSPort,
|
||||||
|
)
|
||||||
|
|
||||||
return api.PodSpec{
|
return api.PodSpec{
|
||||||
Containers: []api.Container{
|
Containers: []api.Container{
|
||||||
// DNS server
|
// DNS server
|
||||||
|
@ -104,8 +111,8 @@ func createKubeDNSPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec {
|
||||||
Requests: dnsPodResources,
|
Requests: dnsPodResources,
|
||||||
},
|
},
|
||||||
Args: []string{
|
Args: []string{
|
||||||
"--domain=" + params.EnvParams["dns_domain"],
|
fmt.Sprintf("--domain=%s", s.InitFlags.Services.DNSDomain),
|
||||||
"--dns-port=10053",
|
fmt.Sprintf("--dns-port=%d", kubeDNSPort),
|
||||||
// TODO __PILLAR__FEDERATIONS__DOMAIN__MAP__
|
// TODO __PILLAR__FEDERATIONS__DOMAIN__MAP__
|
||||||
},
|
},
|
||||||
LivenessProbe: &api.Probe{
|
LivenessProbe: &api.Probe{
|
||||||
|
@ -136,12 +143,12 @@ func createKubeDNSPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec {
|
||||||
},
|
},
|
||||||
Ports: []api.ContainerPort{
|
Ports: []api.ContainerPort{
|
||||||
{
|
{
|
||||||
ContainerPort: 10053,
|
ContainerPort: kubeDNSPort,
|
||||||
Name: "dns-local",
|
Name: "dns-local",
|
||||||
Protocol: api.ProtocolUDP,
|
Protocol: api.ProtocolUDP,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ContainerPort: 10053,
|
ContainerPort: kubeDNSPort,
|
||||||
Name: "dns-tcp-local",
|
Name: "dns-tcp-local",
|
||||||
Protocol: api.ProtocolTCP,
|
Protocol: api.ProtocolTCP,
|
||||||
},
|
},
|
||||||
|
@ -158,16 +165,16 @@ func createKubeDNSPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec {
|
||||||
Args: []string{
|
Args: []string{
|
||||||
"--cache-size=1000",
|
"--cache-size=1000",
|
||||||
"--no-resolv",
|
"--no-resolv",
|
||||||
"--server=127.0.0.1#10053",
|
fmt.Sprintf("--server=127.0.0.1#%d", kubeDNSPort),
|
||||||
},
|
},
|
||||||
Ports: []api.ContainerPort{
|
Ports: []api.ContainerPort{
|
||||||
{
|
{
|
||||||
ContainerPort: 53,
|
ContainerPort: dnsmasqPort,
|
||||||
Name: "dns",
|
Name: "dns",
|
||||||
Protocol: api.ProtocolUDP,
|
Protocol: api.ProtocolUDP,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ContainerPort: 53,
|
ContainerPort: dnsmasqPort,
|
||||||
Name: "dns-tcp",
|
Name: "dns-tcp",
|
||||||
Protocol: api.ProtocolTCP,
|
Protocol: api.ProtocolTCP,
|
||||||
},
|
},
|
||||||
|
@ -182,7 +189,7 @@ func createKubeDNSPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec {
|
||||||
Requests: healthzPodResources,
|
Requests: healthzPodResources,
|
||||||
},
|
},
|
||||||
Args: []string{
|
Args: []string{
|
||||||
"-cmd=nslookup kubernetes.default.svc." + params.EnvParams["dns_domain"] + " 127.0.0.1 >/dev/null && nslookup kubernetes.default.svc." + params.EnvParams["dns_domain"] + " 127.0.0.1:10053 >/dev/null",
|
nslookup,
|
||||||
"-port=8080",
|
"-port=8080",
|
||||||
"-quiet",
|
"-quiet",
|
||||||
},
|
},
|
||||||
|
@ -196,19 +203,27 @@ func createKubeDNSPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
func createKubeDNSServiceSpec(params *kubeadmapi.BootstrapParams) api.ServiceSpec {
|
|
||||||
return api.ServiceSpec{
|
func createKubeDNSServiceSpec(s *kubeadmapi.KubeadmConfig) (*api.ServiceSpec, error) {
|
||||||
|
ip, err := ipallocator.GetIndexedIP(&s.InitFlags.Services.CIDR, 10)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to allocate IP address for kube-dns addon from the given CIDR (%q) [%s]", s.InitFlags.Services.CIDR, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
svc := &api.ServiceSpec{
|
||||||
Selector: map[string]string{"name": "kube-dns"},
|
Selector: map[string]string{"name": "kube-dns"},
|
||||||
Ports: []api.ServicePort{
|
Ports: []api.ServicePort{
|
||||||
{Name: "dns", Port: 53, Protocol: api.ProtocolUDP},
|
{Name: "dns", Port: 53, Protocol: api.ProtocolUDP},
|
||||||
{Name: "dns-tcp", Port: 53, Protocol: api.ProtocolTCP},
|
{Name: "dns-tcp", Port: 53, Protocol: api.ProtocolTCP},
|
||||||
},
|
},
|
||||||
ClusterIP: "100.64.0.2",
|
ClusterIP: ip.String(),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateEssentialAddons(params *kubeadmapi.BootstrapParams, client *clientset.Clientset) error {
|
return svc, nil
|
||||||
kubeProxyDaemonSet := NewDaemonSet("kube-proxy", createKubeProxyPodSpec(params))
|
}
|
||||||
|
|
||||||
|
func CreateEssentialAddons(s *kubeadmapi.KubeadmConfig, client *clientset.Clientset) error {
|
||||||
|
kubeProxyDaemonSet := NewDaemonSet(kubeProxy, createKubeProxyPodSpec(s))
|
||||||
SetMasterTaintTolerations(&kubeProxyDaemonSet.Spec.Template.ObjectMeta)
|
SetMasterTaintTolerations(&kubeProxyDaemonSet.Spec.Template.ObjectMeta)
|
||||||
|
|
||||||
if _, err := client.Extensions().DaemonSets(api.NamespaceSystem).Create(kubeProxyDaemonSet); err != nil {
|
if _, err := client.Extensions().DaemonSets(api.NamespaceSystem).Create(kubeProxyDaemonSet); err != nil {
|
||||||
|
@ -217,15 +232,19 @@ func CreateEssentialAddons(params *kubeadmapi.BootstrapParams, client *clientset
|
||||||
|
|
||||||
fmt.Println("<master/addons> created essential addon: kube-proxy")
|
fmt.Println("<master/addons> created essential addon: kube-proxy")
|
||||||
|
|
||||||
kubeDNSDeployment := NewDeployment("kube-dns", 1, createKubeDNSPodSpec(params))
|
kubeDNSDeployment := NewDeployment("kube-dns", 1, createKubeDNSPodSpec(s))
|
||||||
SetMasterTaintTolerations(&kubeDNSDeployment.Spec.Template.ObjectMeta)
|
SetMasterTaintTolerations(&kubeDNSDeployment.Spec.Template.ObjectMeta)
|
||||||
|
|
||||||
if _, err := client.Extensions().Deployments(api.NamespaceSystem).Create(kubeDNSDeployment); err != nil {
|
if _, err := client.Extensions().Deployments(api.NamespaceSystem).Create(kubeDNSDeployment); err != nil {
|
||||||
return fmt.Errorf("<master/addons> failed creating essential kube-dns addon [%s]", err)
|
return fmt.Errorf("<master/addons> failed creating essential kube-dns addon [%s]", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
kubeDNSService := NewService("kube-dns", createKubeDNSServiceSpec(params))
|
kubeDNSServiceSpec, err := createKubeDNSServiceSpec(s)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("<master/addons> failed creating essential kube-dns addon - %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
kubeDNSService := NewService("kube-dns", *kubeDNSServiceSpec)
|
||||||
if _, err := client.Services(api.NamespaceSystem).Create(kubeDNSService); err != nil {
|
if _, err := client.Services(api.NamespaceSystem).Create(kubeDNSService); err != nil {
|
||||||
return fmt.Errorf("<master/addons> failed creating essential kube-dns addon [%s]", err)
|
return fmt.Errorf("<master/addons> failed creating essential kube-dns addon [%s]", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ const (
|
||||||
kubeDiscoverySecretName = "clusterinfo"
|
kubeDiscoverySecretName = "clusterinfo"
|
||||||
)
|
)
|
||||||
|
|
||||||
func encodeKubeDiscoverySecretData(params *kubeadmapi.BootstrapParams, caCert *x509.Certificate) map[string][]byte {
|
func encodeKubeDiscoverySecretData(s *kubeadmapi.KubeadmConfig, caCert *x509.Certificate) map[string][]byte {
|
||||||
// TODO ListenIP is probably not the right now, although it's best we have right now
|
// TODO ListenIP is probably not the right now, although it's best we have right now
|
||||||
// if user provides a DNS name, or anything else, we should use that, may be it's really
|
// if user provides a DNS name, or anything else, we should use that, may be it's really
|
||||||
// the list of all SANs (minus internal DNS names and service IP)?
|
// the list of all SANs (minus internal DNS names and service IP)?
|
||||||
|
@ -50,8 +50,11 @@ func encodeKubeDiscoverySecretData(params *kubeadmapi.BootstrapParams, caCert *x
|
||||||
tokenMap = map[string]string{}
|
tokenMap = map[string]string{}
|
||||||
)
|
)
|
||||||
|
|
||||||
endpointList = append(endpointList, fmt.Sprintf("https://%s:443", params.Discovery.ListenIP))
|
for _, addr := range s.InitFlags.API.AdvertiseAddrs {
|
||||||
tokenMap[params.Discovery.TokenID] = hex.EncodeToString(params.Discovery.Token)
|
endpointList = append(endpointList, fmt.Sprintf("https://%s:443", addr.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenMap[s.Secrets.TokenID] = hex.EncodeToString(s.Secrets.Token)
|
||||||
|
|
||||||
data["endpoint-list.json"], _ = json.Marshal(endpointList)
|
data["endpoint-list.json"], _ = json.Marshal(endpointList)
|
||||||
data["token-map.json"], _ = json.Marshal(tokenMap)
|
data["token-map.json"], _ = json.Marshal(tokenMap)
|
||||||
|
@ -60,7 +63,7 @@ func encodeKubeDiscoverySecretData(params *kubeadmapi.BootstrapParams, caCert *x
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
func newKubeDiscoveryPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec {
|
func newKubeDiscoveryPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec {
|
||||||
return api.PodSpec{
|
return api.PodSpec{
|
||||||
// We have to use host network namespace, as `HostPort`/`HostIP` are Docker's
|
// We have to use host network namespace, as `HostPort`/`HostIP` are Docker's
|
||||||
// buisness and CNI support isn't quite there yet (except for kubenet)
|
// buisness and CNI support isn't quite there yet (except for kubenet)
|
||||||
|
@ -69,7 +72,7 @@ func newKubeDiscoveryPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec {
|
||||||
SecurityContext: &api.PodSecurityContext{HostNetwork: true},
|
SecurityContext: &api.PodSecurityContext{HostNetwork: true},
|
||||||
Containers: []api.Container{{
|
Containers: []api.Container{{
|
||||||
Name: kubeDiscoverynName,
|
Name: kubeDiscoverynName,
|
||||||
Image: params.EnvParams["discovery_image"],
|
Image: s.EnvParams["discovery_image"],
|
||||||
Command: []string{"/usr/bin/kube-discovery"},
|
Command: []string{"/usr/bin/kube-discovery"},
|
||||||
VolumeMounts: []api.VolumeMount{{
|
VolumeMounts: []api.VolumeMount{{
|
||||||
Name: kubeDiscoverySecretName,
|
Name: kubeDiscoverySecretName,
|
||||||
|
@ -77,7 +80,8 @@ func newKubeDiscoveryPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec {
|
||||||
ReadOnly: true,
|
ReadOnly: true,
|
||||||
}},
|
}},
|
||||||
Ports: []api.ContainerPort{
|
Ports: []api.ContainerPort{
|
||||||
// TODO when CNI issue (#31307) is resolved, we should add `HostIP: params.Discovery.ListenIP`
|
// TODO when CNI issue (#31307) is resolved, we should consider adding
|
||||||
|
// `HostIP: s.API.AdvertiseAddrs[0]`, if there is only one address`
|
||||||
{Name: "http", ContainerPort: 9898, HostPort: 9898},
|
{Name: "http", ContainerPort: 9898, HostPort: 9898},
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
|
@ -90,13 +94,13 @@ func newKubeDiscoveryPodSpec(params *kubeadmapi.BootstrapParams) api.PodSpec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newKubeDiscovery(params *kubeadmapi.BootstrapParams, caCert *x509.Certificate) kubeDiscovery {
|
func newKubeDiscovery(s *kubeadmapi.KubeadmConfig, caCert *x509.Certificate) kubeDiscovery {
|
||||||
kd := kubeDiscovery{
|
kd := kubeDiscovery{
|
||||||
Deployment: NewDeployment(kubeDiscoverynName, 1, newKubeDiscoveryPodSpec(params)),
|
Deployment: NewDeployment(kubeDiscoverynName, 1, newKubeDiscoveryPodSpec(s)),
|
||||||
Secret: &api.Secret{
|
Secret: &api.Secret{
|
||||||
ObjectMeta: api.ObjectMeta{Name: kubeDiscoverySecretName},
|
ObjectMeta: api.ObjectMeta{Name: kubeDiscoverySecretName},
|
||||||
Type: api.SecretTypeOpaque,
|
Type: api.SecretTypeOpaque,
|
||||||
Data: encodeKubeDiscoverySecretData(params, caCert),
|
Data: encodeKubeDiscoverySecretData(s, caCert),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,8 +110,8 @@ func newKubeDiscovery(params *kubeadmapi.BootstrapParams, caCert *x509.Certifica
|
||||||
return kd
|
return kd
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateDiscoveryDeploymentAndSecret(params *kubeadmapi.BootstrapParams, client *clientset.Clientset, caCert *x509.Certificate) error {
|
func CreateDiscoveryDeploymentAndSecret(s *kubeadmapi.KubeadmConfig, client *clientset.Clientset, caCert *x509.Certificate) error {
|
||||||
kd := newKubeDiscovery(params, caCert)
|
kd := newKubeDiscovery(s, caCert)
|
||||||
|
|
||||||
if _, err := client.Extensions().Deployments(api.NamespaceSystem).Create(kd.Deployment); err != nil {
|
if _, err := client.Extensions().Deployments(api.NamespaceSystem).Create(kd.Deployment); err != nil {
|
||||||
return fmt.Errorf("<master/discovery> failed to create %q deployment [%s]", kubeDiscoverynName, err)
|
return fmt.Errorf("<master/discovery> failed to create %q deployment [%s]", kubeDiscoverynName, err)
|
||||||
|
|
|
@ -28,11 +28,14 @@ import (
|
||||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateCertsAndConfigForClients(params *kubeadmapi.BootstrapParams, clientNames []string, caKey *rsa.PrivateKey, caCert *x509.Certificate) (map[string]*clientcmdapi.Config, error) {
|
func CreateCertsAndConfigForClients(s *kubeadmapi.KubeadmConfig, clientNames []string, caKey *rsa.PrivateKey, caCert *x509.Certificate) (map[string]*clientcmdapi.Config, error) {
|
||||||
|
|
||||||
basicClientConfig := kubeadmutil.CreateBasicClientConfig(
|
basicClientConfig := kubeadmutil.CreateBasicClientConfig(
|
||||||
"kubernetes",
|
"kubernetes",
|
||||||
fmt.Sprintf("https://%s:443", params.Discovery.ListenIP),
|
// TODO this is not great, but there is only one address we can use here
|
||||||
|
// so we'll pick the first one, there is much of chance to have an empty
|
||||||
|
// slice by the time this gets called
|
||||||
|
fmt.Sprintf("https://%s:443", s.InitFlags.API.AdvertiseAddrs[0]),
|
||||||
certutil.EncodeCertPEM(caCert),
|
certutil.EncodeCertPEM(caCert),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -36,85 +36,65 @@ import (
|
||||||
// init master` and `kubeadm manual bootstrap master` can get going.
|
// init master` and `kubeadm manual bootstrap master` can get going.
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SERVICE_CLUSTER_IP_RANGE = "--service-cluster-ip-range=100.64.0.0/12"
|
DefaultClusterName = "--cluster-name=kubernetes"
|
||||||
CLUSTER_NAME = "--cluster-name=kubernetes"
|
|
||||||
MASTER = "--master=127.0.0.1:8080"
|
etcd = "etcd"
|
||||||
|
apiServer = "apiserver"
|
||||||
|
controllerManager = "controller-manager"
|
||||||
|
scheduler = "scheduler"
|
||||||
|
proxy = "proxy"
|
||||||
|
kubeAPIServer = "kube-apiserver"
|
||||||
|
kubeControllerManager = "kube-controller-manager"
|
||||||
|
kubeScheduler = "kube-scheduler"
|
||||||
|
kubeProxy = "kube-proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO look into what this really means, scheduler prints it for some reason
|
// TODO look into what this really means, scheduler prints it for some reason
|
||||||
//
|
//
|
||||||
//E0817 17:53:22.242658 1 event.go:258] Could not construct reference to: '&api.Endpoints{TypeMeta:unversioned.TypeMeta{Kind:"", APIVersion:""}, ObjectMeta:api.ObjectMeta{Name:"kube-scheduler", GenerateName:"", Namespace:"kube-system", SelfLink:"", UID:"", ResourceVersion:"", Generation:0, CreationTimestamp:unversioned.Time{Time:time.Time{sec:0, nsec:0, loc:(*time.Location)(nil)}}, DeletionTimestamp:(*unversioned.Time)(nil), DeletionGracePeriodSeconds:(*int64)(nil), Labels:map[string]string(nil), Annotations:map[string]string(nil), OwnerReferences:[]api.OwnerReference(nil), Finalizers:[]string(nil)}, Subsets:[]api.EndpointSubset(nil)}' due to: 'selfLink was empty, can't make reference'. Will not report event: 'Normal' '%v became leader' 'moby'
|
//E0817 17:53:22.242658 1 event.go:258] Could not construct reference to: '&api.Endpoints{TypeMeta:unversioned.TypeMeta{Kind:"", APIVersion:""}, ObjectMeta:api.ObjectMeta{Name:"kube-scheduler", GenerateName:"", Namespace:"kube-system", SelfLink:"", UID:"", ResourceVersion:"", Generation:0, CreationTimestamp:unversioned.Time{Time:time.Time{sec:0, nsec:0, loc:(*time.Location)(nil)}}, DeletionTimestamp:(*unversioned.Time)(nil), DeletionGracePeriodSeconds:(*int64)(nil), Labels:map[string]string(nil), Annotations:map[string]string(nil), OwnerReferences:[]api.OwnerReference(nil), Finalizers:[]string(nil)}, Subsets:[]api.EndpointSubset(nil)}' due to: 'selfLink was empty, can't make reference'. Will not report event: 'Normal' '%v became leader' 'moby'
|
||||||
|
|
||||||
func WriteStaticPodManifests(params *kubeadmapi.BootstrapParams) error {
|
func WriteStaticPodManifests(s *kubeadmapi.KubeadmConfig) error {
|
||||||
staticPodSpecs := map[string]api.Pod{
|
staticPodSpecs := map[string]api.Pod{
|
||||||
// TODO this needs a volume
|
// TODO this needs a volume
|
||||||
"etcd": componentPod(api.Container{
|
etcd: componentPod(api.Container{
|
||||||
Command: []string{
|
Command: []string{
|
||||||
"/usr/local/bin/etcd",
|
"/usr/local/bin/etcd",
|
||||||
"--listen-client-urls=http://127.0.0.1:2379",
|
"--listen-client-urls=http://127.0.0.1:2379",
|
||||||
"--advertise-client-urls=http://127.0.0.1:2379",
|
"--advertise-client-urls=http://127.0.0.1:2379",
|
||||||
"--data-dir=/var/etcd/data",
|
"--data-dir=/var/etcd/data",
|
||||||
},
|
},
|
||||||
Image: images.GetCoreImage(images.KubeEtcdImage, params.EnvParams["etcd_image"], params.Discovery.UseHyperkubeImage),
|
Image: images.GetCoreImage(images.KubeEtcdImage, s.EnvParams["etcd_image"]),
|
||||||
LivenessProbe: componentProbe(2379, "/health"),
|
LivenessProbe: componentProbe(2379, "/health"),
|
||||||
Name: "etcd-server",
|
Name: etcd,
|
||||||
Resources: componentResources("200m"),
|
Resources: componentResources("200m"),
|
||||||
}),
|
}),
|
||||||
// TODO bind-mount certs in
|
// TODO bind-mount certs in
|
||||||
"kube-apiserver": componentPod(api.Container{
|
kubeAPIServer: componentPod(api.Container{
|
||||||
Name: "kube-apiserver",
|
Name: kubeAPIServer,
|
||||||
Image: images.GetCoreImage(images.KubeApiServerImage, params.EnvParams["hyperkube_image"], params.Discovery.UseHyperkubeImage),
|
Image: images.GetCoreImage(images.KubeApiServerImage, s.EnvParams["hyperkube_image"]),
|
||||||
Command: append(getImageEntrypoint("apiserver", params.Discovery.UseHyperkubeImage), []string{
|
Command: getComponentCommand(apiServer, s),
|
||||||
"--address=127.0.0.1",
|
|
||||||
"--etcd-servers=http://127.0.0.1:2379",
|
|
||||||
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota",
|
|
||||||
SERVICE_CLUSTER_IP_RANGE,
|
|
||||||
"--service-account-key-file=/etc/kubernetes/pki/apiserver-key.pem",
|
|
||||||
"--client-ca-file=/etc/kubernetes/pki/ca.pem",
|
|
||||||
"--tls-cert-file=/etc/kubernetes/pki/apiserver.pem",
|
|
||||||
"--tls-private-key-file=/etc/kubernetes/pki/apiserver-key.pem",
|
|
||||||
"--secure-port=443",
|
|
||||||
"--allow-privileged",
|
|
||||||
params.EnvParams["component_loglevel"],
|
|
||||||
"--token-auth-file=/etc/kubernetes/pki/tokens.csv",
|
|
||||||
}...),
|
|
||||||
VolumeMounts: []api.VolumeMount{pkiVolumeMount()},
|
VolumeMounts: []api.VolumeMount{pkiVolumeMount()},
|
||||||
LivenessProbe: componentProbe(8080, "/healthz"),
|
LivenessProbe: componentProbe(8080, "/healthz"),
|
||||||
Resources: componentResources("250m"),
|
Resources: componentResources("250m"),
|
||||||
}, pkiVolume(params)),
|
}, pkiVolume(s)),
|
||||||
"kube-controller-manager": componentPod(api.Container{
|
kubeControllerManager: componentPod(api.Container{
|
||||||
Name: "kube-controller-manager",
|
Name: kubeControllerManager,
|
||||||
Image: images.GetCoreImage(images.KubeControllerManagerImage, params.EnvParams["hyperkube_image"], params.Discovery.UseHyperkubeImage),
|
Image: images.GetCoreImage(images.KubeControllerManagerImage, s.EnvParams["hyperkube_image"]),
|
||||||
Command: append(getImageEntrypoint("controller-manager", params.Discovery.UseHyperkubeImage), []string{
|
Command: getComponentCommand(controllerManager, s),
|
||||||
"--leader-elect",
|
|
||||||
MASTER,
|
|
||||||
CLUSTER_NAME,
|
|
||||||
"--root-ca-file=/etc/kubernetes/pki/ca.pem",
|
|
||||||
"--service-account-private-key-file=/etc/kubernetes/pki/apiserver-key.pem",
|
|
||||||
"--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()},
|
VolumeMounts: []api.VolumeMount{pkiVolumeMount()},
|
||||||
LivenessProbe: componentProbe(10252, "/healthz"),
|
LivenessProbe: componentProbe(10252, "/healthz"),
|
||||||
Resources: componentResources("200m"),
|
Resources: componentResources("200m"),
|
||||||
}, pkiVolume(params)),
|
}, pkiVolume(s)),
|
||||||
"kube-scheduler": componentPod(api.Container{
|
kubeScheduler: componentPod(api.Container{
|
||||||
Name: "kube-scheduler",
|
Name: kubeScheduler,
|
||||||
Image: images.GetCoreImage(images.KubeSchedulerImage, params.EnvParams["hyperkube_image"], params.Discovery.UseHyperkubeImage),
|
Image: images.GetCoreImage(images.KubeSchedulerImage, s.EnvParams["hyperkube_image"]),
|
||||||
Command: append(getImageEntrypoint("scheduler", params.Discovery.UseHyperkubeImage), []string{
|
Command: getComponentCommand(scheduler, s),
|
||||||
"--leader-elect",
|
|
||||||
MASTER,
|
|
||||||
params.EnvParams["component_loglevel"],
|
|
||||||
}...),
|
|
||||||
LivenessProbe: componentProbe(10251, "/healthz"),
|
LivenessProbe: componentProbe(10251, "/healthz"),
|
||||||
Resources: componentResources("100m"),
|
Resources: componentResources("100m"),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
manifestsPath := path.Join(params.EnvParams["prefix"], "manifests")
|
manifestsPath := path.Join(s.EnvParams["prefix"], "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)
|
||||||
}
|
}
|
||||||
|
@ -131,11 +111,11 @@ func WriteStaticPodManifests(params *kubeadmapi.BootstrapParams) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func pkiVolume(params *kubeadmapi.BootstrapParams) api.Volume {
|
func pkiVolume(s *kubeadmapi.KubeadmConfig) api.Volume {
|
||||||
return api.Volume{
|
return api.Volume{
|
||||||
Name: "pki",
|
Name: "pki",
|
||||||
VolumeSource: api.VolumeSource{
|
VolumeSource: api.VolumeSource{
|
||||||
HostPath: &api.HostPathVolumeSource{Path: params.EnvParams["host_pki_path"]},
|
HostPath: &api.HostPathVolumeSource{Path: s.EnvParams["host_pki_path"]},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,10 +169,51 @@ func componentPod(container api.Container, volumes ...api.Volume) api.Pod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getImageEntrypoint(component string, useHyperkube bool) []string {
|
func getComponentCommand(component string, s *kubeadmapi.KubeadmConfig) (command []string) {
|
||||||
if useHyperkube {
|
baseFalgs := map[string][]string{
|
||||||
return []string{"/hyperkube", component}
|
apiServer: []string{
|
||||||
|
"--address=127.0.0.1",
|
||||||
|
"--etcd-servers=http://127.0.0.1:2379",
|
||||||
|
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota",
|
||||||
|
"--service-cluster-ip-range=" + s.InitFlags.Services.CIDR.String(),
|
||||||
|
"--service-account-key-file=/etc/kubernetes/pki/apiserver-key.pem",
|
||||||
|
"--client-ca-file=/etc/kubernetes/pki/ca.pem",
|
||||||
|
"--tls-cert-file=/etc/kubernetes/pki/apiserver.pem",
|
||||||
|
"--tls-private-key-file=/etc/kubernetes/pki/apiserver-key.pem",
|
||||||
|
"--secure-port=443",
|
||||||
|
"--allow-privileged",
|
||||||
|
"--token-auth-file=/etc/kubernetes/pki/tokens.csv",
|
||||||
|
},
|
||||||
|
controllerManager: []string{
|
||||||
|
"--leader-elect",
|
||||||
|
"--master=127.0.0.1:8080",
|
||||||
|
DefaultClusterName,
|
||||||
|
"--root-ca-file=/etc/kubernetes/pki/ca.pem",
|
||||||
|
"--service-account-private-key-file=/etc/kubernetes/pki/apiserver-key.pem",
|
||||||
|
"--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=" + s.InitFlags.Services.CIDR.String(),
|
||||||
|
},
|
||||||
|
scheduler: []string{
|
||||||
|
"--leader-elect",
|
||||||
|
"--master=127.0.0.1:8080",
|
||||||
|
},
|
||||||
|
proxy: []string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
return []string{"/usr/local/bin/kube-" + component}
|
if s.EnvParams["hyperkube_image"] != "" {
|
||||||
|
command = []string{"/hyperkube", component}
|
||||||
|
} else {
|
||||||
|
command = []string{"/usr/local/bin/kube-" + component}
|
||||||
|
}
|
||||||
|
|
||||||
|
command = append(command, s.EnvParams["component_loglevel"])
|
||||||
|
command = append(command, baseFalgs[component]...)
|
||||||
|
|
||||||
|
if component == controllerManager && s.InitFlags.CloudProvider != "" {
|
||||||
|
command = append(command, "--cloud-provider="+s.InitFlags.CloudProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,10 @@ import (
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
kubeadmapi "k8s.io/kubernetes/pkg/kubeadm/api"
|
kubeadmapi "k8s.io/kubernetes/pkg/kubeadm/api"
|
||||||
|
ipallocator "k8s.io/kubernetes/pkg/registry/service/ipallocator"
|
||||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -51,19 +51,26 @@ func newCertificateAuthority() (*rsa.PrivateKey, *x509.Certificate, error) {
|
||||||
return key, cert, nil
|
return key, cert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newServerKeyAndCert(caCert *x509.Certificate, caKey *rsa.PrivateKey, altNames certutil.AltNames) (*rsa.PrivateKey, *x509.Certificate, error) {
|
func newServerKeyAndCert(s *kubeadmapi.KubeadmConfig, caCert *x509.Certificate, caKey *rsa.PrivateKey, altNames certutil.AltNames) (*rsa.PrivateKey, *x509.Certificate, error) {
|
||||||
key, err := certutil.NewPrivateKey()
|
key, err := certutil.NewPrivateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("unabel to create private key [%s]", err)
|
return nil, nil, fmt.Errorf("unabel to create private key [%s]", err)
|
||||||
}
|
}
|
||||||
// TODO these are all hardcoded for now, but we need to figure out what shall we do here exactly
|
|
||||||
altNames.IPs = append(altNames.IPs, net.ParseIP("10.3.0.1"), net.ParseIP("10.16.0.1"), net.ParseIP("100.64.0.1"))
|
internalAPIServerFQDN := []string{
|
||||||
altNames.DNSNames = append(altNames.DNSNames,
|
|
||||||
"kubernetes",
|
"kubernetes",
|
||||||
"kubernetes.default",
|
"kubernetes.default",
|
||||||
"kubernetes.default.svc",
|
"kubernetes.default.svc",
|
||||||
"kubernetes.default.svc.cluster.local",
|
fmt.Sprintf("kubernetes.default.svc.%s", s.InitFlags.Services.DNSDomain),
|
||||||
)
|
}
|
||||||
|
|
||||||
|
internalAPIServerVirtualIP, err := ipallocator.GetIndexedIP(&s.InitFlags.Services.CIDR, 1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("unable to allocate IP address for the API server from the given CIDR (%q) [%s]")
|
||||||
|
}
|
||||||
|
|
||||||
|
altNames.IPs = append(altNames.IPs, internalAPIServerVirtualIP)
|
||||||
|
altNames.DNSNames = append(altNames.DNSNames, internalAPIServerFQDN...)
|
||||||
|
|
||||||
config := certutil.CertConfig{
|
config := certutil.CertConfig{
|
||||||
CommonName: "kube-apiserver",
|
CommonName: "kube-apiserver",
|
||||||
|
@ -131,21 +138,21 @@ func newServiceAccountKey() (*rsa.PrivateKey, error) {
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreatePKIAssets(params *kubeadmapi.BootstrapParams) (*rsa.PrivateKey, *x509.Certificate, error) {
|
func CreatePKIAssets(s *kubeadmapi.KubeadmConfig) (*rsa.PrivateKey, *x509.Certificate, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
altNames certutil.AltNames // TODO actual SANs
|
altNames certutil.AltNames
|
||||||
)
|
)
|
||||||
|
|
||||||
if params.Discovery.ListenIP != nil {
|
if len(s.InitFlags.API.AdvertiseAddrs) > 0 {
|
||||||
altNames.IPs = append(altNames.IPs, params.Discovery.ListenIP)
|
altNames.IPs = append(altNames.IPs, s.InitFlags.API.AdvertiseAddrs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.Discovery.ApiServerDNSName != "" {
|
if len(s.InitFlags.API.ExternalDNSName) > 0 {
|
||||||
altNames.DNSNames = append(altNames.DNSNames, params.Discovery.ApiServerDNSName)
|
altNames.DNSNames = append(altNames.DNSNames, s.InitFlags.API.ExternalDNSName...)
|
||||||
}
|
}
|
||||||
|
|
||||||
pkiPath := path.Join(params.EnvParams["host_pki_path"])
|
pkiPath := path.Join(s.EnvParams["host_pki_path"])
|
||||||
|
|
||||||
caKey, caCert, err := newCertificateAuthority()
|
caKey, caCert, err := newCertificateAuthority()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -156,7 +163,7 @@ func CreatePKIAssets(params *kubeadmapi.BootstrapParams) (*rsa.PrivateKey, *x509
|
||||||
return nil, nil, fmt.Errorf("<master/pki> failure while saving CA keys and certificate - %s", err)
|
return nil, nil, fmt.Errorf("<master/pki> failure while saving CA keys and certificate - %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
apiKey, apiCert, err := newServerKeyAndCert(caCert, caKey, altNames)
|
apiKey, apiCert, err := newServerKeyAndCert(s, caCert, caKey, altNames)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("<master/pki> failure while creating API server keys and certificate - %s", err)
|
return nil, nil, fmt.Errorf("<master/pki> failure while creating API server keys and certificate - %s", err)
|
||||||
}
|
}
|
||||||
|
@ -174,7 +181,7 @@ func CreatePKIAssets(params *kubeadmapi.BootstrapParams) (*rsa.PrivateKey, *x509
|
||||||
return nil, nil, fmt.Errorf("<master/pki> failure while saving service account singing keys - %s", err)
|
return nil, nil, fmt.Errorf("<master/pki> failure while saving service account singing keys - %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO print a summary of SANs used and checksums (signatures) of each of the certiicates
|
// TODO(phase1+) print a summary of SANs used and checksums (signatures) of each of the certiicates
|
||||||
fmt.Printf("<master/pki> created keys and certificates in %q\n", params.EnvParams["host_pki_path"])
|
fmt.Printf("<master/pki> created keys and certificates in %q\n", pkiPath)
|
||||||
return caKey, caCert, nil
|
return caKey, caCert, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,17 +28,17 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/util/uuid"
|
"k8s.io/kubernetes/pkg/util/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
func generateTokenIfNeeded(params *kubeadmapi.BootstrapParams) error {
|
func generateTokenIfNeeded(s *kubeadmapi.KubeadmConfig) error {
|
||||||
ok, err := kubeadmutil.UseGivenTokenIfValid(params)
|
ok, err := kubeadmutil.UseGivenTokenIfValid(s)
|
||||||
if !ok {
|
if !ok {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = kubeadmutil.GenerateToken(params)
|
err = kubeadmutil.GenerateToken(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("<master/tokens> generated token: %q\n", params.Discovery.GivenToken)
|
fmt.Printf("<master/tokens> generated token: %q\n", s.Secrets.GivenToken)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("<master/tokens> accepted provided token")
|
fmt.Println("<master/tokens> accepted provided token")
|
||||||
}
|
}
|
||||||
|
@ -46,15 +46,15 @@ func generateTokenIfNeeded(params *kubeadmapi.BootstrapParams) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateTokenAuthFile(params *kubeadmapi.BootstrapParams) error {
|
func CreateTokenAuthFile(s *kubeadmapi.KubeadmConfig) error {
|
||||||
tokenAuthFilePath := path.Join(params.EnvParams["host_pki_path"], "tokens.csv")
|
tokenAuthFilePath := path.Join(s.EnvParams["host_pki_path"], "tokens.csv")
|
||||||
if err := generateTokenIfNeeded(params); err != nil {
|
if err := generateTokenIfNeeded(s); err != nil {
|
||||||
return fmt.Errorf("<master/tokens> failed to generate token(s) [%s]", err)
|
return fmt.Errorf("<master/tokens> failed to generate token(s) [%s]", err)
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(params.EnvParams["host_pki_path"], 0700); err != nil {
|
if err := os.MkdirAll(s.EnvParams["host_pki_path"], 0700); err != nil {
|
||||||
return fmt.Errorf("<master/tokens> failed to create directory %q [%s]", params.EnvParams["host_pki_path"], err)
|
return fmt.Errorf("<master/tokens> failed to create directory %q [%s]", s.EnvParams["host_pki_path"], err)
|
||||||
}
|
}
|
||||||
serialized := []byte(fmt.Sprintf("%s,kubeadm-node-csr,%s,system:kubelet-bootstrap\n", params.Discovery.BearerToken, uuid.NewUUID()))
|
serialized := []byte(fmt.Sprintf("%s,kubeadm-node-csr,%s,system:kubelet-bootstrap\n", s.Secrets.BearerToken, uuid.NewUUID()))
|
||||||
if err := cmdutil.DumpReaderToFile(bytes.NewReader(serialized), tokenAuthFilePath); err != nil {
|
if err := cmdutil.DumpReaderToFile(bytes.NewReader(serialized), tokenAuthFilePath); err != nil {
|
||||||
return fmt.Errorf("<master/tokens> failed to save token auth file (%q) [%s]", tokenAuthFilePath, err)
|
return fmt.Errorf("<master/tokens> failed to save token auth file (%q) [%s]", tokenAuthFilePath, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,17 +34,17 @@ func getNodeName() string {
|
||||||
return "TODO"
|
return "TODO"
|
||||||
}
|
}
|
||||||
|
|
||||||
func PerformTLSBootstrapFromParams(params *kubeadmapi.BootstrapParams) (*clientcmdapi.Config, error) {
|
func PerformTLSBootstrapFromConfig(s *kubeadmapi.KubeadmConfig) (*clientcmdapi.Config, error) {
|
||||||
caCert, err := ioutil.ReadFile(params.Discovery.CaCertFile)
|
caCert, err := ioutil.ReadFile(s.ManualFlags.CaCertFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("<node/csr> failed to load CA certificate [%s]", err)
|
return nil, fmt.Errorf("<node/csr> failed to load CA certificate [%s]", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return PerformTLSBootstrap(params, strings.Split(params.Discovery.ApiServerURLs, ",")[0], caCert)
|
return PerformTLSBootstrap(s, strings.Split(s.ManualFlags.ApiServerURLs, ",")[0], caCert)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a restful client for doing the certificate signing request.
|
// Create a restful client for doing the certificate signing request.
|
||||||
func PerformTLSBootstrap(params *kubeadmapi.BootstrapParams, apiEndpoint string, caCert []byte) (*clientcmdapi.Config, error) {
|
func PerformTLSBootstrap(s *kubeadmapi.KubeadmConfig, apiEndpoint string, caCert []byte) (*clientcmdapi.Config, error) {
|
||||||
// TODO try all the api servers until we find one that works
|
// TODO try all the api servers until we find one that works
|
||||||
bareClientConfig := kubeadmutil.CreateBasicClientConfig("kubernetes", apiEndpoint, caCert)
|
bareClientConfig := kubeadmutil.CreateBasicClientConfig("kubernetes", apiEndpoint, caCert)
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ func PerformTLSBootstrap(params *kubeadmapi.BootstrapParams, apiEndpoint string,
|
||||||
|
|
||||||
bootstrapClientConfig, err := clientcmd.NewDefaultClientConfig(
|
bootstrapClientConfig, err := clientcmd.NewDefaultClientConfig(
|
||||||
*kubeadmutil.MakeClientConfigWithToken(
|
*kubeadmutil.MakeClientConfigWithToken(
|
||||||
bareClientConfig, "kubernetes", fmt.Sprintf("kubelet-%s", nodeName), params.Discovery.BearerToken,
|
bareClientConfig, "kubernetes", fmt.Sprintf("kubelet-%s", nodeName), s.Secrets.BearerToken,
|
||||||
),
|
),
|
||||||
&clientcmd.ConfigOverrides{},
|
&clientcmd.ConfigOverrides{},
|
||||||
).ClientConfig()
|
).ClientConfig()
|
||||||
|
|
|
@ -22,23 +22,15 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
jose "github.com/square/go-jose"
|
jose "github.com/square/go-jose"
|
||||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||||
kubeadmapi "k8s.io/kubernetes/pkg/kubeadm/api"
|
kubeadmapi "k8s.io/kubernetes/pkg/kubeadm/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RetrieveTrustedClusterInfo(params *kubeadmapi.BootstrapParams) (*clientcmdapi.Config, error) {
|
func RetrieveTrustedClusterInfo(s *kubeadmapi.KubeadmConfig) (*clientcmdapi.Config, error) {
|
||||||
firstURL := strings.Split(params.Discovery.ApiServerURLs, ",")[0] // TODO obviously we should do something better.. .
|
host, port := s.JoinFlags.MasterAddrs[0].String(), 9898
|
||||||
apiServerURL, err := url.Parse(firstURL)
|
requestURL := fmt.Sprintf("http://%s:%d/cluster-info/v1/?token-id=%s", host, port, s.Secrets.TokenID)
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("<node/discovery> failed to parse given API server URL (%q) [%s]", firstURL, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
host, port := strings.Split(apiServerURL.Host, ":")[0], 9898 // TODO this is too naive
|
|
||||||
requestURL := fmt.Sprintf("http://%s:%d/cluster-info/v1/?token-id=%s", host, port, params.Discovery.TokenID)
|
|
||||||
req, err := http.NewRequest("GET", requestURL, nil)
|
req, err := http.NewRequest("GET", requestURL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("<node/discovery> failed to consturct an HTTP request [%s]", err)
|
return nil, fmt.Errorf("<node/discovery> failed to consturct an HTTP request [%s]", err)
|
||||||
|
@ -61,7 +53,7 @@ func RetrieveTrustedClusterInfo(params *kubeadmapi.BootstrapParams) (*clientcmda
|
||||||
|
|
||||||
fmt.Println("<node/discovery> cluster info object received, verifying signature using given token")
|
fmt.Println("<node/discovery> cluster info object received, verifying signature using given token")
|
||||||
|
|
||||||
output, err := object.Verify(params.Discovery.Token)
|
output, err := object.Verify(s.Secrets.Token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("<node/discovery> failed to verify JWS signature of received cluster info object [%s]", err)
|
return nil, fmt.Errorf("<node/discovery> failed to verify JWS signature of received cluster info object [%s]", err)
|
||||||
}
|
}
|
||||||
|
@ -84,5 +76,5 @@ func RetrieveTrustedClusterInfo(params *kubeadmapi.BootstrapParams) (*clientcmda
|
||||||
apiServer := clusterInfo.Endpoints[0]
|
apiServer := clusterInfo.Endpoints[0]
|
||||||
caCert := []byte(clusterInfo.CertificateAuthorities[0])
|
caCert := []byte(clusterInfo.CertificateAuthorities[0])
|
||||||
|
|
||||||
return PerformTLSBootstrap(params, apiServer, caCert)
|
return PerformTLSBootstrap(s, apiServer, caCert)
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,12 +81,12 @@ func MakeClientConfigWithToken(config *clientcmdapi.Config, clusterName string,
|
||||||
// running in that case - they'd need to stop the kubelet, remove the file, and
|
// running in that case - they'd need to stop the kubelet, remove the file, and
|
||||||
// start it again in that case).
|
// start it again in that case).
|
||||||
|
|
||||||
func WriteKubeconfigIfNotExists(params *kubeadmapi.BootstrapParams, name string, kubeconfig *clientcmdapi.Config) error {
|
func WriteKubeconfigIfNotExists(s *kubeadmapi.KubeadmConfig, name string, kubeconfig *clientcmdapi.Config) error {
|
||||||
if err := os.MkdirAll(params.EnvParams["prefix"], 0700); err != nil {
|
if err := os.MkdirAll(s.EnvParams["prefix"], 0700); err != nil {
|
||||||
return fmt.Errorf("<util/kubeconfig> failed to create directory %q [%s]", params.EnvParams["prefix"], err)
|
return fmt.Errorf("<util/kubeconfig> failed to create directory %q [%s]", s.EnvParams["prefix"], err)
|
||||||
}
|
}
|
||||||
|
|
||||||
filename := path.Join(params.EnvParams["prefix"], fmt.Sprintf("%s.conf", name))
|
filename := path.Join(s.EnvParams["prefix"], fmt.Sprintf("%s.conf", name))
|
||||||
// Create and open the file, only if it does not already exist.
|
// Create and open the file, only if it does not already exist.
|
||||||
f, err := os.OpenFile(
|
f, err := os.OpenFile(
|
||||||
filename,
|
filename,
|
||||||
|
|
|
@ -42,7 +42,7 @@ func randBytes(length int) ([]byte, string, error) {
|
||||||
return b, hex.EncodeToString(b), nil
|
return b, hex.EncodeToString(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateToken(params *kubeadmapi.BootstrapParams) error {
|
func GenerateToken(s *kubeadmapi.KubeadmConfig) error {
|
||||||
_, tokenID, err := randBytes(TokenIDLen / 2)
|
_, tokenID, err := randBytes(TokenIDLen / 2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -53,19 +53,19 @@ func GenerateToken(params *kubeadmapi.BootstrapParams) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
params.Discovery.TokenID = tokenID
|
s.Secrets.TokenID = tokenID
|
||||||
params.Discovery.BearerToken = token
|
s.Secrets.BearerToken = token
|
||||||
params.Discovery.Token = tokenBytes
|
s.Secrets.Token = tokenBytes
|
||||||
params.Discovery.GivenToken = fmt.Sprintf("%s.%s", tokenID, token)
|
s.Secrets.GivenToken = fmt.Sprintf("%s.%s", tokenID, token)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UseGivenTokenIfValid(params *kubeadmapi.BootstrapParams) (bool, error) {
|
func UseGivenTokenIfValid(s *kubeadmapi.KubeadmConfig) (bool, error) {
|
||||||
if params.Discovery.GivenToken == "" {
|
if s.Secrets.GivenToken == "" {
|
||||||
return false, nil // not given
|
return false, nil // not given
|
||||||
}
|
}
|
||||||
fmt.Println("<util/tokens> validating provided token")
|
fmt.Println("<util/tokens> validating provided token")
|
||||||
givenToken := strings.Split(strings.ToLower(params.Discovery.GivenToken), ".")
|
givenToken := strings.Split(strings.ToLower(s.Secrets.GivenToken), ".")
|
||||||
// TODO print desired format
|
// TODO print desired format
|
||||||
// TODO could also print more specific messages in each case
|
// TODO could also print more specific messages in each case
|
||||||
invalidErr := "<util/tokens> provided token is invalid - %s"
|
invalidErr := "<util/tokens> provided token is invalid - %s"
|
||||||
|
@ -86,8 +86,8 @@ func UseGivenTokenIfValid(params *kubeadmapi.BootstrapParams) (bool, error) {
|
||||||
"length of second part is incorrect [%d (given) != %d (expected)]",
|
"length of second part is incorrect [%d (given) != %d (expected)]",
|
||||||
len(tokenBytes), TokenBytes))
|
len(tokenBytes), TokenBytes))
|
||||||
}
|
}
|
||||||
params.Discovery.TokenID = givenToken[0]
|
s.Secrets.TokenID = givenToken[0]
|
||||||
params.Discovery.BearerToken = givenToken[1]
|
s.Secrets.BearerToken = givenToken[1]
|
||||||
params.Discovery.Token = tokenBytes
|
s.Secrets.Token = tokenBytes
|
||||||
return true, nil // given and valid
|
return true, nil // given and valid
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue