Part 1: Best practices for migrating your Cloud Foundry app to IBM Cloud Code Engine.
Last year, I blogged about lessons learned from migrating a Cloud Foundry app to IBM Cloud Code Engine. Since then, IBM Cloud Code Engine evolved and I got more experience in migrating apps to the service. With that in mind, I am going to write about my best practices for migrating apps from IBM Cloud Foundry to Code Engine.
For that purpose, I took a common cloud-native app that follows the 12-factor app principles, simplified and updated its code, and created both a Cloud Foundry and a Code Engine version. It serves as an example for the discussion of migration steps and deployment aspects.
In this blog post, I will mostly focus on service binding and the actual code migration. In a follow-up article, I will then look at topics like the build process and DevOps impact, scaling and high availability setup, and I will share further thoughts on security and compliance:
Overview
The sample solution for this blog is a typical web app. It is written in Node.js (JavaScript) and uses the Express web framework. An IBM Cloudant NoSQL database serves as the backing service to store data displayed by the app. As typical for cloud-native/12-factor apps, the sample solution is based on discrete, reusable components that act as microservices to make up the overall app. Both the deployed Node.js program and the database can be scaled, improved or even replaced independently. They work together because of how they are configured and by using well-defined APIs.
Thus, the IBM Cloudant database can be configured to work as an attached resource with the app versions deployed to Cloud Foundry and Code Engine. This is shown in the architecture diagram above. For simplicity, the solution is kept to these two components. When accessed from the web browser, the following page is shown with parts retrieved from the database:
To migrate an existing solution from Cloud Foundry to Code Engine, several things (might) need to be considered:
- Code migration
- Service binding
- Build and deployment process (e.g., commands, toolchain integration, DevOps)
- Scaling and resource management, including high availability
- Routing
- Security and compliance
The above depends on the complexity of your solution, its performance and availability requirements, organisational characteristics and more. Because code migration depends on the strategy for service binding, we will discuss service binding first.
For the discussion, I assume that you have already looked into IBM Cloud Code Engine and are familiar with its basic concepts of project, build and app. If not, the documentation page on migrating Cloud Foundry applications to Code Engine is a good source to get started.
Service binding
The Cloudant database is required for the app to work properly. It could be configured by manually injecting environment variables, but the typical process is through service binding. The relationship between the app and its backing services is explicitly stated, so credentials are created and automatically injected into the runtime environment. Cloud Foundry provides the credentials as part of the VCAP_SERVICES object. Code Engine mimics it through its CE_SERVICES environment variable.
We already mentioned that the architecture diagram shows both the Cloud Foundry and Code Engine app attached to the database service. The code deployed to Code Engine can be considered a different, newer version of the Cloud Foundry app. It continues to be bound to the same database service, but through other means.
To bind the Code Engine version of the app to a service, I recommend the following approach:
- Create an IAM service key (credential) with a descriptive name. You need to specify the IAM role (e.g., Manager, Writer or Reader). Pick one that works for the app but has the least privileges.
- Bind the service to the app by using the existing credential.
Code Engine can create credentials for you during service binding, but I prefer to create them on my own. This gives greater control and I can easily track and even revoke them independently of Code Engine. If you prefer to have Code Engine create the credentials, you need to assign the required privileges.
For the sample app with Cloudant as the database service, the above would require the following two commands to create the service key “Cloudant-CF2CE-Manager” with Manager role and use it for the binding:
If your Cloud Foundry app connects to a service via a so-called user-provided service, I recommend utilizing secrets and configmaps for Code Engine. That way, you can inject the service credentials into the runtime environment and manage them as a named object within the Code Engine project.
Code migration
In most cases, code migration is straight-forward and relatively simple. Instead of reading from an environment variable VCAP_SERVICES for Cloud Foundry, it would be CE_SERVICES for Code Engine. There might be subtle differences in how services are named. This results from the way services are made available via brokers to Cloud Foundry and to the IBM Cloud IAM-based resource management.
Depending on the programming language, your code might utilize a code library or module to access the Cloud Foundry runtime environment, locally injected configuration (“dotenv”) and more. Those sections need to be adapted.
My recommendation is to perform the code migration with an intermediate step:
- The Cloud Foundry code base as the initial source. See the branch 1cloudfoundry_base of the sample app for details.
- Add code to also support a Code Engine deployment. This is shown in the 2cf_ce_intermediate_hybrid branch.
- Finally, move to a Code Engine-only code base after the actual project migration is completed. See the branch 3codeengine_target for the stripped code.
That approach is beneficial because you can continue to maintain or enhance the code base during the migration process, independently of the deployment environment. The screenshot below shows that hybrid code section on the intermediate branch. First, the old code checks for settings as if present in a Cloud Foundry environment. Then, the newer code looks for a Code Engine environment to retrieve the configuration:
Conclusions
In this blog post, I provided an overview of topics to consider when migrating an app from Cloud Foundry to Code Engine. I introduced a sample app and its GitHub repository to discuss service bindings and code migration. The app will also serve as foundation for a follow-up post to look at build and deployment aspects, high availability, and security and compliance.
- See the GitHub repository for the app and more resources.
- My blog from last year: “Migrating from Cloud Foundry to Code Engine“
If you have feedback, suggestions, or questions about this post, please reach out to me on Twitter (@data_henrik) or LinkedIn.