Skip to content

Commit 56081f8

Browse files
committed
Added support for the arm64 ECS Optimized AL2 AMI and the A1 instance family
1 parent 9271525 commit 56081f8

File tree

10 files changed

+188
-85
lines changed

10 files changed

+188
-85
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,10 @@ ecs-cli up --cluster myCluster --empty
330330

331331
This is equivalent to the [create-cluster command](https://docs.aws.amazon.com/cli/latest/reference/ecs/create-cluster.html), and will not create a CloudFormation stack associated with your cluster.
332332

333+
#### AMI
334+
335+
You can specify the AMI to use with your EC2 instances using the `--image-id` flag. Alternatively, if you do not specify an image ID, the ECS CLI will use the [recommended Amazon Linux 2 ECS Optimized AMI](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/retrieve-ecs-optimized_AMI.html). By default, the x86 variant of this AMI is used. However, if you specify an instance in the A1 family using `--instance-type`, then the `arm64` version of the ECS Optimized AMI will be used. Note: `arm64` ECS Optimized AMIs are only supported in some regions; please see [Amazon ECS-Optimized Amazon Linux 2 AMI](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/al2ami.html).
336+
333337
#### User Data
334338

335339
For the EC2 launch type, the ECS CLI always creates EC2 instances that include the following User Data:

ecs-cli/modules/cli/cluster/cluster_app.go

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,21 @@ import (
1717
"bufio"
1818
"fmt"
1919
"os"
20+
"regexp"
2021
"strconv"
2122
"strings"
2223

2324
"github.com/aws/amazon-ecs-cli/ecs-cli/modules/cli/cluster/userdata"
2425
"github.com/aws/amazon-ecs-cli/ecs-cli/modules/cli/compose/container"
2526
ecscontext "github.com/aws/amazon-ecs-cli/ecs-cli/modules/cli/compose/context"
2627
"github.com/aws/amazon-ecs-cli/ecs-cli/modules/cli/compose/entity/task"
28+
"github.com/aws/amazon-ecs-cli/ecs-cli/modules/clients/aws/amimetadata"
2729
"github.com/aws/amazon-ecs-cli/ecs-cli/modules/clients/aws/cloudformation"
2830
ec2client "github.com/aws/amazon-ecs-cli/ecs-cli/modules/clients/aws/ec2"
2931
ecsclient "github.com/aws/amazon-ecs-cli/ecs-cli/modules/clients/aws/ecs"
30-
"github.com/aws/amazon-ecs-cli/ecs-cli/modules/clients/aws/ssm"
3132
"github.com/aws/amazon-ecs-cli/ecs-cli/modules/commands/flags"
3233
"github.com/aws/amazon-ecs-cli/ecs-cli/modules/config"
34+
"github.com/aws/aws-sdk-go/aws"
3335
"github.com/docker/libcompose/project"
3436
"github.com/sirupsen/logrus"
3537
"github.com/urfave/cli"
@@ -60,6 +62,10 @@ const (
6062
ParameterKeySpotPrice = "SpotPrice"
6163
)
6264

65+
const (
66+
defaultARM64InstanceType = "a1.medium"
67+
)
68+
6369
var flagNamesToStackParameterKeys map[string]string
6470
var requiredParameters []string = []string{ParameterKeyCluster}
6571

@@ -81,17 +87,17 @@ func init() {
8187
}
8288

8389
type AWSClients struct {
84-
ECSClient ecsclient.ECSClient
85-
CFNClient cloudformation.CloudformationClient
86-
SSMClient ssm.Client
90+
ECSClient ecsclient.ECSClient
91+
CFNClient cloudformation.CloudformationClient
92+
AMIMetadataClient amimetadata.Client
8793
}
8894

8995
func newAWSClients(commandConfig *config.CommandConfig) *AWSClients {
9096
ecsClient := ecsclient.NewECSClient(commandConfig)
9197
cfnClient := cloudformation.NewCloudformationClient(commandConfig)
92-
ssmClient := ssm.NewSSMClient(commandConfig)
98+
metadataClient := amimetadata.NewMetadataClient(commandConfig)
9399

94-
return &AWSClients{ecsClient, cfnClient, ssmClient}
100+
return &AWSClients{ecsClient, cfnClient, metadataClient}
95101
}
96102

97103
///////////////////////
@@ -185,7 +191,7 @@ func createCluster(context *cli.Context, awsClients *AWSClients, commandConfig *
185191

186192
ecsClient := awsClients.ECSClient
187193
cfnClient := awsClients.CFNClient
188-
ssmClient := awsClients.SSMClient
194+
metadataClient := awsClients.AMIMetadataClient
189195

190196
// Check if cluster is specified
191197
if commandConfig.Cluster == "" {
@@ -277,10 +283,15 @@ func createCluster(context *cli.Context, awsClients *AWSClients, commandConfig *
277283
}
278284

279285
if launchType == config.LaunchTypeEC2 {
286+
architecture, err := determineArchitecture(cfnParams)
287+
if err != nil {
288+
return err
289+
}
290+
280291
// Check if image id was supplied, else populate
281292
_, err = cfnParams.GetParameter(ParameterKeyAmiId)
282293
if err == cloudformation.ParameterNotFoundError {
283-
amiMetadata, err := ssmClient.GetRecommendedECSLinuxAMI()
294+
amiMetadata, err := metadataClient.GetRecommendedECSLinuxAMI(architecture)
284295
if err != nil {
285296
return err
286297
}
@@ -321,6 +332,28 @@ func createCluster(context *cli.Context, awsClients *AWSClients, commandConfig *
321332
return cfnClient.WaitUntilCreateComplete(stackName)
322333
}
323334

335+
func determineArchitecture(cfnParams *cloudformation.CfnStackParams) (string, error) {
336+
architecture := amimetadata.ArchitectureTypeX86
337+
338+
// a1 instances get the Arm based ECS AMI
339+
instanceTypeParam, err := cfnParams.GetParameter(ParameterKeyInstanceType)
340+
if err == cloudformation.ParameterNotFoundError {
341+
logrus.Infof("Defaulting instance type to t2.micro")
342+
} else if err != nil {
343+
return "", err
344+
} else {
345+
instanceType := aws.StringValue(instanceTypeParam.ParameterValue)
346+
// This regex matches all current a1 instances, and should work for any future additions as well
347+
r := regexp.MustCompile("a1\\.(medium|\\d*x?large)")
348+
if r.MatchString(instanceType) {
349+
logrus.Infof("Using Arm ecs-optimized AMI because instance type was %s", instanceType)
350+
architecture = amimetadata.ArchitectureTypeARM64
351+
}
352+
}
353+
354+
return architecture, nil
355+
}
356+
324357
var newCommandConfig = func(context *cli.Context, rdwr config.ReadWriter) (*config.CommandConfig, error) {
325358
return config.NewCommandConfig(context, rdwr)
326359
}

0 commit comments

Comments
 (0)