Merge pull request #3248 from andrewsykim/do

Automatic merge from submit-queue

Create cluster requirements for DigitalOcean

Initial changes required to create a cluster state. Running `kops update cluster --yes` does not work yet. 

Note that DO has already adopted cloud controller managers (https://github.com/digitalocean/digitalocean-cloud-controller-manager) so we set `--cloud-provider=external`. This will end up being the case for aws, gce and vsphere over the next couple of releases. 

https://github.com/kubernetes/kops/issues/2150

```bash
$ kops create cluster --cloud=digitalocean --name=dev.asykim.com --zones=tor1
I0821 18:47:06.302218   28623 create_cluster.go:845] Using SSH public key: /Users/AndrewSyKim/.ssh/id_rsa.pub
I0821 18:47:06.302293   28623 subnets.go:183] Assigned CIDR 172.20.32.0/19 to subnet tor1
Previewing changes that will be made:

I0821 18:47:11.457696   28623 executor.go:91] Tasks: 0 done / 27 total; 27 can run
I0821 18:47:12.113133   28623 executor.go:91] Tasks: 27 done / 27 total; 0 can run
Will create resources:
  Keypair/kops
  	Subject             	o=system:masters,cn=kops
  	Type                	client

  Keypair/kube-controller-manager
  	Subject             	cn=system:kube-controller-manager
  	Type                	client

  Keypair/kube-proxy
  	Subject             	cn=system:kube-proxy
  	Type                	client

  Keypair/kube-scheduler
  	Subject             	cn=system:kube-scheduler
  	Type                	client

  Keypair/kubecfg
  	Subject             	o=system:masters,cn=kubecfg
  	Type                	client

  Keypair/kubelet
  	Subject             	o=system:nodes,cn=kubelet
  	Type                	client

  Keypair/kubelet-api
  	Subject             	cn=kubelet-api
  	Type                	client

  Keypair/master
  	Subject             	cn=kubernetes-master
  	Type                	server
  	AlternateNames      	[100.64.0.1, 127.0.0.1, api.dev.asykim.com, api.internal.dev.asykim.com, kubernetes, kubernetes.default, kubernetes.default.svc, kubernetes.default.svc.cluster.local]

  ManagedFile/dev.asykim.com-addons-bootstrap
  	Location            	addons/bootstrap-channel.yaml

  ManagedFile/dev.asykim.com-addons-core.addons.k8s.io
  	Location            	addons/core.addons.k8s.io/v1.4.0.yaml

  ManagedFile/dev.asykim.com-addons-dns-controller.addons.k8s.io-k8s-1.6
  	Location            	addons/dns-controller.addons.k8s.io/k8s-1.6.yaml

  ManagedFile/dev.asykim.com-addons-dns-controller.addons.k8s.io-pre-k8s-1.6
  	Location            	addons/dns-controller.addons.k8s.io/pre-k8s-1.6.yaml

  ManagedFile/dev.asykim.com-addons-kube-dns.addons.k8s.io-k8s-1.6
  	Location            	addons/kube-dns.addons.k8s.io/k8s-1.6.yaml

  ManagedFile/dev.asykim.com-addons-kube-dns.addons.k8s.io-pre-k8s-1.6
  	Location            	addons/kube-dns.addons.k8s.io/pre-k8s-1.6.yaml

  ManagedFile/dev.asykim.com-addons-limit-range.addons.k8s.io
  	Location            	addons/limit-range.addons.k8s.io/v1.5.0.yaml

  ManagedFile/dev.asykim.com-addons-storage-aws.addons.k8s.io
  	Location            	addons/storage-aws.addons.k8s.io/v1.6.0.yaml

  Secret/admin

  Secret/kube

  Secret/kube-proxy

  Secret/kubelet

  Secret/system:controller_manager

  Secret/system:dns

  Secret/system:logging

  Secret/system:monitoring

  Secret/system:scheduler

Must specify --yes to apply changes

Cluster configuration has been created.

Suggestions:
 * list clusters with: kops get cluster
 * edit this cluster with: kops edit cluster dev.asykim.com
 * edit your node instance group: kops edit ig --name=dev.asykim.com nodes
 * edit your master instance group: kops edit ig --name=dev.asykim.com master-tor1

Finally configure your cluster with: kops update cluster dev.asykim.com --yes
```
This commit is contained in:
Kubernetes Submit Queue 2017-08-22 18:41:10 -07:00 committed by GitHub
commit 7a2ff89d77
12 changed files with 78 additions and 8 deletions

View File

@ -136,8 +136,8 @@ codegen: kops-gobindata
go install k8s.io/kops/upup/tools/generators/...
PATH=${GOPATH_1ST}/bin:${PATH} go generate k8s.io/kops/upup/pkg/fi/cloudup/awstasks
PATH=${GOPATH_1ST}/bin:${PATH} go generate k8s.io/kops/upup/pkg/fi/cloudup/gcetasks
PATH=${GOPATH_1ST}/bin:${PATH} go generate k8s.io/kops/upup/pkg/fi/assettasks
PATH=${GOPATH_1ST}/bin:${PATH} go generate k8s.io/kops/upup/pkg/fi/cloudup/dotasks
PATH=${GOPATH_1ST}/bin:${PATH} go generate k8s.io/kops/upup/pkg/fi/assettasks
PATH=${GOPATH_1ST}/bin:${PATH} go generate k8s.io/kops/upup/pkg/fi/fitasks
.PHONY: protobuf

View File

@ -215,22 +215,22 @@ func ValidateCluster(c *kops.Cluster, strict bool) *field.Error {
return field.Required(fieldSpec.Child("CloudProvider"), "")
}
if c.Spec.Kubelet != nil && (strict || c.Spec.Kubelet.CloudProvider != "") {
if cloudProvider != c.Spec.Kubelet.CloudProvider {
if cloudProvider != c.Spec.Kubelet.CloudProvider && c.Spec.Kubelet.CloudProvider != "external" {
return field.Invalid(fieldSpec.Child("Kubelet", "CloudProvider"), c.Spec.Kubelet.CloudProvider, "Did not match cluster CloudProvider")
}
}
if c.Spec.MasterKubelet != nil && (strict || c.Spec.MasterKubelet.CloudProvider != "") {
if cloudProvider != c.Spec.MasterKubelet.CloudProvider {
if cloudProvider != c.Spec.MasterKubelet.CloudProvider && c.Spec.MasterKubelet.CloudProvider != "external" {
return field.Invalid(fieldSpec.Child("MasterKubelet", "CloudProvider"), c.Spec.MasterKubelet.CloudProvider, "Did not match cluster CloudProvider")
}
}
if c.Spec.KubeAPIServer != nil && (strict || c.Spec.KubeAPIServer.CloudProvider != "") {
if cloudProvider != c.Spec.KubeAPIServer.CloudProvider {
if cloudProvider != c.Spec.KubeAPIServer.CloudProvider && c.Spec.KubeAPIServer.CloudProvider != "external" {
return field.Invalid(fieldSpec.Child("KubeAPIServer", "CloudProvider"), c.Spec.KubeAPIServer.CloudProvider, "Did not match cluster CloudProvider")
}
}
if c.Spec.KubeControllerManager != nil && (strict || c.Spec.KubeControllerManager.CloudProvider != "") {
if cloudProvider != c.Spec.KubeControllerManager.CloudProvider {
if cloudProvider != c.Spec.KubeControllerManager.CloudProvider && c.Spec.KubeControllerManager.CloudProvider != "external" {
return field.Invalid(fieldSpec.Child("KubeControllerManager", "CloudProvider"), c.Spec.KubeControllerManager.CloudProvider, "Did not match cluster CloudProvider")
}
}

View File

@ -104,6 +104,9 @@ func (b *KubeControllerManagerOptionsBuilder) BuildOptions(o interface{}) error
kcm.CloudProvider = "gce"
kcm.ClusterName = gce.SafeClusterName(b.Context.ClusterName)
case kops.CloudProviderDO:
kcm.CloudProvider = "external"
case kops.CloudProviderVSphere:
kcm.CloudProvider = "vsphere"

View File

@ -151,6 +151,10 @@ func (b *KubeletOptionsBuilder) BuildOptions(o interface{}) error {
clusterSpec.Kubelet.HostnameOverride = "@aws"
}
if cloudProvider == kops.CloudProviderDO {
clusterSpec.Kubelet.CloudProvider = "external"
}
if cloudProvider == kops.CloudProviderGCE {
clusterSpec.Kubelet.CloudProvider = "gce"
clusterSpec.Kubelet.HairpinMode = "promiscuous-bridge"

View File

@ -141,6 +141,14 @@ func (b *MasterVolumeBuilder) addAWSVolume(c *fi.ModelBuilderContext, name strin
}
func (b *MasterVolumeBuilder) addDOVolume(c *fi.ModelBuilderContext, name string, volumeSize int32, subnet *kops.ClusterSubnetSpec, etcd *kops.EtcdClusterSpec, m *kops.EtcdMemberSpec, allMembers []string) {
// required that names start with a lower case and only contains letters, numbers and hyphens
name = "kops-" + strings.Replace(name, ".", "-", -1)
// DO has a 64 character limit for volume names
if len(name) >= 64 {
name = name[:64]
}
t := &dotasks.Volume{
Name: s(name),
Lifecycle: b.Lifecycle,

View File

@ -69,6 +69,8 @@ func (c *ClusterResources) ListResources() (map[string]*ResourceTracker, error)
switch c.Cloud.ProviderID() {
case kops.CloudProviderAWS:
return c.listResourcesAWS()
case kops.CloudProviderDO:
return c.listResourcesDO()
case kops.CloudProviderGCE:
return c.listResourcesGCE()
case kops.CloudProviderVSphere:

21
pkg/resources/do.go Normal file
View File

@ -0,0 +1,21 @@
/*
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 resources
func (c *ClusterResources) listResourcesDO() (map[string]*ResourceTracker, error) {
return nil, nil
}

View File

@ -0,0 +1,2 @@
KubeAPIServer:
CloudProvider: external

View File

@ -335,7 +335,6 @@ func (c *ApplyClusterCmd) Run() error {
return fmt.Errorf("DigitalOcean support is currently (very) alpha and is feature-gated. export KOPS_FEATURE_FLAGS=AlphaAllowDO to enable it")
}
// this is a no-op for now, add tasks to this list as more DO support is added
l.AddTypes(map[string]interface{}{
"volume": &dotasks.Volume{},
})
@ -649,7 +648,8 @@ func (c *ApplyClusterCmd) Run() error {
BootstrapScript: bootstrapScriptBuilder,
Lifecycle: clusterLifecycle,
})
case kops.CloudProviderDO:
// DigitalOcean tasks will go here
case kops.CloudProviderGCE:
{
gceModelContext := &gcemodel.GCEModelContext{

View File

@ -33,14 +33,17 @@ import (
const (
defaultNodeMachineTypeGCE = "n1-standard-2"
defaultNodeMachineTypeVSphere = "vsphere_node"
defaultNodeMachineTypeDO = "2gb"
defaultBastionMachineTypeGCE = "f1-micro"
defaultBastionMachineTypeVSphere = "vsphere_bastion"
defaultMasterMachineTypeGCE = "n1-standard-1"
defaultMasterMachineTypeVSphere = "vsphere_master"
defaultMasterMachineTypeDO = "2gb"
defaultVSphereNodeImage = "kops_ubuntu_16_04.ova"
defaultDONodeImage = "coreos-stable"
)
var awsDedicatedInstanceExceptions = map[string]bool{
@ -177,6 +180,16 @@ func defaultMachineType(cluster *kops.Cluster, ig *kops.InstanceGroup) (string,
return defaultBastionMachineTypeGCE, nil
}
case kops.CloudProviderDO:
switch ig.Spec.Role {
case kops.InstanceGroupRoleMaster:
return defaultMasterMachineTypeDO, nil
case kops.InstanceGroupRoleNode:
return defaultNodeMachineTypeDO, nil
}
case kops.CloudProviderVSphere:
switch ig.Spec.Role {
case kops.InstanceGroupRoleMaster:
@ -211,9 +224,15 @@ func defaultImage(cluster *kops.Cluster, channel *kops.Channel) string {
return image.Name
}
}
} else if kops.CloudProviderID(cluster.Spec.CloudProvider) == kops.CloudProviderVSphere {
}
switch kops.CloudProviderID(cluster.Spec.CloudProvider) {
case kops.CloudProviderDO:
return defaultDONodeImage
case kops.CloudProviderVSphere:
return defaultVSphereNodeImage
}
glog.Infof("Cannot set default Image for CloudProvider=%q", cluster.Spec.CloudProvider)
return ""
}

View File

@ -66,6 +66,10 @@ func buildCloudupTags(cluster *api.Cluster) (sets.String, error) {
{
tags.Insert("_aws")
}
case "digitalocean":
{
tags.Insert("_do")
}
case "vsphere":
{
tags.Insert("_vsphere")
@ -147,6 +151,9 @@ func buildNodeupTags(role api.InstanceGroupRole, cluster *api.Cluster, clusterTa
if clusterTags.Has("_aws") {
tags.Insert("_aws")
}
if clusterTags.Has("_do") {
tags.Insert("_do")
}
return tags, nil
}

View File

@ -149,6 +149,10 @@ func (tf *TemplateFunctions) DnsControllerArgv() ([]string, error) {
}
case kops.CloudProviderGCE:
argv = append(argv, "--dns=google-clouddns")
case kops.CloudProviderDO:
// this is not supported yet, here so we can successfully create clusters
// this will be supported for digitalocean in the future
argv = append(argv, "--dns=digitalocean")
case kops.CloudProviderVSphere:
argv = append(argv, "--dns=coredns")
argv = append(argv, "--dns-server="+*tf.cluster.Spec.CloudConfig.VSphereCoreDNSServer)