3. Cloud environment

Applications often need environment specific configuration information, especially in changing environments like in the Amazon cloud environment. Spring Cloud AWS provides a support to retrieve and use environment specific data inside the application context using common Spring mechanisms like property placeholder or the Spring expression language.

3.1 Retrieving instance metadata

Instance metadata are available inside an EC2 environment. The metadata can be queried using a special HTTP address that provides the instance metadata. Spring Cloud AWS enables application to access this metadata directly in expression or property placeholder without the need to call an external HTTP service.

3.1.1 Enabling instance metadata support with XML

The instance metadata retrieval support is enabled through an XML element like the standard property placeholder in Spring. The following code sample demonstrates the activation of the instance metadata support inside an application context.

<beans ...>
  	<aws-context:context-instance-data />
</beans>
[Tip]Tip

Instance metadata can be retrieved without an authorized service call, therefore the configuration above does not require any region or security specific configuration.

3.1.2 Enabling instance metadata support with Java

The instance metadata can also be configured within a Java configuration class without the need for an XML configuration. The next example shows a typical Spring @Configuration class that enables the instance metadata with the org.springframework.cloud.aws.context.config.annotation.EnableInstanceData

@Configuration
@EnableContextInstanceData
public static class ApplicationConfiguration {
}

3.1.3 Enabling instance metadata support in Spring Boot

The instance metadata is automatically available in a Spring Boot application as a property source if the application is running on an EC2 instance.

3.1.4 Using instance metadata

Instance metadata can be used in XML, Java placeholders and expressions. The example below demonstrates the usage of instance metadata inside an XML file using placeholders and also the expression referring to the special variable environment

<beans ...>
 <bean class="org.springframework.cloud.aws....SimpleConfigurationBean">
	<property name="value1" value="#{environment.ami-id}" />
	<property name="value2" value="#{environment.hostname}" />
	<property name="value3" value="${instance-type}" />
	<property name="value4" value="${instance-id}" />
 </bean>
</beans>

Instance metadata can also be injected with the Spring org.springframework.beans.factory.annotation.Value annotation directly into Java fields. The next example demonstrates the use of instance metadata inside a Spring bean.

@Component
public class ApplicationInfoBean {

    @Value("${ami-id:N/A}")
    private String amiId;

    @Value("${hostname:N/A}")
    private String hostname;

    @Value("${instance-type:N/A}")
    private String instanceType;

    @Value("${services/domain:N/A}")
    private String serviceDomain;
}
[Note]Note

Every instance metadata can be accessed by the key available in the instance metadata service Nested properties can be accessed by separating the properties with a slash ('/').

3.1.5 Using instance user data

Besides the default instance metadata it is also possible to configure user data on each instance. This user data is retrieved and parsed by Spring Cloud AWS. The user data can be defined while starting an EC2 instance with the application. Spring Cloud AWS expects the format <key>:<value>;<key>:<value> inside the user data so that it can parse the string and extract the key value pairs.

The user data can be configured using either the management console shown below or a CloudFormation template.

User data in the management console

A CloudFormation template snippet for the configuration of the user data is outlined below:

...
"Resources": {
 "ApplicationServerInstance": {
	 "Type": "AWS::EC2::Instance",
	 "Properties": {
	  "ImageId": "ami-6a56b81d",
	  "UserData": {
	     "Fn::Base64": "data1:value1;data2:value2"
	   },
	  "InstanceType": "t1.micro",
	 }
}
...

The user data can be accessed directly in the application context like the instance metadata through placeholders or expressions.

@Component
public class SecondConfigurationBean {

	@Value("${data1}")
	private String firstDataOption;

	@Value("${data2}")
	private String secondDataOption;
}

3.1.6 Using instance tags

User configured properties can also be configured with tags instead of user data. Tags are a global concept in the context of Amazon Web services and used in different services. Spring Cloud AWS supports instance tags also across different services. Compared to user data, user tags can be updated during runtime, there is no need to stop and restart the instance.

[Tip]Tip

User data can also be used to execute scripts on instance startup. Therefore it is useful to leverage instance tags for user configuration and user data to execute scripts on instance startup.

Instance specific tags can be configured on the instance level through the management console outlined below and like user data also with a CloudFormation template shown afterwards.

Instance data in the management console

A CloudFormation template snippet for the configuration of the instance tags is outlined below:

...
"Resources": {
	"UserTagAndUserDataInstance": {
		"Type": "AWS::EC2::Instance",
		"Properties": {
			"ImageId": "ami-6a56b81d",
		  	"InstanceType": "t1.micro",
		  	"Tags": [
			{
				"Key": "tag1",
			  	"Value": "tagv1"
			},
			{
				"Key": "tag3",
			  	"Value": "tagv3"
			},
			{
				"Key": "tag2",
			  	"Value": "tagv2"
			},
			{
				"Key": "tag4",
				"Value": "tagv4"
			}
			]
		}
	}
}
...

To retrieve the instance tags, Spring Cloud AWS has to make authenticated requests and therefore it will need the region and security configuration before actually resolving the placeholders. Also because the instance tags are not available while starting the application context, they can only be referenced as expressions and not with placeholders. The context-instance-data element defines an attribute user-tags-map that will create a map in the application context for the name. This map can then be queried using expression for other bean definitions.

<beans ...>
 <aws-context:context-instance-data user-tags-map="instanceData" />
</beans>

A java bean might resolve expressions with the @Value annotation.

public class SimpleConfigurationBean {

	@Value("#{instanceData.tag1}")
	private String value1;

	@Value("#{instanceData.tag2}")
	private String value2;

	@Value("#{instanceData.tag3}")
	private String value3;

	@Value("#{instanceData.tag4}")
	private String value4;
}

3.1.7 Configuring custom EC2 client

In some circumstances it is necessary to have a custom EC2 client to retrieve the instance information. The context-instance-data element supports a custom EC2 client with the amazon-ec2 attribute. The next example shows the use of a custom EC2 client that might have a special configuration in place.

<beans ...>

  <aws-context:context-credentials>....</aws-context:context-credentials>
  <aws-context:context-region ... />
  <aws-context:context-instance-data  amazon-ec2="myCustomClient"/>

  <bean id="myCustomClient" class="com.amazonaws.services.ec2.AmazonEC2Client">
	...
  </bean>
</beans>

3.1.8 Injecting the default EC2 client

If there are user tags configured for the instance data (see above) Spring Cloud AWS configures an EC2 client with the specified region and security credentials. Application developers can inject the EC2 client directly into their code using the @Autowired annotation.

public class ApplicationService {

	private final AmazonEC2 amazonEc2;

	@Autowired
	public ApplicationService(AmazonEC2 amazonEc2) {
		this.amazonEc2 = amazonEc2;
	}
}

3.2 Integrating your Spring Cloud application with the AWS Parameter Store

Spring Cloud provides support for centralized configuration, which can be read and made available as a regular Spring PropertySource when the application is started. The Parameter Store Configuration allows you to use this mechanism with the AWS Parameter Store.

Simply add a dependency on the spring-cloud-starter-aws-parameter-store-config starter module to activate the support. The support is similar to the support provided for the Spring Cloud Config Server or Consul’s key-value store: configuration parameters can be defined to be shared across all services or for a specific service and can be profile-specific. Encrypted values will be decrypted when retrieved.

All configuration parameters are retrieved from a common path prefix, which defaults to /config. From there shared parameters are retrieved from a path that defaults to application and service-specific parameters use a path that defaults to the configured spring.application.name. You can use both dots and forward slashes to specify the names of configuration keys. Names of activated profiles will be appended to the path using a separator that defaults to an underscore.

That means that for a service called my-service the module by default would find and use these parameters:

parameter keySpring propertydescription

/config/application/cloud.aws.stack.name

cloud.aws.stack.name

Shared by all services that have the Configuration support enabled. Can be overridden with a service- or profile-specific property.

/config/application_production/cloud.aws.stack.name

cloud.aws.stack.name

Shared by all services that have the Configuration support enabled and have a production Spring profile activated. Can be overridden with a service-specific property.

/config/my-service/cloud/aws/stack/auto

cloud.aws.stack.auto

Specific to the my-service service. Note that slashes in the key path are replaced with dots.

/config/my-service_production/cloud/aws/stack/auto

cloud.aws.stack.auto

Specific to the my-service service when a production Spring profile is activated.

Note that this module does not support full configuration files to be used as parameter values like e.g. Spring Cloud Consul does: AWS parameter values are limited to 4096 characters, so we support individual Spring properties to be configured only.

You can configure the following settings in a Spring Cloud bootstrap.properties or bootstrap.yml file (note that relaxed property binding is applied, so you don’t have to use this exact syntax):

propertydefaultexplanation

aws.paramstore.prefix

/config

Prefix indicating first level for every property loaded from the Parameter Store. Value must start with a forward slash followed by one or more valid path segments or be empty.

aws.paramstore.defaultContext

application

Name of the context that defines properties shared across all services

aws.paramstore.profileSeparator

_

String that separates an appended profile from the context name. Note that an AWS parameter key can only contain dots, dashes and underscores next to alphanumeric characters.

aws.paramstore.failFast

true

Indicates if an error while retrieving the parameters should fail starting the application.

aws.paramstore.name

the configured value for spring.application.name

Name to use when constructing the path for the properties to look up for this specific service.

aws.paramstore.enabled

true

Can be used to disable the Parameter Store Configuration support even though the auto-configuration is on the classpath.