A factor-by-factor guide to creating a 12-factor application on WAS Liberty. If you follow the 12-factors methodology you’ll have a portable application that’s great for running on the cloud and can be maintained easily in a continuous delivery pipeline. This also lends itself nicely to a microservices architecture.

What is a 12-factor applicaton and why should you care?

The 12-factor app is a methodology defined by the developers at Heroku for building platform-as-a-service applications that (quoting from 12factor.net):

  • Use declarative formats for setup automation, which minimizes time and cost for new developers joining the project;
  • Have a clean contract with the underlying operating system, offering maximum portability between execution environments;
  • Are suitable for deployment on modern cloud platforms, removing the need for servers and systems administration;
  • Minimize divergence between development and production, enabling continuous deployment for maximum agility;
  • Can scale up without significant changes to tooling, architecture, or development practices.

In other words if you follow the 12-factors methodology you will have a portable application that is great for running on the cloud and can be maintained easily in a continuous delivery pipeline. This also lends itself nicely to a microservices architecture. You can read more about microservices in the IBM Redbook or on DeveloperWorks.

WAS Liberty has several characteristics that make it ideal for cloud deployment. Hopefully you all know what WAS Liberty is by now (an awesome application server that recently became fully Java EE7 compliant) but if you want to hear more about how Liberty got to where it is now you can read all about it in Holly’s blog post.

Our sample 12-factor application

Rather than try to talk about the 12 factors as abstract concepts we have developed a Liberty application to use as a reference. The application is a data persistence service for some polling application. The polling application communicates with our app using REST requests which allows it to send data and get back previously stored data. This functionality is enabled using the jaxrs-2.0 feature which allows us to make our application accessible by HTTP requests by doing 3 simple things:

  1. Add the jaxrs-2.0 feature to the server.xml of your Liberty server
  2. Add a class to your application that extends javax.ws.rs.Application and has an @ApplicationPath annotation:
    
    package net.wasdev.twelvefactorapp;
    
    import javax.ws.rs.ApplicationPath;
    import javax.ws.rs.core.Application;
    
    @ApplicationPath("/")
    public class JaxrsApplication extends Application {}
    
      

  3. Create a method that is annotated with @GET (and maybe @Produces(…) to specify a media type to return)
    
    @Path("/")
    public class JaxrsHttpReceiver {
    
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public Reponse getResponse() {
           ...
    }
    
      

To hit the getReponse() method you just need to send a HTTP GET request to the context root of your application. (By the way if you want to see some more in depth and cool things that you can do with JAX-RS see this GitHub sample by Erin.)

Our application will use a Cloudant instance hosted on Bluemix and access the database using the Cloudant REST API. When built our application is a ZIP file that contains a packaged Liberty server with a WAR file and the server.xml configuration needed to run the application. It can be run on a local Liberty server or deployed to Bluemix. You can find the app on our GitHub page, it is accessible by HTTP requests and reads and writes data to a Cloudant database hosted on Bluemix.

So let’s get started:

If you want to follow along with the application, head on over to our GitHub page and follow the readme to build your own copy of the app and Cloudant database instance.

Factor 1 – Codebase

“One codebase tracked in revision control, many deploys”

As I mentioned above, the application is stored in a git repository hosted on Github. Git is a revision control tool to allow more than one person to develop a project at once and to make sure that all of your code is safe. Alternatively you can use Bluemix DevOps Services, which combines version control (git) with planning and deployment tools to provide a continuous development and delivery pipeline.

Factor 2 – Dependencies

“Explicitly declare and isolate dependencies”

In our sample application we have dependencies on certain Liberty features, more specifically servlet-3.1, jsonp-1.0 and jaxrs-2.0. Our application must pull down all of the dependencies it requires during the build process. To build this sample we have provided two options: Maven and Gradle. In both cases you declare the dependencies in the build file (pom.xml for Maven or build.gradle for Gradle) and the required packages are downloaded from Maven Central Repository at build time to compile the code. The packaging step uses the Maven or Gradle Liberty plug-ins to pull down a Liberty runtime from the Liberty Repository and produces a packaged Liberty server containing the server configuration and a WAR file with the compiled application code. As a result the application does not have any dependencies that it assumes will already exist on the system.

Factor 3 – Config

“Store config in the environment”

In simple terms this means that we shouldn’t put any environment-specific configuration in the application. The application shouldn’t care what environment it is running in and we shouldn’t need to change the app to run it in a different environment. For our specific application, we need the configuration details for the Cloudant database. We are using the same Cloudant database in both the local and Bluemix environments, and accessing it via the REST API provided by Cloudant. We need the URL to access Cloudant, and to abide by the 12 factors we have chosen to store this information in environment variables. When pushing applications to Bluemix you can provide a manifest.yml file to specify environment variables.


---
applications
- name: 12-factor-application
env:
   dbUsername: <cloudant-username>
   dbPassword: <cloudant-password>
   dbUrl: <cloudant-url>

  

Alternatively if you use the IBM Bluemix Eclipse plug-in it gives you the option to specify environment variables when you push your application. Either way the configuration is stored in the environment and accessed at runtime rather than ingrained into the code.

Factor 4 – Backing Services

“Treat backing services as attached resources”

As mentioned in Factor 3 we can access the Cloudant database through a REST API. We can use the jaxrsClient-2.0 Liberty feature (enabled by the jaxrs-2.0 feature) to build HTTP requests to send to the API. For example here is a GET request:


public String getDatabaseFiles() {
    String authorizationHeaderName = "Authorization";
    String authorizationHeaderValue = "Basic " +
        javax.xml.bind.DatatypeConverter.printBase64Binary((username + ":" + password).getBytes());

    Client client = ClientBuilder.newClient();
    WebTarget target = client.target(dbUrl);
    Invocation.Builder invoBuild = target.request(MediaType.APPLICATION_JSON)
        .header(authorizationHeaderName, authorizationHeaderValue);
    Response httpresponse = invoBuild.get();
    String contents = httpResponse.readEntity(String.class);
    httpResponse.close();
    return contents;
}

  

We can also use a PUT request to create a database for example:


public String createDatabase(String name) {

    // ... see above for start of method
    String url = dbUrl + "/" + name;
    WebTarget target = client.target(url);
    Invocation.Builder invoBuild = target.request(MediaType.APPLICATION_JSON)
        .header(authorizationHeaderName, authorizationHeadervalue);
    Response httpResponse = invoBuild.build("PUT", null).invoke();
    // ... see above for end of method
}

  

Factor 5 – Build, release, run

“Strictly separate build and run stages”

Factor 5 focuses on getting a clearly defined process with no cycles. The build stage should build everything you need; there should be no additional build steps when packaging a build with configuration to form a release artifact nor when running the application.

For our sample, the build stage is clearly defined by the Maven/Gradle tools; the output of a build is a packaged server containing all of the environment agnostic config required to run the application. For the release stage we push a manifest.yml file and the packaged server to Bluemix. The manifest.yml is used to specify the environment variables we want in Bluemix, which in this case is the Cloudant configuration:

---
env:
   dbUsername: <cloudant-username>
   dbPassword: <cloudant-password>
   dbUrl: <cloudant-url>
  
$ cf push <application-name> -p /path/to/12FactorApp.zip -f /path/to/manifest.yml

Once Bluemix has finished deploying your application it will start it up for you, this is the run stage. You can start and stop your application from the dashboard in Bluemix or from the Servers tab in Eclipse if you add the Bluemix Eclipse plug-in.

When running locally the release stage is unzipping the packaged server into a runtime, or other suitable location and defining the environmental variables you require, e.g. Cloudant config and a WLP_USER_DIR. Then to run the application you simply navigate to the bin directory of your Liberty runtime and start the server:

$server run 12FactorAppServer

Factor 6 – Processes

“Execute the app as one or more stateless processes”

This is a very useful factor as it means that if one instance of your application goes down you don’t lose the current state. It also simplifies workload balancing as your application doesn’t have an affinity to any particular instance of a service. In our sample application, persistent state is stored in the database. Any information required to process a request is either included in the request (as any proper invocation of a REST API would do), or is retrieved from the database.

The application does not rely on an established session to satisfy new requests. In fact if your application is deployed onto Bluemix then this factor is almost achieved by default because Bluemix starts and stops process instances for you, and those instances are transient. This means that if your application needs to store state, it has to use a persistent datastore to do so.

Factor 7 – Port binding

“Export services via port binding”

The key for this factor is that the host and port used to access the service should be provided by the environment, not baked into the application, and that you aren’t relying on pre-existing or separately configured services for that endpoint. As mentioned in earlier factors, the release artifact (the packaged server in our sample) contains what is needed to configure and run your application. In Bluemix deployment we could get away with simply pushing a WAR file rather than a packaged server (since Bluemix has its own copy of Liberty) but in all cases, instance-specific attributes like host and port can (and should) be provided by the environment.

If your application is running on a local Liberty server the application would be accessed by visiting http://localhost:9082/12-factor-application/. This points to a specific host and port where your application can be found and the default context root for a Liberty application (the name of the application). In a 12-factor application it makes much more sense to use Bluemix since it creates and manages routes to instances of your application when it is deployed (usually .mybluemix.net). When you want to access your application you simply visit the root context for the route.

Factor 8 – Concurrency

“Scale out via the process model”

This one is an easy factor to fulfill if you deploy to Bluemix. Bluemix comes ready made with both vertical and horizontal scaling. This can be done using the Cloud Foundry Command Line Interface:

$ cf scale APP -i INSTANCES

Alternatively you can do it in the Bluemix dashboard. Bluemix also provides an Autoscaling Service that, when bound to your application, will manage all of the scaling for you.

Factor 9 – Disposability

“Maximize robustness with fast startup and graceful shutdown”

One of the most shouted-about features of Liberty is how quick server startup and shutdown is. Of course since you can make updates to both your app and your server without having to do a restart this is not something that is used often but it does fit nicely with this factor. Since Bluemix’s Java application server of choice is Liberty, you get the benefits on the cloud as well. Bluemix does not require specific cleanup or extra setup between restarts so between the two we can easily create apps with disposability.

Applications also have to ensure they are disposable. Our application does not perform extra configuration steps during startup and does not require any clean up operations to be performed during shutdown. As a result we have an application that starts quickly and can be easily restarted if something goes wrong.

Factor 10 – Dev/prod parity

“Keep development, staging, and production as similar possible”

Since you can do development, staging, and production on Bluemix the simple (and perhaps cheeky) answer here is to do development, staging, and production on Bluemix!

That said, development and preliminary testing can be performed locally, The popularity of Docker images makes standing up test instances of Cloudant or other datastores fairly painless. As the location and credentials for accessing the service are provided by environment variables, it is easy to put together a production-like environment for local testing. If you use the WebSphere Devloper Tools (WDT) to do local development you also get the benefit of incremental publish, which allows you to make live changes to your application without having to go through packaging and release steps at development time.

It is also interesting to note that running a server locally is a good method for testing. Since the server is so quick to startup, rather than having to build a mocking server to run unit tests with, you can actually just run them on a Liberty server without having to have a test suite that takes hours to run.

Factor 11 – Logs

“Treat logs as event streams”

When your application is deployed in Bluemix using the Liberty buildpack (which is the default and what our sample does), anything you write toSystem.out will be included in the messages.log that can be found in the Files and Logs tab on Bluemix.

If you deploy your application to a different environment without the Liberty buildpack (e.g. using a docker image with the IBM Container Service), it may be more appropriate to send all logging and trace from Liberty and your application to standard out. This is more consistent with this factor, which recommends that everything should be sent to the system streams so the containing/hosting environment can deal with it. This can be easily achieved by adding a bootstrap.properties file containing com.ibm.ws.logging.trace.file.name=stdout to your server folder (at the same level as server.xml).

If you take the Bluemix approach and are looking for more detailed information you can also make use of the Monitoring and Analytics service on Bluemix. This is a handy way to keep track of all of your applications and view in depth analytics of your applications at all stages; development, test and production.

Factor 12 – Admin processes

“Run admin/management tasks as one-off processes”

It took a while to decide on a realistic admin process for us to run on our simple application. Examples given on 12factor.net include migrating databases and running one-time scripts to do cleanup – things a small getting-started sample doesn’t usually need to do! We finally settled on gathering statistics about our application.

The monitor-1.0 Liberty feature provides a servlet MXBean that reports runtime and access statistics, such as the application name, servlet name, and request count. This information is normally accessed using a JMX client, but by also enabling the restConnector-1.0 feature we can access the JMX clients using REST requests. Other MBeans are also available, you can view the full list by visiting the /IBMJMXConnectorREST/mbeans/ context root and entering the username and password of the quickStartSecurity element in the server.xml.

In the sample app we have created a servlet which can be accessed using the context root /12-factor-application/admin/stats which collects the request count details from the JMX connector, parses it, and displays the data. This servlet is deployed as part of the application but is only invoked as a one-off admin process.

Conclusion

So that concludes the 12 factors. Hopefully this article has helped you to put the 12 factors into context, understand how they apply to real-life applications, and what tools are available to help you when you are developing your application.

1 comment on"Creating a 12-factor application with WAS Liberty"

  1. […] and some are aspects of the surrounding environment. Kate has just published a sample and accompanying documentation that walks through all 12 factors and shows how to build a 12-factor application using JAX-RS 2.0 […]

Join The Discussion

Your email address will not be published. Required fields are marked *