0

I'm referencing to this documentation: https://docs.aws.amazon.com/codestar/latest/userguide/customize-ec2-multi-endpoints.html#customize-ec2-multi-endpoints-newstage

We currently have a CodeStar project created from the Beanstalk template of type "Java Spring, Web Service". The generated project that uses CloudFormation however only includes a single environment for the deployment of our API.

Question: How does one properly modify this template so that there are two different environments running simultaneously?

In terms of Beanstalk: we need a SingleInstance type for our dev instance, and we want to have a LoadBalanced type for our prod instance (using two EC2 instances for redundancy).

The referenced tutorial mentions awscodestar-<project_name>-infrastructure-prod to be used as the Stack name for the CloudFormation's Sets, but how does that work if there is no actual instance created to be deployed on? I'm confused.

And why is there not already a template file which provides a two-environment CodePipeline/Beanstalk set-up similar to the one described? It seems like a rather mainstream approach to CI/CD.


Here is our template.yml file:

AWSTemplateFormatVersion: 2010-09-09
Transform:
- AWS::CodeStar

Conditions:
  UseSubnet: !Not [!Equals [!Ref 'SubnetId', subnet-none]]

Parameters:
  ProjectId:
    Type: String
    Description: AWS CodeStar project ID used to name project resources and create roles.
  InstanceType:
    Type: String
    Description: The type of Amazon EC2 Linux instances that will be launched for this project.
  KeyPairName:
    Type: String
    Description: The name of an existing Amazon EC2 key pair in the region where the project is created, which you can use to SSH into the new Amazon EC2 Linux instances.
  VpcId:
    Type: String
    Description: The ID of the Amazon Virtual Private Cloud (VPC) used for the new Amazon EC2 Linux instances.
  SubnetId:
    Type: String
    Description: The name of the VPC subnet used for the new Amazon EC2 Linux instances launched for this project.
  SolutionStackName:
    Type: String
    Description: The software stack used to launch environments and configure instances in AWS Elastic Beanstalk.
  EBTrustRole:
    Type: String
    Description: The service role in IAM for AWS Elastic Beanstalk to be created for this project.
  EBInstanceProfile:
    Type: String
    Description: The IAM role that will be created for the Amazon EC2 Linux instances.
  Stage:
    Type: String
    Description: The name for a project pipeline stage, such as Staging or Prod, for which resources are provisioned and deployed.
    Default: ''
Resources:
  EBApplication:
    Description: The AWS Elastic Beanstalk application, which is a container used to deploy the correct application configuration.
    Type: AWS::ElasticBeanstalk::Application
    Properties:
      ApplicationName: !Sub '${ProjectId}app${Stage}'
      Description: The name of the AWS Elastic Beanstalk application to be created for this project.
  EBApplicationVersion:
    Description: The version of the AWS Elastic Beanstalk application to be created for this project.
    Type: AWS::ElasticBeanstalk::ApplicationVersion
    Properties:
      ApplicationName: !Ref 'EBApplication'
      Description: The application version number.
      SourceBundle: 'target/ROOT'
  EBConfigurationTemplate:
    Description: The AWS Elastic Beanstalk configuration template to be created for this project, which defines configuration settings used to deploy different versions of an application.
    Type: AWS::ElasticBeanstalk::ConfigurationTemplate
    Properties:
      ApplicationName: !Ref 'EBApplication'
      Description: The name of the sample configuration template.
      OptionSettings:
      - Namespace: aws:elasticbeanstalk:environment
        OptionName: EnvironmentType
        Value: SingleInstance
      - Namespace: aws:elasticbeanstalk:environment
        OptionName: ServiceRole
        Value: !Ref 'EBTrustRole'
      - Namespace: aws:elasticbeanstalk:healthreporting:system
        OptionName: SystemType
        Value: enhanced
      SolutionStackName: !Ref 'SolutionStackName'
  EBEnvironment:
    Description: The AWS Elastic Beanstalk deployment group where the application is deployed, which is made up of the Amazon EC2 Linux instances launched for this project.
    Type: AWS::ElasticBeanstalk::Environment
    Properties:
      ApplicationName: !Ref 'EBApplication'
      EnvironmentName: !Ref 'EBApplication'
      Description: The application to be deployed to the environment.
      TemplateName: !Ref 'EBConfigurationTemplate'
      VersionLabel: !Ref 'EBApplicationVersion'
      OptionSettings:
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value: !Ref 'EBInstanceProfile'
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: InstanceType
        Value: !Ref 'InstanceType'
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: EC2KeyName
        Value: !Ref 'KeyPairName'
      - Namespace: aws:ec2:vpc
        OptionName: VPCId
        Value: !Ref 'VpcId'
      - !If
        - UseSubnet
        - Namespace: 'aws:ec2:vpc'
          OptionName: Subnets
          Value: !Ref 'SubnetId'
        - !Ref "AWS::NoValue"
payne
  • 4,691
  • 8
  • 37
  • 85

1 Answers1

1

You could create a master template and refer to the production and dev templates as nested stacks. In this case all you would have to do is copy the template.yaml file twice, rename the copies to something appropriate, and upload them to an S3 bucket. Then your template.yaml file would refer to those two templates. Something like this:

AWSTemplateFormatVersion: 2010-09-09
Transform:
- AWS::CodeStar

Description: Master stack which creates all required nested stacks

Resources:
  ProdStack:
    Type: "AWS::CloudFormation::Stack"
    Properties:
      TemplateURL: https://your-bucket/templates/production-stack.yml"
      Parameters:
        InstanceType: t2.micro
        EBInstanceProfile: eg
        KeyPairName: eg
        VpcId: eg
        ProjectId: eg
        SubnetId: eg
        SolutionStackName: eg
        EBTrustRole: eg
      Tags:
        - Key: Environment
          Value: Production
  DevStack:
    Type: "AWS::CloudFormation::Stack"
    Properties:
      TemplateURL: https://your-bucket/templates/development-stack.yml"
      Parameters:
        InstanceType: t2.nano
        EBInstanceProfile: eg
        KeyPairName: eg
        VpcId: eg
        ProjectId: eg
        SubnetId: eg
        SolutionStackName: eg
        EBTrustRole: eg
      Tags:
        - Key: Environment
          Value: Dev

This will create both stacks and allow you to put in the appropriate parameters for each. Take a look here: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stack.html

Your pipeline would likely remain in the master file, and any other parameters you need for both environments, depending on how you structure the project.

badfun
  • 145
  • 1
  • 10
  • Will this end up generating two CodeCommit repos, and two CodePipeline pipelines, for example? – payne Feb 21 '20 at 20:58
  • You likely wouldn't want separate repos for different environments. You can trigger different pipelines off of different branches in the repository. This example only makes the change for the Instance type. – badfun Feb 28 '20 at 17:20
  • Interesting. I'll look into that solution when I have time. Back then, we had tried to "glue" something together, and we're still having problems with it. Feel free to check it out as well: https://stackoverflow.com/q/60460005/9768291 – payne Feb 28 '20 at 22:23