Introduction
Cloud computing offers a remote hardware and runtime environment for your application, where a cloud computing service provider, like Cloud Foundry, is usually responsible for infrastructure setup and management. Such services present an easy way to achieve vertical scalability – application memory, disk space and CPU quota can be increased easily, as well as horizontal scalability – where the number of application instances can be increased or decreased on the fly, all without any hardware investment from the user’s side.
A cloud platform is often considered a realistic option for newly developed applications regarding cost reduction and configuration simplicity. In any case, having new cloud applications and retaining old infrastructure for legacy applications is expensive and complicated, with risks increased. Thus, when considering moving to the cloud, companies consider migrating legacy applications to the cloud as well, to keep their infrastructure approach unified.
Such migration is often not a straightforward process, since many aspects, apart from the technical ones, should be taken care of.
In this Techletter, we focus on our experience with the migration of a large Java application to the Cloud Foundry Platform. In the following, we will address the questions which should be answered before migration as well as the technical aspects of migration.
Things to consider before migration
One may think that only technical aspects limit the feasibility of cloud migration, which we will address in the next section, but there are other questions that need to be answered even before your application is migrated to the cloud.
For example, if your application processes sensitive user data, governmental requirements might exist to store such data within the country where the users are living. Does your Cloud Foundry provider support the storing/processing of highly sensitive data at all? Where will this data be stored geographically?
Business is involved into the migration process as well: will the licensing terms and costs of the third-party software components you are using be the same for the case where the software runs in a virtual container, and not on physical hardware? If your software system requires high availability, do you need a special service-level agreement with your cloud provider?
When it comes to operational changes, your new cloud applications will probably use a new monitoring toolchain, so your processes should be set up and, most importantly, the people who are responsible for the operation services should be trained to use the toolchain efficiently. Can such training courses be organised and conducted before your new cloud application goes live?
These topics are just as important as the technical aspects, seeing as ignoring them can lead to severe problems, damaged reputation or even lawsuits.
We recommend to separate migration aspects into technical and non-technical topics (considering the questions mentioned before) and provide full answers before the very first software release.
Technical Aspects of Migration
Before migrating your Web application to the cloud, it’s good to check if your application already complies with most of the parts of the Twelve-Factor App methodology (12factor.net), for example:
- The configuration is stored in the environment variables
- The build, release, and run stages are separated
- The application runs as a stateless process
- The development and production environments are almost identical
Existing applications usually need to be adapted for the cloud environment. Please note that even though our approach is based on our experience with the Cloud Foundry Platform, these aspects should remain valid for other cloud platforms too.
Architecture: A typical Web application running in the Cloud Foundry environment is able to use only one HTTP port that is accessible for the outside world, so if your application used to have more than one port for incoming HTTP requests, you will have to adapt your architecture accordingly.
Runtime: Applications in Cloud Foundry start in a pristine self-contained environment, which means you should not rely on storing any state information or log files on the filesystem where your application runs – those files will be gone after application restart. For logging purposes, consider using a Log Management Service provided by the cloud application service provider. Your Java application logging subsystem just needs to be reconfigured to use the standard output streams.
Network: Cloud Foundry provides “spaces” for running your applications – each space usually restricts all network traffic from the running applications to the outside world. If your software needs to connect to backend systems, you must create a “connectivity request” for each IP address and port you need to connect to. This has to be done only once, during the space setup and configuration. It’s better to prepare a list of the backends your application is using with their IP addresses and ports.
Complex applications may have to connect to hundreds of different backends, and you want to be sure that every connection is requested and indeed granted in the cloud, otherwise some parts of your application will not function properly. We recommend automating such connectivity checks by creating a simple script (Python or JavaScript) which can be run in your application’s Cloud Foundry space and will read a file with IP addresses and ports and check if all connections can be established.
CI/CD: In a perfect world, all software projects are built and tested on every code change using continuous integration (CI) and are immediately deployed using continuous deployment (CD). Existing projects sometimes lack one or both of these practices. It is a good idea to complement the cloud migration with setting up the CI/CD pipelines. You can even create a separate build project for your cloud application in the same repository, so that the cloud migration does not affect much of your existing build and deployment processes.
Setting up CD jobs for your cloud application helps to diagnose deployment problems earlier: for example, even though the whole infrastructure configuration should be easy, transparent and not changed by the cloud provider, be aware that this assumption of a perfect world may be wrong. Indeed, in our project, once the network provider changed firewall configuration and the CI server could not reach the cloud instances anymore, then one day our developers started using new third-party libraries which have dramatically increased application size, and deployment suddenly failed just because the application file became too big to be uploaded to the cloud. You don’t want to discover these problems a day before your shiny new cloud application goes to production.

Pic. 1 – A typical CI/CD workflow triggered on every code change
Package format: A legacy Java application often has its own deployment format – it might be a special start-up script which unpacks the application and starts it, or it even can be packetised differently, depending on the target environment: developer’s machine, CI or production server. When moving to the cloud, it’s a good idea to unify the application format so that the same application package can be run everywhere.
Some cloud migration paths suggest using the so-called “fat JAR” format for Java applications, which is fine for simple cases, but is prone to problems in large software projects. We’ve had very good experience with the “distZip” format, a zip file containing start-up script and all the JAR files needed to run the application. Such a zip file can be directly deployed and run in the Cloud Foundry. Using Gradle as a flexible build automation system allows you to easily create a distZip format file with the application: you just need to apply and configure the application plugin and the rest will be done automatically, including customisable start-up script generation for both Windows and Unix environments.
Troubleshooting: Sometimes you need to troubleshoot your application and want to see what the environment looks like – in this case you can use the Cloud Foundry command line interface (CLI) to log in via SSH to your application container and see the directories content or run some basic Linux utilities (like ‘top’ to see the current processes or ‘nc’ to test the connection to a problematic backend system). If the application crashes or does not start at all, there’s the possibility to provide a customised start-up command during deployment.
Conclusion
Migrating an existing Java Web application for the Cloud Foundry Platform is not always very straightforward. Our experience shows that the following steps are helpful to perform such a migration efficiently:
- Plan the migration project in advance and involve all stakeholders, including the data protection, business and operations departments.
- Start with a small proof-of-concept project and elaborate it iteratively to become your new cloud application.
- Automate everything: cloud connectivity checks, code integration and deployment.
- Use the single application file format for development, tests and production.
- Get familiar with the Cloud Foundry CLI.