Skip to content

Commit 7240f8f

Browse files
committed
Adds optional Fargate-based build tasks
Allows switching build tasks between EC2 and Fargate to enhance flexibility.
1 parent b5f444a commit 7240f8f

File tree

2 files changed

+132
-19
lines changed

2 files changed

+132
-19
lines changed

provider/aws/builds.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,75 @@ func (p *Provider) authECR(host, access, secret string) (string, string, error)
790790
return parts[0], parts[1], nil
791791
}
792792

793+
// Helper function to prepare launch configuration
794+
func (p *Provider) prepareLaunchConfiguration() (*string, *ecs.NetworkConfiguration, error) {
795+
stackFargateBuild, err := p.stackParameter(p.Rack, "FargateBuild")
796+
if err != nil {
797+
return nil, nil, err
798+
}
799+
800+
if stackFargateBuild != "Yes" {
801+
return aws.String("EC2"), nil, nil
802+
}
803+
804+
// Fetch subnets and security groups
805+
subnets, err := p.fetchSubnets()
806+
if err != nil {
807+
return nil, nil, err
808+
}
809+
secGroups, err := p.fetchSecurityGroups()
810+
if err != nil {
811+
return nil, nil, err
812+
}
813+
814+
// Configure Fargate-specific network settings
815+
nc := &ecs.NetworkConfiguration{
816+
AwsvpcConfiguration: &ecs.AwsVpcConfiguration{
817+
Subnets: subnets,
818+
SecurityGroups: secGroups,
819+
},
820+
}
821+
822+
return aws.String("FARGATE"), nc, nil
823+
}
824+
825+
// Helper function to fetch subnets
826+
func (p *Provider) fetchSubnets() ([]*string, error) {
827+
subnets := []*string{}
828+
for _, subnet := range []string{"Subnet0", "Subnet1", "SubnetPrivate0", "SubnetPrivate1"} {
829+
res, _ := p.stackResource(p.Rack, subnet)
830+
if res != nil && res.PhysicalResourceId != nil {
831+
subnets = append(subnets, res.PhysicalResourceId)
832+
}
833+
}
834+
835+
if len(subnets) == 0 {
836+
return nil, fmt.Errorf("no subnets found for Fargate")
837+
}
838+
839+
return subnets, nil
840+
}
841+
842+
// Helper function to fetch security groups
843+
func (p *Provider) fetchSecurityGroups() ([]*string, error) {
844+
biSecGroup, _ := p.stackParameter(p.Rack, "BuildInstanceSecurityGroup")
845+
if biSecGroup != "" {
846+
return []*string{aws.String(biSecGroup)}, nil
847+
}
848+
849+
iSecGroup, _ := p.stackParameter(p.Rack, "InstanceSecurityGroup")
850+
if iSecGroup != "" {
851+
return []*string{aws.String(iSecGroup)}, nil
852+
}
853+
854+
is, _ := p.stackResource(p.Rack, "InstancesSecurity")
855+
if is != nil && is.PhysicalResourceId != nil {
856+
return []*string{is.PhysicalResourceId}, nil
857+
}
858+
859+
return nil, fmt.Errorf("no security groups found for Fargate")
860+
}
861+
793862
func (p *Provider) runBuild(build *structs.Build, burl string, opts structs.BuildCreateOptions) error {
794863
log := Logger.At("runBuild").Namespace("url=%q", burl).Start()
795864

@@ -864,11 +933,19 @@ func (p *Provider) runBuild(build *structs.Build, burl string, opts structs.Buil
864933
}
865934
}
866935

936+
// Determine launch type and network configuration
937+
launchType, nc, err := p.prepareLaunchConfiguration()
938+
if err != nil {
939+
Logger.Error(err)
940+
return err
941+
}
942+
867943
req := &ecs.RunTaskInput{
868944
Cluster: aws.String(p.BuildCluster),
869945
Count: aws.Int64(1),
870946
StartedBy: aws.String(fmt.Sprintf("convox.%s", build.App)),
871947
TaskDefinition: aws.String(td),
948+
LaunchType: launchType,
872949
Overrides: &ecs.TaskOverride{
873950
ContainerOverrides: []*ecs.ContainerOverride{
874951
{
@@ -928,6 +1005,9 @@ func (p *Provider) runBuild(build *structs.Build, burl string, opts structs.Buil
9281005
},
9291006
},
9301007
}
1008+
if nc.AwsvpcConfiguration != nil {
1009+
req.NetworkConfiguration = nc
1010+
}
9311011

9321012
task, err := p.runTask(req)
9331013
if err != nil {

provider/aws/formation/rack.json

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,17 @@
4646
"ExistingVpcAndInternetGateway": {
4747
"Fn::And": [ { "Condition": "ExistingVpc" }, { "Condition": "InternetGateway" } ]
4848
},
49+
"BuildUsingFargate": {
50+
"Fn::And": [
51+
{
52+
"Fn::Equals": [
53+
{ "Fn::FindInMap": [ "RegionConfig", { "Ref": "AWS::Region" }, "Fargate" ] },
54+
"Yes"
55+
]
56+
},
57+
{ "Fn::Equals": [ { "Ref": "FargateBuild" }, "Yes" ] }
58+
]
59+
},
4960
"HighAvailability": { "Fn::Equals": [ { "Ref": "HighAvailability" }, "true" ] },
5061
"HttpProxy": { "Fn::Not": [ { "Fn::Equals": [ { "Ref": "HttpProxy" }, "" ] } ] },
5162
"InstanceARM": {
@@ -433,7 +444,7 @@
433444
"Value": { "Ref": "AWS::StackName" }
434445
},
435446
"RackDomain": {
436-
"Value": {
447+
"Value": {
437448
"Fn::Join": [ ".", [
438449
"rack",
439450
{ "Fn::Select": [ 0, { "Fn::Split": [ ".", { "Fn::GetAtt": [ "ApiBalancer", "DNSName" ] } ] } ] },
@@ -765,6 +776,12 @@
765776
"Default": "false",
766777
"AllowedValues": [ "true", "false" ]
767778
},
779+
"FargateBuild": {
780+
"Type": "String",
781+
"Description": "Use Fargate for build instances",
782+
"Default": "No",
783+
"AllowedValues": [ "Yes", "No" ]
784+
},
768785
"NoHaInstanceCount": {
769786
"Default": "1",
770787
"Description": "The number of instances in the runtime cluster for no HighAvailable racks",
@@ -3000,7 +3017,7 @@
30003017
{ "Key": "Name", "Value": { "Ref": "AWS::StackName" }},
30013018
{ "Key": "Rack", "Value": { "Ref": "AWS::StackName" }},
30023019
{ "Key": "GatewayAttachment", "Value": { "Fn::If": [ "ExistingVpc", "existing",{ "Ref": "GatewayAttachment"}]}},
3003-
{ "Key": "NatGateways", "Value": { "Fn::If":
3020+
{ "Key": "NatGateways", "Value": { "Fn::If":
30043021
[ "PrivateInstances",
30053022
{
30063023
"Fn::Join": [
@@ -3262,7 +3279,7 @@
32623279
{ "Key": "Name", "Value": { "Ref": "AWS::StackName" }},
32633280
{ "Key": "Rack", "Value": { "Ref": "AWS::StackName" }},
32643281
{ "Key": "GatewayAttachment", "Value": { "Fn::If": [ "ExistingVpc", "existing",{ "Ref": "GatewayAttachment"}]}},
3265-
{ "Key": "NatGateways", "Value": { "Fn::If":
3282+
{ "Key": "NatGateways", "Value": { "Fn::If":
32663283
[ "PrivateInstances",
32673284
{
32683285
"Fn::Join": [
@@ -3968,17 +3985,22 @@
39683985
"DeploymentConfiguration": { "MinimumHealthyPercent": { "Fn::If": [ "HighAvailability", "50", "0" ] }, "MaximumPercent": "200" },
39693986
"DesiredCount": { "Fn::If": [ "HighAvailability", { "Ref": "ApiCount" }, 1 ] },
39703987
"LoadBalancers": [ { "ContainerName": "web", "ContainerPort": "5443", "TargetGroupArn": { "Ref": "ApiBalancerTargetGroup" } }],
3971-
"PlacementConstraints": [ { "Fn::If": ["SpotFleet", { "Type": "memberOf", "Expression": "attribute:asg == primary" }, { "Ref": "AWS::NoValue" }] } ],
3988+
"PlacementConstraints": [ { "Fn::If": ["SpotFleet", { "Type": "memberOf", "Expression": "attribute:asg == primary" }, { "Ref": "AWS::NoValue" }] } ],
39723989
"Role": { "Fn::GetAtt": [ "ServiceRole", "Arn" ] },
39733990
"TaskDefinition": { "Ref": "ApiWebTasks" }
39743991
}
39753992
},
39763993
"ApiBuildTasks": {
39773994
"Type": "AWS::ECS::TaskDefinition",
39783995
"Properties": {
3996+
"RequiresCompatibilities": [
3997+
{ "Fn::If": [ "BuildUsingFargate", "FARGATE", "EC2" ] }
3998+
],
3999+
"NetworkMode": { "Fn::If": [ "BuildUsingFargate", "awsvpc", "bridge" ] },
4000+
"Cpu": { "Ref": "BuildCpu" },
4001+
"Memory": { "Ref": "BuildMemory" },
39794002
"ContainerDefinitions": [
39804003
{
3981-
"Cpu": { "Ref": "BuildCpu" },
39824004
"DockerLabels": {
39834005
"convox.release": { "Ref": "Version" },
39844006
"rack.ApiBalancerSecurity": { "Ref": "ApiBalancerSecurity" },
@@ -4079,14 +4101,19 @@
40794101
"LinuxParameters": {
40804102
"InitProcessEnabled": "true"
40814103
},
4082-
"Memory": { "Ref": "BuildMemory" },
40834104
"ReadonlyRootFilesystem": { "Fn::If": [ "EnableContainerReadonlyRootFilesystem", "true", "false" ] },
4084-
"MountPoints": [
4085-
{ "SourceVolume": "config", "ContainerPath": "/etc/sysconfig/docker" },
4086-
{ "SourceVolume": "docker", "ContainerPath": "/var/run/docker.sock" },
4087-
{ "SourceVolume": "home", "ContainerPath": "/root/" },
4088-
{ "SourceVolume": "temp", "ContainerPath": "/tmp/" }
4089-
],
4105+
"MountPoints": {
4106+
"Fn::If": [
4107+
"BuildUsingFargate",
4108+
{ "Ref": "AWS::NoValue" },
4109+
[
4110+
{ "SourceVolume": "config", "ContainerPath": "/etc/sysconfig/docker" },
4111+
{ "SourceVolume": "docker", "ContainerPath": "/var/run/docker.sock" },
4112+
{ "SourceVolume": "home", "ContainerPath": "/root/" },
4113+
{ "SourceVolume": "temp", "ContainerPath": "/tmp/" }
4114+
]
4115+
]
4116+
},
40904117
"Name": "build",
40914118
"Secrets": [{
40924119
"Name": "PASSWORD",
@@ -4097,12 +4124,18 @@
40974124
"ExecutionRoleArn": { "Fn::GetAtt": [ "ApiRole", "Arn" ] },
40984125
"Family": { "Fn::Sub": "${AWS::StackName}-build" },
40994126
"TaskRoleArn": { "Fn::GetAtt": [ "ApiRole", "Arn" ] },
4100-
"Volumes": [
4101-
{ "Name": "config", "Host": { "SourcePath": "/etc/sysconfig/docker" } },
4102-
{ "Name": "docker", "Host": { "SourcePath": "/var/run/docker.sock" } },
4103-
{ "Name": "home" },
4104-
{ "Name": "temp" }
4105-
]
4127+
"Volumes": {
4128+
"Fn::If": [
4129+
"BuildUsingFargate",
4130+
{ "Ref": "AWS::NoValue" },
4131+
[
4132+
{ "Name": "config", "Host": { "SourcePath": "/etc/sysconfig/docker" } },
4133+
{ "Name": "docker", "Host": { "SourcePath": "/var/run/docker.sock" } },
4134+
{ "Name": "home" },
4135+
{ "Name": "temp" }
4136+
]
4137+
]
4138+
}
41064139
}
41074140
},
41084141
"ApiMonitorTasks": {
@@ -4515,7 +4548,7 @@
45154548
"VersioningConfiguration": { "Status" : {"Ref": "EnableS3Versioning" } },
45164549
"LifecycleConfiguration": { "Fn::If": [ "BlankLogRetention",
45174550
{ "Rules": [ { "NoncurrentVersionExpiration": { "NewerNoncurrentVersions" : 1, "NoncurrentDays" : 365 }, "Status": "Enabled" } ] },
4518-
{ "Rules": [
4551+
{ "Rules": [
45194552
{ "ExpirationInDays": { "Ref": "LogRetention" }, "Status": "Enabled" },
45204553
{ "NoncurrentVersionExpiration": { "NewerNoncurrentVersions" : 1, "NoncurrentDays" : 365 }, "Status": "Enabled" }
45214554
] }

0 commit comments

Comments
 (0)