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.
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
$ 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
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
$ 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.
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 Begin collection INFO [*collector.CfAppsCollector] Begin collection INFO [*collector.CfAppsCollector] Done INFO [*collector.CfServicesCollector] Begin collection INFO [*collector.CfServicesCollector] Done INFO Collection done INFO 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
$ ls m2k_collect cf
./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.
./m2k_collect/cf directory into the source directory
$ mv m2k_collect cloud-foundry/
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
$ move2kube plan -s cloud-foundry INFO Configuration loading done INFO Planning Transformation - Base Directory INFO [CloudFoundry] Planning transformation INFO Identified 1 named services and 0 to-be-named services INFO [CloudFoundry] Done INFO [ComposeAnalyser] Planning transformation INFO [ComposeAnalyser] Done INFO [DockerfileDetector] Planning transformation INFO [DockerfileDetector] Done INFO [Base Directory] Identified 1 named services and 0 to-be-named services INFO Transformation planning - Base Directory done INFO Planning Transformation - Directory Walk INFO Identified 1 named services and 0 to-be-named services in cfnodejsapp INFO Transformation planning - Directory Walk done INFO [Directory Walk] Identified 1 named services and 0 to-be-named services INFO [Named Services] Identified 1 named services INFO No of services identified : 1 INFO 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
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.
move2kube transform on this plan:
$ move2kube transform INFO Detected a plan file at path /Users/username/m2k.plan. Will transform using this plan. INFO 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 INFO Iteration 1 INFO Iteration 2 - 1 artifacts to process INFO Transformer CloudFoundry processing 1 artifacts INFO Transformer CloudFoundry Done INFO Created 0 pathMappings and 1 artifacts. Total Path Mappings : 0. Total Artifacts : 1. INFO Iteration 3 - 1 artifacts to process INFO 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
8080 INFO Transformer Nodejs-Dockerfile Done INFO Created 2 pathMappings and 2 artifacts. Total Path Mappings : 2. Total Artifacts : 2. INFO Iteration 4 - 2 artifacts to process INFO 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 Transformer DockerfileImageBuildScript Done INFO Transformer DockerfileParser processing 1 artifacts INFO Transformer ZuulAnalyser processing 2 artifacts INFO Transformer ZuulAnalyser Done INFO Transformer DockerfileParser Done INFO Created 1 pathMappings and 4 artifacts. Total Path Mappings : 3. Total Artifacts : 4. INFO Iteration 5 - 4 artifacts to process INFO 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 Transformer ClusterSelector Done INFO 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
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
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
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
No authentication for the container registry login type:
No authentication INFO Generating Buildconfig pipeline for CI/CD INFO Generating Buildconfig pipeline for CI/CD INFO Transformer Buildconfig Done INFO Transformer ComposeGenerator processing 2 artifacts INFO Transformer ComposeGenerator Done INFO Transformer ContainerImagesPushScriptGenerator processing 2 artifacts INFO Transformer ContainerImagesPushScriptGenerator Done INFO Transformer ClusterSelector processing 2 artifacts INFO Transformer ClusterSelector Done INFO Transformer Knative processing 2 artifacts INFO Transformer Knative Done INFO Transformer ClusterSelector processing 2 artifacts INFO Transformer ClusterSelector Done INFO Transformer Kubernetes processing 2 artifacts INFO Transformer Kubernetes Done INFO Transformer ClusterSelector processing 2 artifacts INFO Transformer ClusterSelector Done INFO 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 Transformer Tekton Done INFO Created 35 pathMappings and 9 artifacts. Total Path Mappings : 38. Total Artifacts : 8. INFO Iteration 6 - 9 artifacts to process INFO Transformer Parameterizer processing 5 artifacts INFO Transformer Parameterizer Done INFO Transformer ReadMeGenerator processing 6 artifacts INFO Transformer ReadMeGenerator Done INFO Plan Transformation done INFO 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
Deploy the application to Kubernetes
Now it’s time to deploy the application. Let's get inside the
$ cd myproject/ $ ls Readme.md deploy scripts source
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
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
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".
USERNAMEwith your own account name. Be sure to log in to the
$ 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 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 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
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.