Migrate and deploy Cloud Foundry applications to Kubernetes
In this tutorial, you will transform a Cloud Foundry application to Kubernetes with the Move2Kube command-line tool. You’ll learn how to create deployment artifacts using Move2Kube’s three-step process: collect, plan, and transform.
In this activity, you will learn how to transform a Cloud Foundry application to Kubernetes with Move2Kube. We will walk through the steps to install the tool and then create deployment artifacts using Move2Kube’s three-step process: collect, plan, and transform.
This example uses data from the move2kube-demos repository on GitHub.
What is Move2Kube?
Move2Kube is a tool that helps automate your migration to Kubernetes from platforms like Cloud Foundry or Docker Compose. It analyzes source files, such as manifest files, and generates the deployment artifacts required to deploy the application in Kubernetes.
To transform a Cloud Foundry application to Kubernetes, simply execute the following command:
$ move2kube transform -s cloud-foundry
Move2Kube will automatically analyze the artifacts in the cloud-foundry
directory and transform and create all artifacts required for deploying the application in Kubernetes.
Prerequisites
First, you will need a directory that contains the source code files and the manifest.yml
file of a Cloud Foundry application. In this tutorial, we will use the cloud-foundry
sample directory from the move2kube-demos repository:
$ curl https://move2kube.konveyor.io/scripts/download.sh | bash -s -- -d samples/cloud-foundry -r move2kube-demos
Let's see the structure inside the ./cloud-foundry
directory. The cloud-foundry
directory contains the source code files and the manifest.yml
file:
$ tree cloud-foundry
cloud-foundry/
├── cfnodejsapp
│ ├── main.js
│ ├── manifest.yml
│ ├── package-lock.json
│ └── package.json
└── m2k_collect
└── cf
└── cfapps.yaml
Next, install the following tools:
To verify that dependencies were installed correctly, you can run any of the following commands:
$ move2kube version
$ docker version
$ podman info
$ kubectl version
Finally, install the Cloud Foundry CLI.
The example application
To demonstrate how to migrate a Cloud Foundry application to Kubernetes with Move2Kube, we will use the source code inside the cloud-foundry/cfnodejsapp
directory.
If you want to try out Move2Kube on your Cloud Foundry application, then in place of our sample cloud-foundry
directory, provide the path of the source directory (containing the source code and/or manifest files) of your Cloud Foundry application to Move2Kube during the plan phase.
Deploy to Cloud Foundry
Optional step: Here will deploy a simple Node.js application into Cloud Foundry. If you already have a running Cloud Foundry application, you can use that instead.
Provision a Cloud Foundry app with the name cfnodejsapp
using your cloud provider (e.g., IBM Cloud). Make note of the API endpoint. (You can find a list of supported API endpoints for the IBM Cloud Foundry service in the documentation).
Log in to Cloud Foundry using the following command:
$ cf login -a <YOUR CF API endpoint>
Run the following commands to deploy the sample application to Cloud Foundry. The sample application’s source code is present inside the ./cloud-foundry/cfnodejsapp
folder.
$ cf push -f ./cloud-foundry/cfnodejsapp -p ./cloud-foundry/cfnodejsapp
You can visit the URL of the application (you can get this by running cf apps
) to see it running.
Generate target artifacts
Now that we have a running Cloud Foundry application, we can transform it using Move2Kube. We will use a three-stage process (collect, plan, and transform) for the transformation. Be sure to run these steps from the directory where the cloud-foundry directory is located.
collect
We will first collect some data about our running Cloud Foundry application.
Note: This step is only necessary if you are interested in metadata such as environment variables from a running instance. If you don't have a running application, you can use the m2k_collect
directory that comes with the sample.
Here we will limit the collection to only Cloud Foundry information using the -a cf
annotation flag:
$ cf login -a <YOUR CF API endpoint>
$ move2kube collect -a cf
INFO[0000] Begin collection
INFO[0000] [*collector.CfAppsCollector] Begin collection
INFO[0013] [*collector.CfAppsCollector] Done
INFO[0013] [*collector.CfServicesCollector] Begin collection
INFO[0027] [*collector.CfServicesCollector] Done
INFO[0027] Collection done
INFO[0027] Collect Output in [/Users/username/m2k_collect]. Copy this directory into the source directory to be used for planning.
The data we collect will be stored in a new directory called ./m2k_collect
.
$ ls m2k_collect
cf
The ./m2k_collect/cf
directory contains a YAML file with runtime information about the application you are transforming. The file contains details about the supported buildpacks, the memory, the number of instances, and supported ports. If there are environment variables, it collects that information, too.
Move the ./m2k_collect/cf
directory into the source directory ./cloud-foundry
:
$ mv m2k_collect cloud-foundry/
plan
Next, we will create a plan to transform your application to run on Kubernetes. During the plan phase, Move2Kube will combine the runtime metadata (if available) with source artifacts and come up with a plan for us.
Here, we provide the path to the Cloud Foundry application’s source directory to Move2Kube using the -s
flag:
$ move2kube plan -s cloud-foundry
INFO[0000] Configuration loading done
INFO[0000] Planning Transformation - Base Directory
INFO[0000] [CloudFoundry] Planning transformation
INFO[0000] Identified 1 named services and 0 to-be-named services
INFO[0000] [CloudFoundry] Done
INFO[0000] [ComposeAnalyser] Planning transformation
INFO[0000] [ComposeAnalyser] Done
INFO[0000] [DockerfileDetector] Planning transformation
INFO[0000] [DockerfileDetector] Done
INFO[0000] [Base Directory] Identified 1 named services and 0 to-be-named services
INFO[0000] Transformation planning - Base Directory done
INFO[0000] Planning Transformation - Directory Walk
INFO[0000] Identified 1 named services and 0 to-be-named services in cfnodejsapp
INFO[0000] Transformation planning - Directory Walk done
INFO[0000] [Directory Walk] Identified 1 named services and 0 to-be-named services
INFO[0000] [Named Services] Identified 1 named services
INFO[0000] No of services identified : 1
INFO[0000] Plan can be found at [/Users/username/m2k.plan].
This creates an m2k.plan
, which is essentially a YAML file. Let's see what is inside the plan file:
$ cat m2k.plan
# click to see the full plan yaml
apiVersion: move2kube.konveyor.io/v1alpha1
kind: Plan
....
In the plan, you can see that Move2Kube has detected the cfnodejsapp
service—the name of our sample Cloud Foundry application—from its manifest.yml
.
The plan file tells us that we can transform the application using two transformers, CloudFoundry or Nodejs-Dockerfile.
The transformer can combine the source artifacts manifest.yml
with the runtime information from cfapps.yaml
to execute the transformation.
transform
Let's invoke move2kube transform
on this plan:
$ move2kube transform
INFO[0000] Detected a plan file at path /Users/username/m2k.plan. Will transform using this plan.
INFO[0000] Starting Plan Transformation
? Select all transformer types that you are interested in:
ID: move2kube.transformers.types
Hints:
[Services that don't support any of the transformer types you are interested in will be ignored.]
[Use arrows to move, space to select, <right> to all, <left> to none, type to filter]
> [✓] Buildconfig
[✓] CloudFoundry
[✓] ClusterSelector
[✓] ComposeAnalyser
[✓] ComposeGenerator
[✓] ContainerImagesPushScriptGenerator
[✓] DockerfileDetector
[✓] DockerfileParser
[✓] DotNetCore-Dockerfile
[✓] EarAnalyser
[✓] EarRouter
[✓] Golang-Dockerfile
[✓] Gradle
[✓] Jar
[✓] Jboss
[✓] Knative
[✓] Kubernetes
[✓] KubernetesVersionChanger
[✓] Liberty
[✓] Maven
[✓] Nodejs-Dockerfile
[✓] PHP-Dockerfile
[✓] Parameterizer
[✓] Python-Dockerfile
[✓] ReadMeGenerator
[✓] Ruby-Dockerfile
[✓] Rust-Dockerfile
[✓] Tekton
[✓] Tomcat
[✓] WarAnalyser
[✓] WarRouter
[✓] WinConsoleApp-Dockerfile
[✓] WinSLWebApp-Dockerfile
[✓] WinWebApp-Dockerfile
[✓] ZuulAnalyser
Let's go ahead with the default selection by pressing the Return or Enter key:
Buildconfig, CloudFoundry, ClusterSelector, ComposeAnalyser, ComposeGenerator, ContainerImagesPushScriptGenerator, DockerfileDetector, DockerfileImageBuildScript, DockerfileParser, DotNetCore-Dockerfile, EarAnalyser, EarRouter, Golang-Dockerfile, Gradle, Jar, Jboss, Knative, Kubernetes, KubernetesVersionChanger, Liberty, Maven, Nodejs-Dockerfile, PHP-Dockerfile, Parameterizer, Python-Dockerfile, ReadMeGenerator, Ruby-Dockerfile, Rust-Dockerfile, Tekton, Tomcat, WarAnalyser, WarRouter, WinConsoleApp-Dockerfile, WinSLWebApp-Dockerfile, WinWebApp-Dockerfile, ZuulAnalyser
? Select all services that are needed:
ID: move2kube.services.[].enable
Hints:
[The services unselected here will be ignored.]
[Use arrows to move, space to select, <right> to all, <left> to none, type to filter]
> [✓] cfnodejsapp
Here, we go ahead with the cfnodejsapp
service:
cfnodejsapp
INFO[0555] Iteration 1
INFO[0555] Iteration 2 - 1 artifacts to process
INFO[0555] Transformer CloudFoundry processing 1 artifacts
INFO[0555] Transformer CloudFoundry Done
INFO[0555] Created 0 pathMappings and 1 artifacts. Total Path Mappings : 0. Total Artifacts : 1.
INFO[0555] Iteration 3 - 1 artifacts to process
INFO[0555] Transformer Nodejs-Dockerfile processing 1 artifacts
? Select port to be exposed for the service cfnodejsapp :
ID: move2kube.services.cfnodejsapp.port
Hints:
[Select Other if you want to expose the service cfnodejsapp to some other port]
[Use arrows to move, type to filter]
> 8080
Other (specify custom option)
Select the port on which you want to expose the cfnodejsapp
service:
8080
INFO[0675] Transformer Nodejs-Dockerfile Done
INFO[0675] Created 2 pathMappings and 2 artifacts. Total Path Mappings : 2. Total Artifacts : 2.
INFO[0675] Iteration 4 - 2 artifacts to process
INFO[0675] Transformer DockerfileImageBuildScript processing 2 artifacts
? Select the container runtime to use :
ID: move2kube.containerruntime
Hints:
[The container runtime selected will be used in the scripts]
[Use arrows to move, type to filter]
> docker
podman
Select the container runtime you want to use:
docker
INFO[0744] Transformer DockerfileImageBuildScript Done
INFO[0744] Transformer DockerfileParser processing 1 artifacts
INFO[0744] Transformer ZuulAnalyser processing 2 artifacts
INFO[0744] Transformer ZuulAnalyser Done
INFO[0744] Transformer DockerfileParser Done
INFO[0744] Created 1 pathMappings and 4 artifacts. Total Path Mappings : 3. Total Artifacts : 4.
INFO[0744] Iteration 5 - 4 artifacts to process
INFO[0744] Transformer ClusterSelector processing 2 artifacts
? Choose the cluster type:
ID: move2kube.target.clustertype
Hints:
[Choose the cluster type you would like to target]
[Use arrows to move, type to filter]
> Openshift
AWS-EKS
Azure-AKS
GCP-GKE
IBM-IKS
IBM-Openshift
Kubernetes
Now you need to select the cluster type you want to deploy to. We’ll select the Openshift
cluster type:
Openshift
INFO[0842] Transformer ClusterSelector Done
INFO[0842] Transformer Buildconfig processing 2 artifacts
? What kind of service/ingress to create for cfnodejsapp's 8080 port?
ID: move2kube.services."cfnodejsapp"."8080".servicetype
Hints:
[Choose Ingress if you want a ingress/route resource to be created]
[Use arrows to move, type to filter]
Ingress
LoadBalancer
NodePort
> ClusterIP
Don't create service
Select the ClusterIP
to create a service in the OpenShift cluster:
ClusterIP
? Provide the minimum number of replicas each service should have
ID: move2kube.minreplicas
Hints:
[If the value is 0 pods won't be started by default]
Let's go ahead with the default option again—2 replicas for each service:
2
? Enter the URL of the image registry :
Hints:
[You can always change it later by changing the yamls.]
[Use arrows to move, type to filter]
Other (specify custom option)
index.docker.io
> quay.io
us.icr.io
Then you need to select the registry where your images are hosted. Here, we’ve selected quay.io.
Select Other
if your registry name is not listed.
quay.io
? Enter the namespace where the new images should be pushed :
ID: move2kube.target.imageregistry.namespace
Hints:
[Ex : myproject]
(myproject) username
Input the username or organization that you want to push an image to. For example, if you enter danieloh30
as the username, the image path will be quay.io/danieloh30/cfnodejsapp
.
danieloh30
? [quay.io] What type of container registry login do you want to use?
ID: move2kube.target.imageregistry.logintype
Hints:
[Docker login from config mode, will use the default config from your local machine.]
[Use arrows to move, type to filter]
Use existing pull secret
> No authentication
UserName/Password
Select No authentication
for the container registry login type:
No authentication
INFO[2439] Generating Buildconfig pipeline for CI/CD
INFO[2439] Generating Buildconfig pipeline for CI/CD
INFO[2439] Transformer Buildconfig Done
INFO[2439] Transformer ComposeGenerator processing 2 artifacts
INFO[2439] Transformer ComposeGenerator Done
INFO[2439] Transformer ContainerImagesPushScriptGenerator processing 2 artifacts
INFO[2439] Transformer ContainerImagesPushScriptGenerator Done
INFO[2439] Transformer ClusterSelector processing 2 artifacts
INFO[2439] Transformer ClusterSelector Done
INFO[2439] Transformer Knative processing 2 artifacts
INFO[2439] Transformer Knative Done
INFO[2439] Transformer ClusterSelector processing 2 artifacts
INFO[2439] Transformer ClusterSelector Done
INFO[2439] Transformer Kubernetes processing 2 artifacts
INFO[2439] Transformer Kubernetes Done
INFO[2439] Transformer ClusterSelector processing 2 artifacts
INFO[2439] Transformer ClusterSelector Done
INFO[2439] Transformer Tekton processing 2 artifacts
? Provide the ingress host domain
ID: move2kube.target.ingress.host
Hints:
[Ingress host domain is part of service URL]
(myproject.com)
It then asks for the Ingress hosting domain. You can get this from the cluster you are going to deploy to; however, you don't need to use Ingress because the Red Hat OpenShift cluster allows you to create a Route to access the application based on the fully qualified domain name (FQDN) domain. Go ahead with the default response by pressing the Return or Enter key.
ID: move2kube.target.ingress.host
Hints:
[Ingress host domain is part of service URL]
myproject.com
INFO[2780] Transformer Tekton Done
INFO[2780] Created 35 pathMappings and 9 artifacts. Total Path Mappings : 38. Total Artifacts : 8.
INFO[2780] Iteration 6 - 9 artifacts to process
INFO[2780] Transformer Parameterizer processing 5 artifacts
INFO[2780] Transformer Parameterizer Done
INFO[2780] Transformer ReadMeGenerator processing 6 artifacts
INFO[2780] Transformer ReadMeGenerator Done
INFO[2780] Plan Transformation done
INFO[2780] Transformed target artifacts can be found at [/Users/username/myproject].
Finally, the transformation is successful, and the target artifacts should be available inside the ./myproject
directory. To view the structure of the ./myproject
directory, execute the following command:
# click to see the output
$ tree myproject
You should see that all the deployment artifacts are present inside the ./myproject
directory.
Deploy the application to Kubernetes
Now it’s time to deploy the application. Let's get inside the ./myproject
directory:
$ cd myproject/
$ ls
Readme.md deploy scripts source
Run the builddockerimages.sh
script inside the ./myproject/scripts
directory. (This step might take some time to complete.)
$ cd scripts
$ ./builddockerimages.sh
[+] Building 1.9s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 747B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for registry.access.redhat.com/ubi8/nodejs-12:latest 1.7s
=> [internal] load build context 0.0s
=> => transferring context: 868B 0.0s
=> [1/3] FROM registry.access.redhat.com/ubi8/nodejs-12@sha256:1208ace959a40906e0e0e753b5ed5621c052a5a115e333d70ca8fa5e5c0dc0ca 0.0s
=> CACHED [2/3] COPY . . 0.0s
=> CACHED [3/3] RUN npm install 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:2d560a9a7b40f2d29447b57b619d55a5dd103ae5dd626cd517791f4ae8e61cbb 0.0s
=> => naming to docker.io/library/cfnodejsapp 0.0s
/Users/username/myproject
done
Now, using the pushimages.sh
script, we can push our application’s images to the registry we specified during the transform phase. For this step, you need to log in to your Docker registry. To log in to quay.io, run docker login quay.io
. To log in to the IBM Cloud us.icr.io registry, refer to the documentation.
$ ./pushimages.sh
Using default tag: latest
The push refers to repository [quay.io/danieloh30/cfnodejsapp]
44682b6a7ca8: Layer already exists
4d994360499e: Layer already exists
31226b9a7823: Layer already exists
718375ad3f65: Layer already exists
e0b9a99c51af: Layer already exists
ef5d9ad2a541: Layer already exists
93749af418e7: Layer already exists
latest: digest: sha256:197c820069a3691c727db3ccf0d544601035fdca6dba7b96bae16463068a5307 size: 1789
Note: If you pushed the image repository to quay.io, then in the Repository Visibility in the quay.io cfnodejsapp
repository settings, select whether you want the repository to be public so that the Kubernetes cluster can properly access it.
Finally, we will deploy the application with the oc apply
command using the YAML files that Move2Kube created for us in the ./myproject/deploy/yamls
directory.
We'll use Developer Sandbox for Red Hat OpenShift, a shared multitenant OpenShift cluster that is preconfigured with a set of developer tools. To access the sandbox, visit Get started in the Sandbox and sign up for free.
We will create Kubernetes resources in the OpenShift cluster using the oc
command line tool instead of kubectl. If you haven't already installed the oc
CLI, follow the instructions in this article: Where can I download the OpenShift command line tool?
Before you deploy the application, you need to log in to the OpenShift cluster on the sandbox. You can copy the oc
login
command with a valid token, as shown in Figure 1.
When you paste the oc login
command into your local terminal, the output should look like this:
$ oc login --token=sha256~_4yyHH7hAANsx7BchfB4xkclvdmWUAdt-efqZt0MVOQ --server=https://api.sandbox.x8i5.p1.openshiftapps.com:6443
Logged into "https://api.sandbox.x8i5.p1.openshiftapps.com:6443" as "USERNAME" using the token provided.
You have access to the following projects and can switch between them with 'oc project <projectname>':
* USERNAME-dev
USERNAME-stage
Using project "doh-dev".
ReplaceUSERNAME
with your own account name. Be sure to log in to the USERNAME-dev
project.
$ cd ..
$ oc apply -f deploy/yamls
deployment.apps/cfnodejsapp created
imagestream.image.openshift.io/cfnodejsapp-latest created
service/cfnodejsapp created
secret/cfnodejsapp-vcapasenv configured
Now our application is accessible on the cluster. You can check the status of pods by running the following command:
$ oc get pods
NAME READY STATUS RESTARTS AGE
cfnodejsapp-7f9ccb98d7-b97xn 1/1 Running 0 7s
cfnodejsapp-7f9ccb98d7-zhdnh 1/1 Running 0 7s
Create a Route to access the application via the FQDN URL:
$ oc expose svc/cfnodejsapp
route.route.openshift.io/cfnodejsapp exposed
You can get the route URL using the following oc
command:
$ oc get route
NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD
cfnodejsapp cfnodejsapp-doh-dev.apps.sandbox.x8i5.p1.openshiftapps.com cfnodejsapp port-8080 None
Access the application using the curl
command-line tool:
$ curl cfnodejsapp-doh-dev.apps.sandbox.x8i5.p1.openshiftapps.com
<h1>This is a node server</h1>
You can also make sure the application deployed successfully via the Topology view on the OpenShift cluster. Let's add a Node.js
label to the application pod using the following oc
command:
$ oc label deployment/cfnodejsapp app.openshift.io/runtime=nodejs --overwrite
deployment.apps/cfnodejsapp labeled
In the OpenShift web console, navigate to the Topology view in the Developer perspective. You will see the Node.js icon, as shown in Figure 2.
Click on the Open URL icon. This will take you to the application page, as shown in Figure 3
Conclusion
This tutorial demonstrated a simple way to perform a holistic transformation of your Cloud Foundry application to Kubernetes using the Developer Sandbox for Red Hat OpenShift. Visit the Developer Sandbox page to learn more.