building spring applications on cloud foundry
DESCRIPTION
Speakers: Josh Long and Andy Piper Let's face it, the cloud is here to stay. The cloud's potential can seem sometimes overwhelming, but it doesn't have to if you use Spring. Spring - and the various Spring projects - already embrace the architecture characteristics that make for great, cloud-centric applications in any environment. While Spring works well on any cloud platform, it enjoys a special place in the sun on Cloud Foundry, the open source PaaS from Pivotal. In this talk, join Andy Piper as he introduces how to build Spring applications that work well in the cloud and on Cloud Foundry in particular. We'll cover how to consume services with Spring on Cloud Foundry, how to scale out using RabbitMQ and Spring Integration, how to use standalone processes and RabbitMQ for better batch processing, and discuss strategies for exposing and consuming services in a RESTful service-based cloud architecture.TRANSCRIPT
© 2013 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Building Spring applications on Cloud Foundry - a Marriage Made in
Heavenby Andy Piper and Josh Long
Developer Advocate @ Cloud Foundrysocial web enthusiastmaker, educator, LEGO fanOSS contributor Eclipse Project Lead (Paho / MQTT)excited by “what’s next”, Internet of Things, etc.
2
About Andy Piper
Developer Advocateinterested in big data, the open web, cloud and all things Spring
3
About Josh Long
What is a “developer advocate”?
Today’s topics!
§What is Cloud Foundry?§What’s new since #s2gx 2012?§run.pivotal.io
§Java buildpack and Spring§demos!
6
Spring
Deploy to Cloud or on premise
Big, Fast,
FlexibleData Web,
Integration,Batch
GemFire
P O P Q U I Z :
Cloud Foundry? Platform CF?
What is Cloud Foundry, and what’s new?
9
Cloud Storage
Virtualization
...++
Pivotal DataFabric
Pivotal CloudFabric
Data-DrivenApplication
Development
Pivotal Data Science Labs
Cloud Foundry is Part of the Pivotal Suite
GemFire
Deploy and scale applications in seconds on your choice of clouds
The industry’s open Platform as a Service
STANDARDIZED FOR SPEED
Platform as a Service (aka PaaS)
Empower developers to build great apps, not plumbing infrastructure
� An abstraction layer on top of IaaS
� Application is the unit of deployment– not VMs, AppServers, etc..
� Separate the concerns of AppDev & Operations – Databases, Messaging, Load-balancing etc.. “aaS”
� Eliminate bottleneck of provisioning and deployment
� Make full use of investments in the “Cloud”
SaaS
PaaS
IaaS
* An actual application provisioning/update flow in a large enterprise. Image is blurred for privacy reasons
Simplify Application Deployment, from: this…
To: Pushing apps to the cloud with a few easy verbs
cf-‐iaas.yml
provision <my cloud>
add_capacity <my cloud>
target <my cloud>
push <my app>
create <my services>
bind <my services>
scale <my app> +100
OPERATOR DEVELOPER
Cloud Deployment: 2-‐4 hours App Deployment: 30-‐90 seconds
15
A Foundation Based on Choice
Runtime/Frameworks ServicesWhat:
How:
Which:
Buildpacks Service Brokers
… and Custom Runtimes … and Custom Services
16
From VM Centric to Application Centric
InfrastructureOne
JVM
VM
InfrastructureOne
InfrastructureTwo
App
Container 1
App Server
JVM
Container 2
App Server
JVM
Dev Framework Dev Framework
App Server
Configurations Manifests, Automations
InfrastructureTwo
JVM
VM
Dev Framework
App Server
Configurations
App App App
� Your Datacenter / Private Clouds– Cloud Foundry Lighthouse Program – Packaged product coming soon
� Hosted / Public Clouds– run.pivotal.io– Other Cloud Foundry public PaaS via partners (e.g. anynines)
� Developer Laptop– micro clouds as free developer tool
Multi-Clouds, No App Changes!
MicroClouds
PrivateClouds
PublicClouds
A L O T C A N H A P P E N I N 1 2 M O N T H S !
What’s new since SpringOne 2012?
New features
19
• a whole new architecture (“v2” or “ng”)• organizations and spaces (team features)• new router, with added WebSockets• new DEAs, with built-in stager and buildpacks• new Services model, with Marketplace feature
Cloud Foundry – The Inner Shell
Cloud Controller
Dynamic Router
UAA/Login Servers Health Manager
DEA Pool(s)Service Broker Node(s)
User ProvidedService Instances
Messaging (NATS)
Apps
Cloud Foundry BOSH
Buildpacks
Logging
The Runtime is the inner shell. Components are dynamically discoverable and loosely coupled, exposing health through HTTP endpoints so agents can collect state information (app state & system state) and act on it.
CF RunIme
CF BOSH BOSH is the outer shell
C L O U D F O U N D RY
Demo
Java buildpack• Fully rebuilt for Cloud Foundry by the Spring team• Choice of containers e.g. web, Grails, Play, Groovy, Java
main(), Spring Boot, etc• Configurable• Pluggable / extensible (Dropwizard, Jonas, etc etc.)
• http://blog.cloudfoundry.com/2013/09/06/introducing-the-cloud-foundry-java-buildpack/
• https://github.com/cloudfoundry/java-buildpack
22
Choice!• IBM donated WebSphere Liberty Buildpack• http://blog.cloudfoundry.com/2013/09/09/ibm-websphere-
liberty-buildpack-contributed-to-cloud-foundry/
23
C L O U D F O U N D RY
Demo
Spring Tool Suite• Updated to support Cloud Foundry v2
25
C L O U D F O U N D RY
Demo
Service Creation and Binding
27
VCAP_APPLICATION={"instance_id":"e4e2d8e0f66552df3bc8eba5ac2de23b","instance_index":0,"host":"0.0.0.0","port":61797,"started_at":"2013-09-09 00:43:36 +0000","started_at_timestamp":1378687416,"start":"2013-09-09 00:43:36 +0000","state_timestamp":1378687416,"limits":{"mem":512,"disk":1024,"fds":16384},"application_version":"556843e0-63b2-4a6f-bf1c-0f1fbc2eec95","application_name":"music-demo-ap","application_uris":["music-demo-ap.cfapps.io"],"version":"556843e0-63b2-4a6f-bf1c-0f1fbc2eec95","name":"music-demo-ap","uris":["music-demo-ap.cfapps.io"],"users":null}VCAP_SERVICES={"elephantsql-n/a":[{"name":"elephantsql-c299a","label":"elephantsql-n/a","tags":["postgres","postgresql","relational"],"plan":"turtle","credentials":{"uri":"postgres://wurble:[email protected]:5432/wurble"}}],"newrelic-n/a":[{"name":"newrelic-1764c","label":"newrelic-n/a","tags":[],"plan":"standard","credentials":{"licenseKey":"6f044737f4786878ad3870d7e84c78de3e9a70fce"}}]}
The Environment• Asking Questions
– You can introspect the environment variables (System.getenv(“..”)), or...
– import the CloudFoundry runtime API from Java! • (much simpler)
<dependency> <groupId>org.cloudfoundry</groupId> <artifactId>cloudfoundry-runtime</artifactId> <version>0.8.5</version> </dependency>
28
CloudEnvironment cloudEnvironment = new CloudEnvironment();
if (cloudEnvironment.getCloudApiUri() != null) {
model.put("host", cloudEnvironment.getInstanceInfo().getHost());
model.put("port", cloudEnvironment.getInstanceInfo().getPort());
}
The Environment
• Ask Questions of the Cloud– import the CloudFoundry runtime API
29
Auto-Reconfiguration: Getting Started• Deploy Spring apps to the cloud without changing a single
line of code• Cloud Foundry automatically re-configures bean definitions
to bind to cloud services• Works with Spring and Grails
30
Auto-Reconfiguration: Relational DB• Detects beans of type javax.sql.DataSource• Connects to MySQL or PostgreSQL services
– Specifies driver, url, username, password, validation query
• Creates Commons DBCP or Tomcat DataSource• Replaces existing DataSource
31
import org.apache.commons.dbcp.BasicDataSource;...@Bean(destroyMethod = "close")public BasicDataSource dataSource(){
BasicDataSource bds = new BasicDataSource(); bds.setUrl( "jdbc:h2:mem"); bds.setPassword(""); bds.setUsername("sa"); bds.setDriverClass( Driver.class); return bds;}
Auto-Reconfiguration: How It Works• Cloud Foundry installs a BeanFactoryPostProcessor in
your application context during staging– Adds jar to your application– Modifies web.xml to load BFPP
• Adds context file to contextConfigLocation– web-app context-param– Spring MVC DispatcherServlet init-param
• Adds PostgreSQL and MySQL driver jars as needed for DataSource reconfiguration
32
Introducing... the cloud Namespace• <cloud:> namespace for use in Spring app contexts• Provides application-level control of bean service bindings• Recommended for development of new cloud apps• Use when:
– You have multiple services of the same type– You have multiple connecting beans of the same type
• e.g. DataSource, MongoDBFactory– You have custom bean configuration
• e.g. DataSource pool size, connection properties
33
<cloud:service-scan>
• Scans all services bound to the application and creates a bean of an appropriate type for each– Same bean types as auto-reconfiguration
• Useful during early development phases
34
<beans ... xmlns:cloud="http://schema.cloudfoundry.org/spring" xsi:schemaLocation="http://schema.cloudfoundry.org/spring http://schema.cloudfoundry.org/spring/cloudfoundry-spring-0.8.xsd ...">
<cloud:service-scan/>
</beans>
<cloud:service-scan> Autowired • Created beans can be autowired as dependencies• Use @Qualifier with service name if multiple services of same
type bound to app
35
@Autowired(required=false)private ConnectionFactory rabbitConnectionFactory;
@Autowiredprivate RedisConnectionFactory redisConnectionFactory;
@Autowired@Qualifier("test_mysql_database")private DataSource mysqlDataSource;
@Autowired(required=false)@Qualifier("test_postgres_database")private DataSource postgresDataSource;
<cloud:data-source>
• Configures a DataSource bean– Commons DBCP or Tomcat DataSource
• Basic attributes:– id: defaults to service name– service-name: only needed if you have multiple relational
database services bound to the app
36
<cloud:data-source id="dataSource"/>
<bean class="org.sf.orm.jpa.LocalContainerEntityManagerFactoryBean"id="entityManagerFactory"> <property name="dataSource" ref="dataSource"/></bean>
<cloud:data-source> Example
37
<cloud:data-source id="dataSource" service-name="mySQLSvc"><cloud:pool pool-size="1-5"/><cloud:connection properties="charset=utf-8"/>
</cloud:data-source>
...
@Autowired private DataSource dataSource ;
<cloud:properties>• Exposes basic information about services that can be consumed with Spring’s property
placeholder support• Basic attributes:
– id: the name of the properties bean
• Properties automatically available when deploying Spring 3.1 applications
38
<cloud:properties id="cloudProperties" /><context:property-placeholder properties-ref="cloudProperties"/>
@Autowired private Environment environment;
@Beanpublic ComboPooledDataSource dataSource() throws Exception { String user = this.environment.getProperty ("cloud.services.mysql.connection.username"); ComboPooledDataSource cpds = new ComboPooledDataSource(); cpds.setUser(user); return cpds; }
Spring Environment Abstraction• Bean definitions for a specific environment (Profiles)
– e.g. development, testing, production– Possibly different deployment environments– Activate profiles by name
• spring.profiles.active system property• Other means outside deployment unit • “default” profile activates if no other profiles specified
• Custom resolution of placeholders– Dependent on the actual environment – Ordered property sources
39
Isolating Cloud Foundry Configuration
• Switch between local, testing and Cloud Foundry deployments with Profiles
40
Isolating Cloud Foundry Configuration
41
<bean class="org.sf.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/></bean>
<beans profile="cloud"> <cloud:data-source id="dataSource" /></beans><beans profile="default"> <bean class="org.a.commons.dbcp.BasicDataSource" id="dataSource"> <property name="url" value="jdbc:mysql://localhost/my_db" /> </bean></beans>
Cloud Properties
• Cloud Foundry uses Environment abstraction to automatically expose properties to Spring apps– Basic information about the application, such as its name and
the cloud provider– Detailed connection information for bound services
• cloud.services.{service-name}.connection.{property}• aliases for service name created based on the service type
– e.g. “cloud.services.mysql.connection.{property}”– only if there is a single service for that type bound
42
Cloud Properties Example
• Use service properties to create your own connection factories (e.g., with c3p0)
43
import com.mchange.v2.c3p0.* ;
@Autowired private Environment e;
@Bean public ComboPooledDataSource cpds (){ ComboPooledDataSource cpds = new ComboPooledDataSource ();
String host=e.getProperty("cloud.services.mysql.connection.host"), port=e.getProperty("cloud.services.mysql.connection.port"), name=e.getProperty("cloud.services.mysql.connection.name"), pw=e.getProperty("cloud.services.mysql.connection.password");
cpds.set...( host ... ); return cpds;}
Profile Support: How It Works
• Cloud Foundry installs a custom ApplicationContextInitializer in your app during staging– Modifies web.xml
• Adds to contextInitializerClasses context-param
• Adds a PropertySource to the Environment
44
Java Configuration
• Alternative to <cloud:*> namespace– Spring Java Configuration– Non-Spring apps
• Programmatic creation of service connection factories– Using ServiceCreator and ServiceInfo classes
• CloudEnvironment class provides access to all cloud properties and service info without requiring JSON parsing
• Included in cloudfoundry-runtime lib
45
Using ServiceCreator
46
//Provides access to CF service and application env infoCloudEnvironment environment = new CloudEnvironment(); //Retrieve env info for bound service named "mysqlService"RdbmsServiceInfo mysqlSvc = environment.getServiceInfo("mysqlService", RdbmsServiceInfo.class); //create a DataSource bound to the serviceRdbmsServiceCreator dataSourceCreator = new RdbmsServiceCreator();
DataSource dataSource = dataSourceCreator.createService(mysqlSvc);
Using ServiceInfo
47
//Provides access to CF service and application env infoCloudEnvironment environment = new CloudEnvironment(); //Retrieve env info for bound service named "mongoService"MongoServiceInfo mongoSvc = environment.getServiceInfo("mongoService", MongoServiceInfo.class); //create a Mongo DB bound to the serviceMongo mongoDB = new Mongo(mongoSvc.getHost(), mongoSvc.getPort());
C L O U D F O U N D RY
Demo
Using ServiceInfo
49
//Provides access to CF service and application env infoCloudEnvironment environment = new CloudEnvironment(); //Retrieve env info for bound service named "mongoService"MongoServiceInfo mongoSvc = environment.getServiceInfo("mongoService", MongoServiceInfo.class); //create a Mongo DB bound to the serviceMongo mongoDB = new Mongo(mongoSvc.getHost(), mongoSvc.getPort());
Any Questions?
Twitter:
Find session replays on YouTube: spring.io/video
@andypiper @starbuxman@springcentral @cloudfoundry