0

I have a CDK app with a Stack class that creates an AWS Elastic Beanstalk App.

When there is a new app version I want to create, I want the Stack to create a new AppVersion on the Beanstalk Environment without deleting the already existing AppVersion(s).

With my current setup, everytime I run cdk deploy, the Stack creates the new AppVersion resource and Deletes the existing AppVersion.

Here's my Stack code:

 class ProdStack extends cdk.Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    // Construct an S3 asset from the ZIP located from directory up.
    const webAppZipArchive = new s3assets.Asset(
      this,
      `${process.env.STACK_NAME}`,
      getBuildZipConfig()
    );

    // EBS IAM Roles
    const EbInstanceRole = new iam.Role(this, `my-aws-elasticbeanstalk-ec2-role`, {
      assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
    });

    const managedPolicy = iam.ManagedPolicy.fromAwsManagedPolicyName('AWSElasticBeanstalkWebTier');
    EbInstanceRole.addManagedPolicy(managedPolicy);

    const profileName = `${id}-InstanceProfile`;

    const instanceProfile = new iam.CfnInstanceProfile(this, profileName, {
      instanceProfileName: profileName,
      roles: [EbInstanceRole.roleName],
    });

    const node = this.node;
    const platform = node.tryGetContext('platform');

    const APPLICATION_NAME = id;
    const ENVIRONMENT_NAME = `${id}-env`;
    const APP_VERSION = process.env.COMMIT_HASH;

    // Create the EB application
    const app = new elasticbeanstalk.CfnApplication(this, 'Application', {
      applicationName: APPLICATION_NAME,
    });

    // Create an app version from the S3 asset defined earlier
    const appVersionProps = new elasticbeanstalk.CfnApplicationVersion(this, APP_VERSION, {
      applicationName: APPLICATION_NAME,
      sourceBundle: {
        s3Bucket: webAppZipArchive.s3BucketName,
        s3Key: webAppZipArchive.s3ObjectKey,
      },
      description: APP_VERSION,
    });

    appVersionProps.addDependsOn(app);

    // Create EB environment
    let optionSettingProperties = [
      {
        namespace: 'aws:ec2:instances',
        optionName: 'InstanceTypes',
        value: 'c5.large',
      },
      {
        namespace: 'aws:autoscaling:launchconfiguration',
        optionName: 'IamInstanceProfile',
        value: profileName,
      },
      {
        namespace: 'aws:elasticbeanstalk:command',
        optionName: 'DeploymentPolicy',
        value: 'Immutable',
      },
    ];

    optionSettingProperties = [...optionSettingProperties, ...this.getEnvConfig()];

    const env = new elasticbeanstalk.CfnEnvironment(this, 'Environment', {
      environmentName: ENVIRONMENT_NAME,
      applicationName: APPLICATION_NAME,
      platformArn: platform,
      solutionStackName: '64bit Amazon Linux 2 v5.4.9 running Node.js 14',
      optionSettings: optionSettingProperties,
      cnamePrefix: process.env.CNAME_PREFIX,
    });

    env.addDependsOn(appVersionProps);
}

Any help will be greatly appreciated.

Thank you!

1 Answers1

0

Your stack has one CfnApplicationVersion construct. If you want more explicitly-defined version instances, either (a) add more CfnApplicationVersion constructs to your Stack or (b) add more instances of ProdStack to your App.

A Stack is the CDK/CloudFormation unit of deployment. Running cdk deploy the first time in an enviornment (= region + account) creates the Stack's resources. Subsequent cdk deploy commands update or replace existing resources.

fedonev
  • 20,327
  • 2
  • 25
  • 34
  • Thank you for your answer! However, it doesn't really solve the problem. My use case is that whenever there will be a push on my main branch, a Github Action will trigger cdk-deploy, which will use the `ProdStack` class. I want an AppVersion to be uploaded and **added** to the list of AppVersions. This is so that if the newly uploaded AppVersion fails to deploy, I can quickly deploy the previous AppVersion. So option a) that you suggested isn't really possible because the Stack class won't know which AppVersions already exist. I'm not too sure what you're suggesting with b). – Sahaj Arora Feb 26 '22 at 21:27
  • Please know that I have a CNAME_PREFIX set to the Beanstalk Environment and that helps redirect traffic to my domain name (example.com) to the beanstalk environment since there's a known url for it with the help of cname. – Sahaj Arora Feb 26 '22 at 21:32
  • I guess what you're suggesting with b) is that I can literally just create a new stack everytime ? That's a possible solution but I wonder how those stacks will be cleaned over time when the old AppVersions get deleted by AWS with the help of LifeCycle policy that I've set on them. According to that policy, whenever there are more than 4 AppVersions, the older one is deleted. Does that delete the CloudFormation stack as well ? – Sahaj Arora Feb 26 '22 at 21:35
  • @SahajArora The OP asks a simple question. I answered it. Your comments reveal new requirements. CDK/Cfn may not be the right tool for your job. EB [creates an application version whenever you upload source code.](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/applications-versions.html). This SO answer suggests you can [link EB directly with Github](https://stackoverflow.com/questions/39090857/deploy-a-github-branch-automatically-to-aws-elastic-beanstalk). What you describe in the comments is possible using CDK/Cfn, but smells like an EB anti-pattern. – fedonev Feb 27 '22 at 09:58