mirror of https://github.com/kubernetes/kops.git
Merge pull request #1911 from justinsb/more_options_to_code
Move more options to code
This commit is contained in:
commit
0ce094a956
|
@ -33,29 +33,29 @@ type KubeAPIServerOptionsBuilder struct {
|
|||
var _ loader.OptionsBuilder = &KubeAPIServerOptionsBuilder{}
|
||||
|
||||
func (b *KubeAPIServerOptionsBuilder) BuildOptions(o interface{}) error {
|
||||
options := o.(*kops.ClusterSpec)
|
||||
if options.KubeAPIServer == nil {
|
||||
options.KubeAPIServer = &kops.KubeAPIServerConfig{}
|
||||
clusterSpec := o.(*kops.ClusterSpec)
|
||||
if clusterSpec.KubeAPIServer == nil {
|
||||
clusterSpec.KubeAPIServer = &kops.KubeAPIServerConfig{}
|
||||
}
|
||||
|
||||
if options.KubeAPIServer.APIServerCount == nil {
|
||||
count := b.buildAPIServerCount()
|
||||
if clusterSpec.KubeAPIServer.APIServerCount == nil {
|
||||
count := b.buildAPIServerCount(clusterSpec)
|
||||
if count == 0 {
|
||||
return fmt.Errorf("no instance groups found")
|
||||
}
|
||||
options.KubeAPIServer.APIServerCount = fi.Int32(int32(count))
|
||||
clusterSpec.KubeAPIServer.APIServerCount = fi.Int32(int32(count))
|
||||
}
|
||||
|
||||
if options.KubeAPIServer.StorageBackend == nil {
|
||||
if clusterSpec.KubeAPIServer.StorageBackend == nil {
|
||||
// For the moment, we continue to use etcd2
|
||||
options.KubeAPIServer.StorageBackend = fi.String("etcd2")
|
||||
clusterSpec.KubeAPIServer.StorageBackend = fi.String("etcd2")
|
||||
}
|
||||
|
||||
k8sVersion, err := b.Context.KubernetesVersion()
|
||||
k8sVersion, err := KubernetesVersion(clusterSpec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if options.KubeAPIServer.KubeletPreferredAddressTypes == nil {
|
||||
if clusterSpec.KubeAPIServer.KubeletPreferredAddressTypes == nil {
|
||||
if k8sVersion.GTE(semver.MustParse("1.5.0")) {
|
||||
// Default precedence
|
||||
//options.KubeAPIServer.KubeletPreferredAddressTypes = []string {
|
||||
|
@ -66,7 +66,7 @@ func (b *KubeAPIServerOptionsBuilder) BuildOptions(o interface{}) error {
|
|||
//}
|
||||
|
||||
// We prioritize the internal IP above the hostname
|
||||
options.KubeAPIServer.KubeletPreferredAddressTypes = []string{
|
||||
clusterSpec.KubeAPIServer.KubeletPreferredAddressTypes = []string{
|
||||
string(api.NodeInternalIP),
|
||||
string(api.NodeHostName),
|
||||
string(api.NodeExternalIP),
|
||||
|
@ -78,7 +78,7 @@ func (b *KubeAPIServerOptionsBuilder) BuildOptions(o interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (b *KubeAPIServerOptionsBuilder) buildAPIServerCount() int {
|
||||
func (b *KubeAPIServerOptionsBuilder) buildAPIServerCount(clusterSpec *kops.ClusterSpec) int {
|
||||
// The --apiserver-count flag is (generally agreed) to be something we need to get rid of in k8s
|
||||
|
||||
// We should do something like this:
|
||||
|
@ -103,7 +103,7 @@ func (b *KubeAPIServerOptionsBuilder) buildAPIServerCount() int {
|
|||
// the flag won't exist
|
||||
|
||||
counts := make(map[string]int)
|
||||
for _, etcdCluster := range b.Context.Cluster.Spec.EtcdClusters {
|
||||
for _, etcdCluster := range clusterSpec.EtcdClusters {
|
||||
counts[etcdCluster.Name] = len(etcdCluster.Members)
|
||||
}
|
||||
|
||||
|
|
|
@ -17,20 +17,22 @@ limitations under the License.
|
|||
package components
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/blang/semver"
|
||||
"k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/pkg/apis/kops/util"
|
||||
"math/big"
|
||||
"net"
|
||||
)
|
||||
|
||||
// OptionsContext is the context object for options builders
|
||||
type OptionsContext struct {
|
||||
Cluster *kops.Cluster
|
||||
}
|
||||
|
||||
// KubernetesVersion parses the semver version of kubernetes, from the cluster spec
|
||||
func (c *OptionsContext) KubernetesVersion() (*semver.Version, error) {
|
||||
kubernetesVersion := c.Cluster.Spec.KubernetesVersion
|
||||
func KubernetesVersion(clusterSpec *kops.ClusterSpec) (*semver.Version, error) {
|
||||
kubernetesVersion := clusterSpec.KubernetesVersion
|
||||
|
||||
if kubernetesVersion == "" {
|
||||
return nil, fmt.Errorf("KubernetesVersion is required")
|
||||
|
@ -45,8 +47,8 @@ func (c *OptionsContext) KubernetesVersion() (*semver.Version, error) {
|
|||
}
|
||||
|
||||
// UsesKubenet returns true if our networking is derived from kubenet
|
||||
func (c *OptionsContext) UsesKubenet() (bool, error) {
|
||||
networking := c.Cluster.Spec.Networking
|
||||
func UsesKubenet(clusterSpec *kops.ClusterSpec) (bool, error) {
|
||||
networking := clusterSpec.Networking
|
||||
if networking == nil || networking.Classic != nil {
|
||||
return false, nil
|
||||
} else if networking.Kubenet != nil {
|
||||
|
@ -63,3 +65,35 @@ func (c *OptionsContext) UsesKubenet() (bool, error) {
|
|||
return false, fmt.Errorf("No networking mode set")
|
||||
}
|
||||
}
|
||||
|
||||
func WellKnownServiceIP(clusterSpec *kops.ClusterSpec, id int) (net.IP, error) {
|
||||
_, cidr, err := net.ParseCIDR(clusterSpec.ServiceClusterIPRange)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing ServiceClusterIPRange %q: %v", clusterSpec.ServiceClusterIPRange, err)
|
||||
}
|
||||
|
||||
ip4 := cidr.IP.To4()
|
||||
if ip4 != nil {
|
||||
n := binary.BigEndian.Uint32(ip4)
|
||||
n += uint32(id)
|
||||
serviceIP := make(net.IP, len(ip4))
|
||||
binary.BigEndian.PutUint32(serviceIP, n)
|
||||
return serviceIP, nil
|
||||
}
|
||||
|
||||
ip6 := cidr.IP.To16()
|
||||
if ip6 != nil {
|
||||
baseIPInt := big.NewInt(0)
|
||||
baseIPInt.SetBytes(ip6)
|
||||
serviceIPInt := big.NewInt(0)
|
||||
serviceIPInt.Add(big.NewInt(int64(id)), baseIPInt)
|
||||
serviceIP := make(net.IP, len(ip6))
|
||||
serviceIPBytes := serviceIPInt.Bytes()
|
||||
for i := range serviceIPBytes {
|
||||
serviceIP[len(serviceIP)-len(serviceIPBytes)+i] = serviceIPBytes[i]
|
||||
}
|
||||
return serviceIP, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Unexpected IP address type for ServiceClusterIPRange: %s", clusterSpec.ServiceClusterIPRange)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
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 components
|
||||
|
||||
import (
|
||||
"k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/upup/pkg/fi/loader"
|
||||
)
|
||||
|
||||
// DefaultsOptionsBuilder adds default options. This should come first!
|
||||
type DefaultsOptionsBuilder struct {
|
||||
Context *OptionsContext
|
||||
}
|
||||
|
||||
var _ loader.OptionsBuilder = &DefaultsOptionsBuilder{}
|
||||
|
||||
func (b *DefaultsOptionsBuilder) BuildOptions(o interface{}) error {
|
||||
options := o.(*kops.ClusterSpec)
|
||||
|
||||
if options.ClusterDNSDomain == "" {
|
||||
options.ClusterDNSDomain = "cluster.local"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -31,19 +31,19 @@ type DockerOptionsBuilder struct {
|
|||
var _ loader.OptionsBuilder = &DockerOptionsBuilder{}
|
||||
|
||||
func (b *DockerOptionsBuilder) BuildOptions(o interface{}) error {
|
||||
options := o.(*kops.ClusterSpec)
|
||||
if options.Docker == nil {
|
||||
options.Docker = &kops.DockerConfig{}
|
||||
clusterSpec := o.(*kops.ClusterSpec)
|
||||
if clusterSpec.Docker == nil {
|
||||
clusterSpec.Docker = &kops.DockerConfig{}
|
||||
}
|
||||
|
||||
if fi.StringValue(options.Docker.Version) == "" {
|
||||
if options.KubernetesVersion == "" {
|
||||
if fi.StringValue(clusterSpec.Docker.Version) == "" {
|
||||
if clusterSpec.KubernetesVersion == "" {
|
||||
return fmt.Errorf("KubernetesVersion is required")
|
||||
}
|
||||
|
||||
sv, err := b.Context.KubernetesVersion()
|
||||
sv, err := KubernetesVersion(clusterSpec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to determine kubernetes version from %q", options.KubernetesVersion)
|
||||
return fmt.Errorf("unable to determine kubernetes version from %q", clusterSpec.KubernetesVersion)
|
||||
}
|
||||
|
||||
dockerVersion := ""
|
||||
|
@ -54,10 +54,10 @@ func (b *DockerOptionsBuilder) BuildOptions(o interface{}) error {
|
|||
}
|
||||
|
||||
if dockerVersion == "" {
|
||||
return fmt.Errorf("unknown version of kubernetes %q (cannot infer docker version)", options.KubernetesVersion)
|
||||
return fmt.Errorf("unknown version of kubernetes %q (cannot infer docker version)", clusterSpec.KubernetesVersion)
|
||||
}
|
||||
|
||||
options.Docker.Version = &dockerVersion
|
||||
clusterSpec.Docker.Version = &dockerVersion
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -41,10 +41,10 @@ var _ loader.OptionsBuilder = &KubeControllerManagerOptionsBuilder{}
|
|||
// BuildOptions generates the configurations used to create kubernetes controller manager manifest
|
||||
func (b *KubeControllerManagerOptionsBuilder) BuildOptions(o interface{}) error {
|
||||
|
||||
options := o.(*kops.ClusterSpec)
|
||||
clusterSpec := o.(*kops.ClusterSpec)
|
||||
|
||||
if options.KubeControllerManager == nil {
|
||||
options.KubeControllerManager = &kops.KubeControllerManagerConfig{}
|
||||
if clusterSpec.KubeControllerManager == nil {
|
||||
clusterSpec.KubeControllerManager = &kops.KubeControllerManagerConfig{}
|
||||
}
|
||||
|
||||
k8sv148, err := util.ParseKubernetesVersion("v1.4.8")
|
||||
|
@ -63,7 +63,7 @@ func (b *KubeControllerManagerOptionsBuilder) BuildOptions(o interface{}) error
|
|||
return fmt.Errorf("Unable to parse kubernetesVersion %s", err)
|
||||
}
|
||||
|
||||
kubernetesVersion, err := b.Context.KubernetesVersion()
|
||||
kubernetesVersion, err := KubernetesVersion(clusterSpec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to parse kubernetesVersion %s", err)
|
||||
}
|
||||
|
@ -78,27 +78,27 @@ func (b *KubeControllerManagerOptionsBuilder) BuildOptions(o interface{}) error
|
|||
|
||||
glog.V(4).Infof("Kubernetes version %q supports AttachDetachReconcileSyncPeriod; will configure", kubernetesVersion)
|
||||
// If not set ... or set to 0s ... which is stupid
|
||||
if options.KubeControllerManager.AttachDetachReconcileSyncPeriod == nil ||
|
||||
options.KubeControllerManager.AttachDetachReconcileSyncPeriod.Duration.String() == "0s" {
|
||||
if clusterSpec.KubeControllerManager.AttachDetachReconcileSyncPeriod == nil ||
|
||||
clusterSpec.KubeControllerManager.AttachDetachReconcileSyncPeriod.Duration.String() == "0s" {
|
||||
|
||||
glog.V(8).Infof("AttachDetachReconcileSyncPeriod is not set; will set to default %v", defaultAttachDetachReconcileSyncPeriod)
|
||||
options.KubeControllerManager.AttachDetachReconcileSyncPeriod = &metav1.Duration{Duration: defaultAttachDetachReconcileSyncPeriod}
|
||||
clusterSpec.KubeControllerManager.AttachDetachReconcileSyncPeriod = &metav1.Duration{Duration: defaultAttachDetachReconcileSyncPeriod}
|
||||
|
||||
// If less than 1 min and greater than 1 sec ... you get a warning
|
||||
} else if options.KubeControllerManager.AttachDetachReconcileSyncPeriod.Duration < defaultAttachDetachReconcileSyncPeriod &&
|
||||
options.KubeControllerManager.AttachDetachReconcileSyncPeriod.Duration > time.Second {
|
||||
} else if clusterSpec.KubeControllerManager.AttachDetachReconcileSyncPeriod.Duration < defaultAttachDetachReconcileSyncPeriod &&
|
||||
clusterSpec.KubeControllerManager.AttachDetachReconcileSyncPeriod.Duration > time.Second {
|
||||
|
||||
glog.Infof("KubeControllerManager AttachDetachReconcileSyncPeriod is set lower than recommended: %s", defaultAttachDetachReconcileSyncPeriod)
|
||||
|
||||
// If less than 1sec you get an error. Controller is coded to not allow configuration
|
||||
// less than one second.
|
||||
} else if options.KubeControllerManager.AttachDetachReconcileSyncPeriod.Duration < time.Second {
|
||||
} else if clusterSpec.KubeControllerManager.AttachDetachReconcileSyncPeriod.Duration < time.Second {
|
||||
return fmt.Errorf("AttachDetachReconcileSyncPeriod cannot be set to less than 1 second")
|
||||
}
|
||||
} else {
|
||||
|
||||
glog.V(4).Infof("not setting AttachDetachReconcileSyncPeriod, k8s version is too low")
|
||||
options.KubeControllerManager.AttachDetachReconcileSyncPeriod = nil
|
||||
clusterSpec.KubeControllerManager.AttachDetachReconcileSyncPeriod = nil
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -47,9 +47,7 @@ func Test_Build_KCM_Builder_Lower_Version(t *testing.T) {
|
|||
c := buildCluster()
|
||||
|
||||
kcm := &KubeControllerManagerOptionsBuilder{
|
||||
Context: &OptionsContext{
|
||||
Cluster: c,
|
||||
},
|
||||
Context: &OptionsContext{},
|
||||
}
|
||||
|
||||
spec := c.Spec
|
||||
|
@ -76,9 +74,7 @@ func Test_Build_KCM_Builder_High_Enough_Version(t *testing.T) {
|
|||
c.Spec.KubernetesVersion = v
|
||||
|
||||
kcm := &KubeControllerManagerOptionsBuilder{
|
||||
Context: &OptionsContext{
|
||||
Cluster: c,
|
||||
},
|
||||
Context: &OptionsContext{},
|
||||
}
|
||||
|
||||
spec := c.Spec
|
||||
|
@ -101,9 +97,7 @@ func Test_Build_KCM_Builder_Change_Duration(t *testing.T) {
|
|||
c.Spec.KubernetesVersion = "v1.5.2"
|
||||
|
||||
kcm := &KubeControllerManagerOptionsBuilder{
|
||||
Context: &OptionsContext{
|
||||
Cluster: c,
|
||||
},
|
||||
Context: &OptionsContext{},
|
||||
}
|
||||
|
||||
spec := c.Spec
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
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 components
|
||||
|
||||
import (
|
||||
"k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/upup/pkg/fi/loader"
|
||||
)
|
||||
|
||||
// KubeDnsOptionsBuilder adds options for kube-dns
|
||||
type KubeDnsOptionsBuilder struct {
|
||||
Context *OptionsContext
|
||||
}
|
||||
|
||||
var _ loader.OptionsBuilder = &KubeDnsOptionsBuilder{}
|
||||
|
||||
func (b *KubeDnsOptionsBuilder) BuildOptions(o interface{}) error {
|
||||
clusterSpec := o.(*kops.ClusterSpec)
|
||||
|
||||
if clusterSpec.KubeDNS == nil {
|
||||
clusterSpec.KubeDNS = &kops.KubeDNSConfig{}
|
||||
}
|
||||
|
||||
clusterSpec.KubeDNS.Replicas = 2
|
||||
ip, err := WellKnownServiceIP(clusterSpec, 10)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clusterSpec.KubeDNS.ServerIP = ip.String()
|
||||
clusterSpec.KubeDNS.Domain = clusterSpec.ClusterDNSDomain
|
||||
// TODO: Once we start shipping more images, start using them
|
||||
clusterSpec.KubeDNS.Image = "gcr.io/google_containers/kubedns-amd64:1.3"
|
||||
|
||||
return nil
|
||||
}
|
|
@ -31,47 +31,70 @@ type KubeletOptionsBuilder struct {
|
|||
var _ loader.OptionsBuilder = &KubeletOptionsBuilder{}
|
||||
|
||||
func (b *KubeletOptionsBuilder) BuildOptions(o interface{}) error {
|
||||
options := o.(*kops.ClusterSpec)
|
||||
clusterSpec := o.(*kops.ClusterSpec)
|
||||
|
||||
kubernetesVersion, err := b.Context.KubernetesVersion()
|
||||
kubernetesVersion, err := KubernetesVersion(clusterSpec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if options.Kubelet == nil {
|
||||
options.Kubelet = &kops.KubeletConfigSpec{}
|
||||
if clusterSpec.Kubelet == nil {
|
||||
clusterSpec.Kubelet = &kops.KubeletConfigSpec{}
|
||||
}
|
||||
if options.MasterKubelet == nil {
|
||||
options.MasterKubelet = &kops.KubeletConfigSpec{}
|
||||
if clusterSpec.MasterKubelet == nil {
|
||||
clusterSpec.MasterKubelet = &kops.KubeletConfigSpec{}
|
||||
}
|
||||
|
||||
ip, err := WellKnownServiceIP(clusterSpec, 10)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Standard options
|
||||
clusterSpec.Kubelet.EnableDebuggingHandlers = fi.Bool(true)
|
||||
clusterSpec.Kubelet.PodManifestPath = "/etc/kubernetes/manifests"
|
||||
clusterSpec.Kubelet.AllowPrivileged = fi.Bool(true)
|
||||
clusterSpec.Kubelet.LogLevel = fi.Int32(2)
|
||||
clusterSpec.Kubelet.ClusterDNS = ip.String()
|
||||
clusterSpec.Kubelet.ClusterDomain = clusterSpec.ClusterDNSDomain
|
||||
clusterSpec.Kubelet.BabysitDaemons = fi.Bool(true)
|
||||
clusterSpec.Kubelet.APIServers = "https://" + clusterSpec.MasterInternalName
|
||||
clusterSpec.Kubelet.NonMasqueradeCIDR = clusterSpec.NonMasqueradeCIDR
|
||||
|
||||
clusterSpec.MasterKubelet.RegisterSchedulable = fi.Bool(false)
|
||||
clusterSpec.MasterKubelet.APIServers = "http://127.0.0.1:8080"
|
||||
// Replace the CIDR with a CIDR allocated by KCM (the default, but included for clarity)
|
||||
// We _do_ allow debugging handlers, so we can do logs
|
||||
// This does allow more access than we would like though
|
||||
clusterSpec.MasterKubelet.EnableDebuggingHandlers = fi.Bool(true)
|
||||
|
||||
// In 1.5 we fixed this, but in 1.4 we need to set the PodCIDR on the master
|
||||
// so that hostNetwork pods can come up
|
||||
if kubernetesVersion.Major == 1 && kubernetesVersion.Minor <= 4 {
|
||||
// We bootstrap with a fake CIDR, but then this will be replaced (unless we're running with _isolated_master)
|
||||
options.MasterKubelet.PodCIDR = "10.123.45.0/28"
|
||||
clusterSpec.MasterKubelet.PodCIDR = "10.123.45.0/28"
|
||||
}
|
||||
|
||||
// 1.5 deprecates the reconcile cidr option (and 1.6 removes it)
|
||||
if kubernetesVersion.Major == 1 && kubernetesVersion.Minor <= 4 {
|
||||
options.MasterKubelet.ReconcileCIDR = fi.Bool(true)
|
||||
clusterSpec.MasterKubelet.ReconcileCIDR = fi.Bool(true)
|
||||
|
||||
if fi.BoolValue(b.Context.Cluster.Spec.IsolateMasters) {
|
||||
options.MasterKubelet.ReconcileCIDR = fi.Bool(false)
|
||||
if fi.BoolValue(clusterSpec.IsolateMasters) {
|
||||
clusterSpec.MasterKubelet.ReconcileCIDR = fi.Bool(false)
|
||||
}
|
||||
|
||||
usesKubenet, err := b.Context.UsesKubenet()
|
||||
usesKubenet, err := UsesKubenet(clusterSpec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if usesKubenet {
|
||||
options.Kubelet.ReconcileCIDR = fi.Bool(true)
|
||||
clusterSpec.Kubelet.ReconcileCIDR = fi.Bool(true)
|
||||
}
|
||||
}
|
||||
|
||||
if kubernetesVersion.Major == 1 && kubernetesVersion.Minor >= 4 {
|
||||
// For pod eviction in low memory or empty disk situations
|
||||
if options.Kubelet.EvictionHard == nil {
|
||||
if clusterSpec.Kubelet.EvictionHard == nil {
|
||||
evictionHard := []string{
|
||||
// TODO: Some people recommend 250Mi, but this would hurt small machines
|
||||
"memory.available<100Mi",
|
||||
|
@ -83,15 +106,48 @@ func (b *KubeletOptionsBuilder) BuildOptions(o interface{}) error {
|
|||
"imagefs.available<10%",
|
||||
"imagefs.inodesFree<5%",
|
||||
}
|
||||
options.Kubelet.EvictionHard = fi.String(strings.Join(evictionHard, ","))
|
||||
clusterSpec.Kubelet.EvictionHard = fi.String(strings.Join(evictionHard, ","))
|
||||
}
|
||||
}
|
||||
|
||||
// IsolateMasters enables the legacy behaviour, where master pods on a separate network
|
||||
// In newer versions of kubernetes, most of that functionality has been removed though
|
||||
if fi.BoolValue(b.Context.Cluster.Spec.IsolateMasters) {
|
||||
options.MasterKubelet.EnableDebuggingHandlers = fi.Bool(false)
|
||||
options.MasterKubelet.HairpinMode = "none"
|
||||
if fi.BoolValue(clusterSpec.IsolateMasters) {
|
||||
clusterSpec.MasterKubelet.EnableDebuggingHandlers = fi.Bool(false)
|
||||
clusterSpec.MasterKubelet.HairpinMode = "none"
|
||||
}
|
||||
|
||||
cloudProvider := fi.CloudProviderID(clusterSpec.CloudProvider)
|
||||
|
||||
if cloudProvider == fi.CloudProviderAWS {
|
||||
clusterSpec.Kubelet.CloudProvider = "aws"
|
||||
clusterSpec.Kubelet.CgroupRoot = "docker"
|
||||
|
||||
// Use the hostname from the AWS metadata service
|
||||
clusterSpec.Kubelet.HostnameOverride = "@aws"
|
||||
}
|
||||
|
||||
if cloudProvider == fi.CloudProviderGCE {
|
||||
clusterSpec.Kubelet.CloudProvider = "gce"
|
||||
clusterSpec.Kubelet.HairpinMode = "promiscuous-bridge"
|
||||
|
||||
clusterSpec.Kubelet.RuntimeCgroups = "/docker-daemon"
|
||||
clusterSpec.Kubelet.KubeletCgroups = "/kubelet"
|
||||
clusterSpec.Kubelet.SystemCgroups = "/system"
|
||||
clusterSpec.Kubelet.CgroupRoot = "/"
|
||||
}
|
||||
|
||||
usesKubenet, err := UsesKubenet(clusterSpec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if usesKubenet {
|
||||
clusterSpec.Kubelet.NetworkPluginName = "kubenet"
|
||||
|
||||
if kubernetesVersion.Major == 1 && kubernetesVersion.Minor >= 4 {
|
||||
// AWS MTU is 9001
|
||||
clusterSpec.Kubelet.NetworkPluginMTU = fi.Int32(9001)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -31,7 +31,9 @@ type NetworkingOptionsBuilder struct {
|
|||
var _ loader.OptionsBuilder = &NetworkingOptionsBuilder{}
|
||||
|
||||
func (b *NetworkingOptionsBuilder) BuildOptions(o interface{}) error {
|
||||
k8sVersion, err := b.Context.KubernetesVersion()
|
||||
clusterSpec := o.(*kops.ClusterSpec)
|
||||
|
||||
k8sVersion, err := KubernetesVersion(clusterSpec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -41,7 +43,7 @@ func (b *NetworkingOptionsBuilder) BuildOptions(o interface{}) error {
|
|||
options.Kubelet = &kops.KubeletConfigSpec{}
|
||||
}
|
||||
|
||||
networking := b.Context.Cluster.Spec.Networking
|
||||
networking := clusterSpec.Networking
|
||||
if networking == nil {
|
||||
return fmt.Errorf("networking not set")
|
||||
}
|
||||
|
|
|
@ -25,11 +25,14 @@ import (
|
|||
|
||||
"k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/pkg/apis/kops/util"
|
||||
"k8s.io/kops/pkg/model/components"
|
||||
"net"
|
||||
)
|
||||
|
||||
type KopsModelContext struct {
|
||||
Cluster *kops.Cluster
|
||||
|
||||
Region string
|
||||
Cluster *kops.Cluster
|
||||
InstanceGroups []*kops.InstanceGroup
|
||||
|
||||
SSHPublicKeys [][]byte
|
||||
|
@ -223,3 +226,7 @@ func VersionGTE(version semver.Version, major uint64, minor uint64) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *KopsModelContext) WellKnownServiceIP(id int) (net.IP, error) {
|
||||
return components.WellKnownServiceIP(&c.Cluster.Spec, id)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
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 model
|
||||
|
||||
import (
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/fitasks"
|
||||
)
|
||||
|
||||
// PKIModelBuilder configures PKI keypairs
|
||||
type PKIModelBuilder struct {
|
||||
*KopsModelContext
|
||||
}
|
||||
|
||||
var _ fi.ModelBuilder = &PKIModelBuilder{}
|
||||
|
||||
func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
||||
{
|
||||
// Keypair used by the kubelet
|
||||
t := &fitasks.Keypair{
|
||||
Name: fi.String("kubelet"),
|
||||
Subject: "cn=kubelet",
|
||||
Type: "client",
|
||||
}
|
||||
c.AddTask(t)
|
||||
}
|
||||
|
||||
{
|
||||
// Keypair used for admin kubecfg
|
||||
t := &fitasks.Keypair{
|
||||
Name: fi.String("kubecfg"),
|
||||
Subject: "cn=kubecfg",
|
||||
Type: "client",
|
||||
}
|
||||
c.AddTask(t)
|
||||
}
|
||||
|
||||
{
|
||||
// Keypair used for apiserver
|
||||
|
||||
// A few names used from inside the cluster, which all resolve the same based on our default suffixes
|
||||
alternateNames := []string{
|
||||
"kubernetes",
|
||||
"kubernetes.default",
|
||||
"kubernetes.default.svc",
|
||||
"kubernetes.default.svc." + b.Cluster.Spec.ClusterDNSDomain,
|
||||
}
|
||||
|
||||
// Names specified in the cluster spec
|
||||
alternateNames = append(alternateNames, b.Cluster.Spec.MasterPublicName)
|
||||
alternateNames = append(alternateNames, b.Cluster.Spec.MasterInternalName)
|
||||
|
||||
// Referencing it by internal IP should work also
|
||||
{
|
||||
ip, err := b.WellKnownServiceIP(1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
alternateNames = append(alternateNames, ip.String())
|
||||
}
|
||||
|
||||
t := &fitasks.Keypair{
|
||||
Name: fi.String("master"),
|
||||
Subject: "cn=kubernetes-master",
|
||||
Type: "server",
|
||||
AlternateNames: alternateNames,
|
||||
}
|
||||
c.AddTask(t)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
keypair/kubecfg:
|
||||
subject: cn=kubecfg
|
||||
type: client
|
|
@ -1,3 +0,0 @@
|
|||
keypair/kubelet:
|
||||
subject: cn=kubelet
|
||||
type: client
|
|
@ -1,11 +0,0 @@
|
|||
keypair/master:
|
||||
subject: cn=kubernetes-master
|
||||
type: server
|
||||
alternateNames:
|
||||
- kubernetes
|
||||
- kubernetes.default
|
||||
- kubernetes.default.svc
|
||||
- kubernetes.default.svc.{{ .ClusterDNSDomain }}
|
||||
- "{{ .MasterPublicName }}"
|
||||
- "{{ .MasterInternalName }}"
|
||||
- "{{ WellKnownServiceIP 1 }}"
|
|
@ -1,6 +0,0 @@
|
|||
KubeDNS:
|
||||
Replicas: 2
|
||||
ServerIP: {{ WellKnownServiceIP 10 }}
|
||||
Domain: {{ .ClusterDNSDomain }}
|
||||
# TODO: Once we start shipping more images, start using them
|
||||
Image: gcr.io/google_containers/kubedns-amd64:1.3
|
|
@ -1,5 +0,0 @@
|
|||
Kubelet:
|
||||
CloudProvider: aws
|
||||
CgroupRoot: docker
|
||||
# Use the hostname from the AWS metadata service
|
||||
HostnameOverride: "@aws"
|
|
@ -1,7 +0,0 @@
|
|||
Kubelet:
|
||||
CloudProvider: gce
|
||||
HairpinMode: promiscuous-bridge
|
||||
RuntimeCgroups: /docker-daemon
|
||||
KubeletCgroups: /kubelet
|
||||
SystemCgroups: /system
|
||||
CgroupRoot: /
|
|
@ -1,8 +0,0 @@
|
|||
Kubelet:
|
||||
# AWS MTU is 9001
|
||||
NetworkPluginMTU: 9001
|
||||
|
||||
# TODO: Having to duplicate MasterKubelet & Kubelet feels wrong
|
||||
MasterKubelet:
|
||||
# AWS MTU is 9001
|
||||
NetworkPluginMTU: 9001
|
|
@ -1,8 +0,0 @@
|
|||
Kubelet:
|
||||
# AWS MTU is 9001
|
||||
NetworkPluginMTU: 9001
|
||||
|
||||
# TODO: Having to duplicate MasterKubelet & Kubelet feels wrong
|
||||
MasterKubelet:
|
||||
# AWS MTU is 9001
|
||||
NetworkPluginMTU: 9001
|
|
@ -1,2 +0,0 @@
|
|||
Kubelet:
|
||||
NetworkPluginName: kubenet
|
|
@ -1,18 +0,0 @@
|
|||
Kubelet:
|
||||
EnableDebuggingHandlers: true
|
||||
PodManifestPath: /etc/kubernetes/manifests
|
||||
AllowPrivileged: true
|
||||
LogLevel: 2
|
||||
ClusterDNS: {{ WellKnownServiceIP 10 }}
|
||||
ClusterDomain: {{ .ClusterDNSDomain }}
|
||||
BabysitDaemons: true
|
||||
APIServers: https://{{ .MasterInternalName }}
|
||||
NonMasqueradeCIDR: {{ .NonMasqueradeCIDR }}
|
||||
|
||||
MasterKubelet:
|
||||
RegisterSchedulable: false
|
||||
APIServers: http://127.0.0.1:8080
|
||||
# Replace the CIDR with a CIDR allocated by KCM (the default, but included for clarity)
|
||||
# We _do_ allow debugging handlers, so we can do logs
|
||||
# This does allow more access than we would like though
|
||||
EnableDebuggingHandlers: true
|
|
@ -1,6 +0,0 @@
|
|||
Multizone: true
|
||||
|
||||
ClusterDNSDomain: cluster.local
|
||||
|
||||
KubeUser: admin
|
||||
|
|
@ -378,6 +378,7 @@ func (c *ApplyClusterCmd) Run() error {
|
|||
&model.ExternalAccessModelBuilder{KopsModelContext: modelContext},
|
||||
&model.FirewallModelBuilder{KopsModelContext: modelContext},
|
||||
&model.IAMModelBuilder{KopsModelContext: modelContext},
|
||||
&model.PKIModelBuilder{KopsModelContext: modelContext},
|
||||
&model.MasterVolumeBuilder{KopsModelContext: modelContext},
|
||||
&model.NetworkModelBuilder{KopsModelContext: modelContext},
|
||||
&model.SSHKeyModelBuilder{KopsModelContext: modelContext},
|
||||
|
|
|
@ -254,17 +254,19 @@ func (c *populateClusterSpec) run() error {
|
|||
|
||||
tf.AddTo(templateFunctions)
|
||||
|
||||
optionsContext := &components.OptionsContext{
|
||||
Cluster: cluster,
|
||||
}
|
||||
optionsContext := &components.OptionsContext{}
|
||||
var fileModels []string
|
||||
var codeModels []loader.OptionsBuilder
|
||||
for _, m := range c.Models {
|
||||
switch m {
|
||||
case "config":
|
||||
// Note: DefaultOptionsBuilder comes first
|
||||
codeModels = append(codeModels, &components.DefaultsOptionsBuilder{Context: optionsContext})
|
||||
|
||||
codeModels = append(codeModels, &components.KubeAPIServerOptionsBuilder{Context: optionsContext})
|
||||
codeModels = append(codeModels, &components.DockerOptionsBuilder{Context: optionsContext})
|
||||
codeModels = append(codeModels, &components.NetworkingOptionsBuilder{Context: optionsContext})
|
||||
codeModels = append(codeModels, &components.KubeDnsOptionsBuilder{Context: optionsContext})
|
||||
codeModels = append(codeModels, &components.KubeletOptionsBuilder{Context: optionsContext})
|
||||
codeModels = append(codeModels, &components.KubeControllerManagerOptionsBuilder{Context: optionsContext})
|
||||
fileModels = append(fileModels, m)
|
||||
|
|
|
@ -29,15 +29,12 @@ package cloudup
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
api "k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/pkg/model"
|
||||
"k8s.io/kops/util/pkg/vfs"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
"math/big"
|
||||
"net"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
@ -52,38 +49,6 @@ type TemplateFunctions struct {
|
|||
modelContext *model.KopsModelContext
|
||||
}
|
||||
|
||||
func (tf *TemplateFunctions) WellKnownServiceIP(id int) (net.IP, error) {
|
||||
_, cidr, err := net.ParseCIDR(tf.cluster.Spec.ServiceClusterIPRange)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing ServiceClusterIPRange %q: %v", tf.cluster.Spec.ServiceClusterIPRange, err)
|
||||
}
|
||||
|
||||
ip4 := cidr.IP.To4()
|
||||
if ip4 != nil {
|
||||
n := binary.BigEndian.Uint32(ip4)
|
||||
n += uint32(id)
|
||||
serviceIP := make(net.IP, len(ip4))
|
||||
binary.BigEndian.PutUint32(serviceIP, n)
|
||||
return serviceIP, nil
|
||||
}
|
||||
|
||||
ip6 := cidr.IP.To16()
|
||||
if ip6 != nil {
|
||||
baseIPInt := big.NewInt(0)
|
||||
baseIPInt.SetBytes(ip6)
|
||||
serviceIPInt := big.NewInt(0)
|
||||
serviceIPInt.Add(big.NewInt(int64(id)), baseIPInt)
|
||||
serviceIP := make(net.IP, len(ip6))
|
||||
serviceIPBytes := serviceIPInt.Bytes()
|
||||
for i := range serviceIPBytes {
|
||||
serviceIP[len(serviceIP)-len(serviceIPBytes)+i] = serviceIPBytes[i]
|
||||
}
|
||||
return serviceIP, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Unexpected IP address type for ServiceClusterIPRange: %s", tf.cluster.Spec.ServiceClusterIPRange)
|
||||
}
|
||||
|
||||
// This will define the available functions we can use in our YAML models
|
||||
// If we are trying to get a new function implemented it MUST
|
||||
// be defined here.
|
||||
|
@ -96,8 +61,6 @@ func (tf *TemplateFunctions) AddTo(dest template.FuncMap) {
|
|||
// Network topology definitions
|
||||
dest["GetELBName32"] = tf.modelContext.GetELBName32
|
||||
|
||||
dest["WellKnownServiceIP"] = tf.WellKnownServiceIP
|
||||
|
||||
dest["Base64Encode"] = func(s string) string {
|
||||
return base64.StdEncoding.EncodeToString([]byte(s))
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ type Keypair struct {
|
|||
}
|
||||
|
||||
var _ fi.HasCheckExisting = &Keypair{}
|
||||
var _ fi.HasName = &Keypair{}
|
||||
|
||||
// It's important always to check for the existing key, so we don't regenerate keys e.g. on terraform
|
||||
func (e *Keypair) CheckExisting(c *fi.Context) bool {
|
||||
|
|
Loading…
Reference in New Issue