Skip to content
This repository has been archived by the owner on Sep 30, 2020. It is now read-only.

Create etcd and workers in private subnets, controllers in public subnet #169

Merged
merged 20 commits into from
Jan 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d04a698
first pass at public private network topology
icereval Dec 27, 2016
7d93778
use function for logical name and refs
icereval Dec 27, 2016
57f57a0
define subnets in cluster, code review updates
icereval Dec 28, 2016
3137b09
simplify route tables, add node pool private logic
icereval Dec 29, 2016
e8fab45
workers private subnet and controller elb subnet selection
neoandroid Dec 29, 2016
096bd5c
fix tests
neoandroid Dec 29, 2016
3e8d431
fix go format
neoandroid Dec 30, 2016
fb99a1f
create nat gateways when workers are private yet somehow etcd & contr…
neoandroid Dec 31, 2016
e4db361
private worker efs mount targets
icereval Dec 31, 2016
6c5f04f
Merge pull request #2 from icereval/feature/private-worker-efs
neoandroid Dec 31, 2016
ce9f075
fix parameter comment
neoandroid Jan 3, 2017
34024ed
Merge branch 'master' into masters-private-subnet
neoandroid Jan 10, 2017
83dc882
remove duplicated code introduced by private subnets from cfn templates
neoandroid Jan 10, 2017
03d19fe
remove AvailabilityZones property from cfn template because its redun…
neoandroid Jan 11, 2017
a601020
Merge branch 'master' into masters-private-subnet
neoandroid Jan 11, 2017
70d791c
fix wrong variable type
neoandroid Jan 17, 2017
08a45e7
Merge branch 'master' into masters-private-subnet
neoandroid Jan 17, 2017
6dce8c8
Merge branch 'master' into masters-private-subnet
neoandroid Jan 19, 2017
0c0060b
fix format
neoandroid Jan 19, 2017
b379650
refactor private subnet support to improve stability and maintainability
neoandroid Jan 20, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/nodepool/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func runCmdUp(cmd *cobra.Command, args []string) error {
return fmt.Errorf("Failed to validate user data: %v", err)
}

data, err := conf.RenderStackTemplate(stackTemplateOptions(), upOpts.export)
data, err := conf.RenderStackTemplate(stackTemplateOptions(), upOpts.prettyPrint)
if err != nil {
return fmt.Errorf("Failed to render stack template: %v", err)
}
Expand Down
140 changes: 88 additions & 52 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ func NewDefaultCluster() *Cluster {
AWSCliImageRepo: "quay.io/coreos/awscli",
AWSCliTag: "master",
ContainerRuntime: "docker",
Subnets: []*Subnet{},
Subnets: []*model.Subnet{},
EIPAllocationIDs: []string{},
MapPublicIPs: true,
Experimental: experimental,
ManageCertificates: true,
Expand Down Expand Up @@ -171,14 +172,19 @@ func ClusterFromBytes(data []byte) (*Cluster, error) {

// For backward-compatibility
if len(c.Subnets) == 0 {
c.Subnets = []*Subnet{
c.Subnets = []*model.Subnet{
{
AvailabilityZone: c.AvailabilityZone,
InstanceCIDR: c.InstanceCIDR,
},
}
}

// Mark top-level subnets appropriately
for _, subnet := range c.Subnets {
subnet.TopLevel = true
}

return c, nil
}

Expand Down Expand Up @@ -210,14 +216,15 @@ type ComputedDeploymentSettings struct {
// Though it is highly configurable, it's basically users' responsibility to provide `correct` values if they're going beyond the defaults.
type DeploymentSettings struct {
ComputedDeploymentSettings
ClusterName string `yaml:"clusterName,omitempty"`
KeyName string `yaml:"keyName,omitempty"`
Region string `yaml:"region,omitempty"`
AvailabilityZone string `yaml:"availabilityZone,omitempty"`
ReleaseChannel string `yaml:"releaseChannel,omitempty"`
AmiId string `yaml:"amiId,omitempty"`
VPCID string `yaml:"vpcId,omitempty"`
RouteTableID string `yaml:"routeTableId,omitempty"`
ClusterName string `yaml:"clusterName,omitempty"`
KeyName string `yaml:"keyName,omitempty"`
Region string `yaml:"region,omitempty"`
AvailabilityZone string `yaml:"availabilityZone,omitempty"`
ReleaseChannel string `yaml:"releaseChannel,omitempty"`
AmiId string `yaml:"amiId,omitempty"`
VPCID string `yaml:"vpcId,omitempty"`
InternetGatewayID string `yaml:"internetGatewayId,omitempty"`
RouteTableID string `yaml:"routeTableId,omitempty"`
// Required for validations like e.g. if instance cidr is contained in vpc cidr
VPCCIDR string `yaml:"vpcCIDR,omitempty"`
InstanceCIDR string `yaml:"instanceCIDR,omitempty"`
Expand All @@ -228,7 +235,8 @@ type DeploymentSettings struct {
ContainerRuntime string `yaml:"containerRuntime,omitempty"`
KMSKeyARN string `yaml:"kmsKeyArn,omitempty"`
StackTags map[string]string `yaml:"stackTags,omitempty"`
Subnets []*Subnet `yaml:"subnets,omitempty"`
Subnets []*model.Subnet `yaml:"subnets,omitempty"`
EIPAllocationIDs []string `yaml:"eipAllocationIDs,omitempty"`
MapPublicIPs bool `yaml:"mapPublicIPs,omitempty"`
ElasticFileSystemID string `yaml:"elasticFileSystemId,omitempty"`
SSHAuthorizedKeys []string `yaml:"sshAuthorizedKeys,omitempty"`
Expand All @@ -248,22 +256,25 @@ type WorkerSettings struct {
WorkerSpotPrice string `yaml:"workerSpotPrice,omitempty"`
WorkerSecurityGroupIds []string `yaml:"workerSecurityGroupIds,omitempty"`
WorkerTenancy string `yaml:"workerTenancy,omitempty"`
WorkerTopologyPrivate bool `yaml:"workerTopologyPrivate,omitempty"`
}

// Part of configuration which is specific to controller nodes
type ControllerSettings struct {
model.Controller `yaml:"controller,omitempty"`
ControllerCount int `yaml:"controllerCount,omitempty"`
ControllerCreateTimeout string `yaml:"controllerCreateTimeout,omitempty"`
ControllerInstanceType string `yaml:"controllerInstanceType,omitempty"`
ControllerRootVolumeType string `yaml:"controllerRootVolumeType,omitempty"`
ControllerRootVolumeIOPS int `yaml:"controllerRootVolumeIOPS,omitempty"`
ControllerRootVolumeSize int `yaml:"controllerRootVolumeSize,omitempty"`
ControllerTenancy string `yaml:"controllerTenancy,omitempty"`
model.Controller `yaml:"controller,omitempty"`
ControllerCount int `yaml:"controllerCount,omitempty"`
ControllerCreateTimeout string `yaml:"controllerCreateTimeout,omitempty"`
ControllerInstanceType string `yaml:"controllerInstanceType,omitempty"`
ControllerLoadBalancerPrivate bool `yaml:"controllerLoadBalancerPrivate,omitempty"`
ControllerRootVolumeType string `yaml:"controllerRootVolumeType,omitempty"`
ControllerRootVolumeIOPS int `yaml:"controllerRootVolumeIOPS,omitempty"`
ControllerRootVolumeSize int `yaml:"controllerRootVolumeSize,omitempty"`
ControllerTenancy string `yaml:"controllerTenancy,omitempty"`
}

// Part of configuration which is specific to etcd nodes
type EtcdSettings struct {
model.Etcd `yaml:"etcd,omitempty"`
EtcdCount int `yaml:"etcdCount"`
EtcdInstanceType string `yaml:"etcdInstanceType,omitempty"`
EtcdRootVolumeSize int `yaml:"etcdRootVolumeSize,omitempty"`
Expand Down Expand Up @@ -299,12 +310,6 @@ type Cluster struct {
CustomSettings map[string]interface{} `yaml:"customSettings,omitempty"`
}

type Subnet struct {
AvailabilityZone string `yaml:"availabilityZone,omitempty"`
InstanceCIDR string `yaml:"instanceCIDR,omitempty"`
lastAllocatedAddr *net.IP
}

type Experimental struct {
AuditLog AuditLog `yaml:"auditLog"`
AwsEnvironment AwsEnvironment `yaml:"awsEnvironment"`
Expand Down Expand Up @@ -388,7 +393,8 @@ type WaitSignal struct {
}

const (
vpcLogicalName = "VPC"
vpcLogicalName = "VPC"
internetGatewayLogicalName = "InternetGateway"
)

var supportedReleaseChannels = map[string]bool{
Expand Down Expand Up @@ -477,27 +483,19 @@ func (c Cluster) Config() (*Config, error) {
config.AMI = c.AmiId
}

//Set logical name constants
config.VPCLogicalName = vpcLogicalName

//Set reference strings

//Assume VPC does not exist, reference by logical name
config.VPCRef = fmt.Sprintf(`{ "Ref" : %q }`, config.VPCLogicalName)
if config.VPCID != "" {
//This means this VPC already exists, and we can reference it directly by ID
config.VPCRef = fmt.Sprintf("%q", config.VPCID)
}

config.EtcdInstances = make([]model.EtcdInstance, config.EtcdCount)

for etcdIndex := 0; etcdIndex < config.EtcdCount; etcdIndex++ {

//Round-robbin etcd instances across all available subnets
subnetIndex := etcdIndex % len(config.Subnets)
subnet := *config.Subnets[subnetIndex]
if config.Etcd.TopologyPrivate() {
subnet = *config.Etcd.Subnets[subnetIndex]
}

instance := model.EtcdInstance{
SubnetIndex: subnetIndex,
Subnet: subnet,
}

config.EtcdInstances[etcdIndex] = instance
Expand All @@ -506,6 +504,21 @@ func (c Cluster) Config() (*Config, error) {

}

// Populate top-level subnets to model
if len(config.Subnets) > 0 {
if config.WorkerSettings.MinWorkerCount() > 0 && config.WorkerSettings.TopologyPrivate() == false {
config.WorkerSettings.Subnets = config.Subnets
}
if config.ControllerSettings.MinControllerCount() > 0 && config.ControllerSettings.TopologyPrivate() == false {
config.ControllerSettings.Subnets = config.Subnets
}
}
config.ControllerElb.Private = config.ControllerSettings.ControllerLoadBalancerPrivate
config.ControllerElb.Subnets = config.Subnets
if config.ControllerElb.Private == true {
config.ControllerElb.Subnets = config.ControllerSettings.Subnets
}

config.IsChinaRegion = strings.HasPrefix(config.Region, "cn")

return &config, nil
Expand Down Expand Up @@ -620,16 +633,11 @@ func (c Cluster) RenderStackTemplate(opts StackTemplateOptions, prettyPrint bool
type Config struct {
Cluster

ControllerElb model.ControllerElb
EtcdInstances []model.EtcdInstance

// Encoded TLS assets
TLSConfig *CompactTLSAssets

//Logical names of dynamic resources
VPCLogicalName string

//Reference strings for dynamic resources
VPCRef string
}

// CloudFormation stack name which is unique in an AWS account.
Expand All @@ -638,6 +646,30 @@ func (c Cluster) StackName() string {
return c.ClusterName
}

func (c Config) VPCLogicalName() string {
return vpcLogicalName
}

func (c Config) VPCRef() string {
if c.VPCID != "" {
return fmt.Sprintf("%q", c.VPCID)
} else {
return fmt.Sprintf(`{ "Ref" : %q }`, c.VPCLogicalName())
}
}

func (c Config) InternetGatewayLogicalName() string {
return internetGatewayLogicalName
}

func (c Config) InternetGatewayRef() string {
if c.InternetGatewayID != "" {
return fmt.Sprintf("%q", c.InternetGatewayID)
} else {
return fmt.Sprintf(`{ "Ref" : %q }`, c.InternetGatewayLogicalName())
}
}

func (c Cluster) valid() error {
if c.CreateRecordSet {
if c.HostedZone == "" && c.HostedZoneID == "" {
Expand Down Expand Up @@ -776,8 +808,8 @@ func (c DeploymentSettings) Valid() (*DeploymentValidationResult, error) {
return nil, errors.New("kmsKeyArn must be set")
}

if c.VPCID == "" && c.RouteTableID != "" {
return nil, errors.New("vpcId must be specified if routeTableId is specified")
if c.VPCID == "" && (c.RouteTableID != "" || c.InternetGatewayID != "") {
return nil, errors.New("vpcId must be specified if routeTableId or internetGatewayId are specified")
}

if c.Region == "" {
Expand Down Expand Up @@ -922,12 +954,16 @@ func (c *Cluster) AvailabilityZones() []string {
return []string{c.AvailabilityZone}
}

azs := make([]string, len(c.Subnets))
for i := range azs {
azs[i] = c.Subnets[i].AvailabilityZone
result := []string{}
seen := map[string]bool{}
for _, s := range c.Subnets {
val := s.AvailabilityZone
if _, ok := seen[val]; !ok {
result = append(result, val)
seen[val] = true
}
}

return azs
return result
}

/*
Expand Down
Loading