1
votes

I am trying to setup the AWS environment for my SpringBoot application which uses Postgres. I decided to use CloudFormation to configure all the AWS components needed for my application.

Following is the cloud formation template app.json:

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Parameters": {
    "S3BucketName": {
      "Description": "S3 BucketName",
      "Type": "String"
    },
    "S3FileName": {
      "Description": "Name of the jar/war file",
      "Type": "String"
    },
    "DBName":{
      "Default":"mytododb",
      "Description":"The database name",
      "Type":"String",
      "MinLength":"1",
      "MaxLength":"64",
      "AllowedPattern":"[a-zA-Z][a-zA-Z0-9]*",
      "ConstraintDescription":"must begin with a letter and contain only alphanumeric characters."
    },
    "DBUser":{
      "Description":"The database admin account username",
      "Type":"String",
      "MinLength":"1",
      "MaxLength":"16",
      "AllowedPattern":"[a-zA-Z][a-zA-Z0-9]*",
      "ConstraintDescription":"must begin with a letter and contain only alphanumeric characters."
    },
    "DBPassword":{
      "NoEcho":"true",
      "Description":"The database admin account password",
      "Type":"String",
      "MinLength":"8",
      "MaxLength":"41",
      "AllowedPattern":"[a-zA-Z0-9]*",
      "ConstraintDescription":"must contain only alphanumeric characters."
    },
    "DBAllocatedStorage":{
      "Default":"5",
      "Description":"The size of the database (Gb)",
      "Type":"Number",
      "MinValue":"5",
      "MaxValue":"1024",
      "ConstraintDescription":"must be between 5 and 1024Gb."
    },
    "DBInstanceClass":{
      "Default":"db.t2.micro",
      "Description":"The database instance type",
      "Type":"String",
      "ConstraintDescription":"must select a valid database instance type."
    },
    "MultiAZDatabase":{
      "Default":"false",
      "Description":"Create a multi-AZ RDS database instance",
      "Type":"String",
      "AllowedValues":[
        "true",
        "false"
      ],
      "ConstraintDescription":"must be either true or false."
    }
  },
  "Resources": {
    "SpringBootApplication": {
      "Type": "AWS::ElasticBeanstalk::Application",
      "Properties": {
        "Description":"Spring boot and elastic beanstalk"
      }
    },
    "SpringBootApplicationVersion": {
      "Type": "AWS::ElasticBeanstalk::ApplicationVersion",
      "Properties": {
        "ApplicationName":{"Ref":"SpringBootApplication"},
        "SourceBundle": {
          "S3Bucket": {
            "Ref": "S3BucketName"
          },
          "S3Key": {
            "Ref": "S3FileName"
          }
        }
      }
    },
    "SpringBootBeanStalkConfigurationTemplate": {
      "Type": "AWS::ElasticBeanstalk::ConfigurationTemplate",
      "Properties": {
        "ApplicationName": {"Ref":"SpringBootApplication"},
        "Description":"A display of speed boot application",
        "OptionSettings": [
          {
            "Namespace": "aws:rds:dbinstance",
            "OptionName": "DBAllocatedStorage",
            "Value": {
              "Ref": "DBAllocatedStorage"
            }
          },
          {
            "Namespace": "aws:rds:dbinstance",
            "OptionName": "DBDeletionPolicy",
            "Value": "Delete"
          },
          {
            "Namespace": "aws:rds:dbinstance",
            "OptionName": "DBEngine",
            "Value": "postgres"
          },
          {
            "Namespace": "aws:rds:dbinstance",
            "OptionName": "DBEngineVersion",
            "Value": "10.4"
          },
          {
            "Namespace": "aws:rds:dbinstance",
            "OptionName": "DBInstanceClass",
            "Value": { "Ref": "DBInstanceClass" }
          },
          {
            "OptionName": "DBPassword",
            "Namespace": "aws:rds:dbinstance",
            "Value": { "Ref": "DBPassword" }
          },
          {
            "Namespace": "aws:rds:dbinstance",
            "OptionName": "DBUser",
            "Value": { "Ref": "DBUser" }
          },
          {
            "Namespace": "aws:rds:dbinstance",
            "OptionName": "MultiAZDatabase",
            "Value": { "Ref": "MultiAZDatabase" }
          }
        ],
        "SolutionStackName": "64bit Amazon Linux 2018.03 v2.9.2 running Java 8"
      }
    },
    "SpringBootBeanstalkEnvironment": {
      "Type": "AWS::ElasticBeanstalk::Environment",
      "Properties": {
        "ApplicationName": {"Ref":"SpringBootApplication"},
        "EnvironmentName":"TodoAppEnvironment",
        "TemplateName": {"Ref":"SpringBootBeanStalkConfigurationTemplate"},
        "VersionLabel": {"Ref": "SpringBootApplicationVersion"}
      }
    }
  },
  "Outputs": {
    "DevURL": {
      "Description": "The URL of the DEV Elastic Beanstalk environment",
      "Value": {
        "Fn::Join": [
          "",
          [
            {
              "Fn::GetAtt": [
                "SpringBootBeanstalkEnvironment",
                "EndpointURL"
              ]
            }
          ]
        ]
      },
      "Export": {
        "Name": {
          "Fn::Sub": "${AWS::StackName}-EndpointURL"
        }
      }
    }
  }
}

And the parameters file parameters.json is:

[
  {
    "ParameterKey": "DBUser",
    "ParameterValue": "myuser"
  },
  {
    "ParameterKey": "DBPassword",
    "ParameterValue": "secret"
  },
  {
    "ParameterKey": "S3BucketName",
    "ParameterValue": "todoapp"
  },
  {
    "ParameterKey": "S3FileName",
    "ParameterValue": "todo-api-spring-boot-0.0.1.jar"
  }
]

I am creating the CloudFormation stack using aws cloudformation create-stack --template-body file://app.json --parameters file://parameters.json --stack-name=todo-stack

Problem: The stack is getting created, however the database (RDS) instance is not getting created and when I see in ElasticBeanstalk configuration for the app in Management Console there is no Database configuration associated with the application.

My expectation/assumption is by configuring various aws:rds:dbinstance properties in OptionSettings an RDS instance will be provisioned and associates with ElasticBeanstalk application.

Is my understanding wrong or am I missing any other setting?

PS: The idea is to use integrated RDS so that I can use RDS_HOST, RDS_PORT etc properties in my application to connect to database.

I am able to configure a separate RDS Resource and connect to it by specifying the connection parameters. But I am expecting aws:rds:dbinstance properties in OptionSettings would create the RDS and associate it to Elasticbeanstalk application. If that is not the case then what is the purpose of configuring those parameters in OptionSettings?

Ref:

https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options-general.html#command-options-general-rdsdbinstance

https://github.com/metabase/metabase/blob/master/bin/aws-eb-docker/cloudformation-elasticbeanstalk.json.template

1

1 Answers

0
votes

RDS creation is not done due to the Namespace Approach. Basically Namespace is used to override the default properties of the resources which you have created.

So the solution is to include the RDS creation template before your "SpringBootBeanStalkConfigurationTemplate"

  "Resources": {
    "RDS Creation": {
      {
      "Type" : "AWS::RDS::DBInstance",
      "Properties" : {
          "AllocatedStorage" : String,
          "AllowMajorVersionUpgrade" : Boolean,
          "AssociatedRoles" : [ DBInstanceRole, ... ],
          "AutoMinorVersionUpgrade" : Boolean,
          "AvailabilityZone" : String,
          "BackupRetentionPeriod" : Integer,
          "CharacterSetName" : String,
          "CopyTagsToSnapshot" : Boolean,
          "DBClusterIdentifier" : String,
          "DBInstanceClass" : String,
          "DBInstanceIdentifier" : String,
          "DBName" : String,
          "DBParameterGroupName" : String,
          "DBSecurityGroups" : [ String, ... ],
          "DBSnapshotIdentifier" : String,
          "DBSubnetGroupName" : String,
          "DeleteAutomatedBackups" : Boolean,
          "DeletionProtection" : Boolean,
          "Domain" : String,
          "DomainIAMRoleName" : String,
          "EnableCloudwatchLogsExports" : [ String, ... ],
          "EnableIAMDatabaseAuthentication" : Boolean,
          "EnablePerformanceInsights" : Boolean,
          "Engine" : String,
          "EngineVersion" : String,
          "Iops" : Integer,
          "KmsKeyId" : String,
          "LicenseModel" : String,
          "MasterUsername" : String,
          "MasterUserPassword" : String,
          "MonitoringInterval" : Integer,
          "MonitoringRoleArn" : String,
          "MultiAZ" : Boolean,
          "OptionGroupName" : String,
          "PerformanceInsightsKMSKeyId" : String,
          "PerformanceInsightsRetentionPeriod" : Integer,
          "Port" : String,
          "PreferredBackupWindow" : String,
          "PreferredMaintenanceWindow" : String,
          "ProcessorFeatures" : [ ProcessorFeature, ... ],
          "PromotionTier" : Integer,
          "PubliclyAccessible" : Boolean,
          "SourceDBInstanceIdentifier" : String,
          "SourceRegion" : String,
          "StorageEncrypted" : Boolean,
          "StorageType" : String,
          "Tags" : [ Tag, ... ],
          "Timezone" : String,
          "UseDefaultProcessorFeatures" : Boolean,
          "VPCSecurityGroups" : [ String, ... ]
        }
    }
  }
}

After this, you can include the RDS parameters in your other Resources as it will be created first.