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.
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.
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 | |
---|---|
Instance metadata can be retrieved without an authorized service call, therefore the configuration above does not require any region or security specific configuration. |
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 { }
The instance metadata is automatically available in a Spring Boot application as a property source if the application is running on an EC2 instance.
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 | |
---|---|
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 ('/'). |
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.
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; }
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 | |
---|---|
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.
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; }
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>
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; } }