By the end of this chapter the reader should be able to:
In the previous chapters, we've discussed the different options of deploying a software system to the cloud for the first time and later updating it. However, it's common that a software system is already deployed and in use before a need (or an opportunity) to migrate (move) it to the cloud arises. This migration can be from a traditional on-premises deployment or another cloud deployment. In this case, additional factors need to be taken into consideration.
In this chapter, we'll discuss the general process of migrating software system(s) to the cloud, the different strategies that can be used, and we'll migrate our WordPress application that we deployed in chapter 4 to a Kubernetes cluster as an example.
The figure below summarizes a general migration process with seven phases that start with identifying a reason for the migration to be considered and end with monitoring the new deployment. We'll discuss each of these phases below.
Figure 9.1: A General Migration Process
Any change in a running system involves a cost to investigate, plan and execute the change and an inevitable risk. So, unless there's a good reason for the change, most leaders would prefer not to take the risk. However, the case for migration has been increasingly evident, especially after the pandemic. Even before the pandemic, the benefits of using cloud technologies have been proven repeatedly by the increasing adoption.
So, in most situations, the case for cloud technology has already been made. However, it's not always the best idea, and not all systems are suitable for a cloud deployment. So, an analysis phase is needed to make an informed decision about the migration.
Big enterprises use multiple software systems to operate. For example, a university would have a Registration System, an HR system, a learning management system, a research support system … etc.
Those systems/subsystems constitute what's often referred to as the technology landscape. Each of these systems would need to be evaluated to determine whether it's suitable for the cloud and whether a return on investment (ROI) would make it worthwhile to make the move.
In addition to that, the complexity and risk involved in the migration need to be carefully considered as well.
A tool like StratoZone can help automate several aspects of that analysis.
In 2011 the research and consultancy institute Gartner identified four strategies commonly used for migration that started with R and called them the 4Rs mental model. Amazon adopted this mental model and added two more strategies, so now we have the 6Rs mental models for migration strategies. These strategies are described below.
The figure below summarizes the three strategies that require some change in the system.
Figure 9.2: Refactor, Replatform and Rehost Strategies
We can allocate the most suitable strategy for each system based on the landscape analysis.
If multiple systems were found to be suitable for the cloud, then they need to be prioritized, and a careful plan needs to be created for the migration. It's recommended that teams that don't have experience with cloud migration start with the least complex system to focus on gaining expertise before moving to the complex ones. Other details about the migration need to be decided at this phase as well, like deciding on the provider(s), the automation tools that can be used, … etc.
In this phase, the actual execution takes place, including preparing the target destination on the cloud and moving the system to that destination.
Like any software-related project, validation is an essential phase in which we ensure that the system is running as expected after the migration.
Finally, actively monitoring the migrated system helps identify and resolve any problems as soon as possible.
In Chapter 4, we deployed a WordPress web application using IaaS (GCE) for the webserver/middle-tier component and using PaaS (Cloud SQL) for the database component. Let's use that application to exercise working with migration.
Even though that was a cloud deployment, we know now that containerization would be a much better option. Also, let's say that the number of requests our application needs to serve varies over time, and we would like to utilize the flexibility provided by Kubernetes orchestration.
Even though we have one application, we would like to go more granular and evaluate the system's two components separately.
After monitoring the performance of the database component, we realized that it's coping well with the change in demand. Also, since this is the first migration, it's too risky to tamper with the data at the moment, so we'd rather keep the database component as-is.
The webserver/middle-tier component is the one that is problematic in terms of coping with the demand, and it's not as risky as losing our data.
Based on the analysis, we decided to Retain the database component. For the webserver component, we'll need to Re-platform to encapsulate it in a Docker container image and then Re-host it on a Kubernetes cluster.
Migrate for Anthos(M4A) is a great tool to automate many of the steps that we need to do. For a real migration, the planning step would include more project management activities, like timelines and role/responsibility assignments … etc. However, in this exercise, we'll focus on the technical plan.
Go to the Access scopes section and choose 'Allow full access to all Cloud APIs', then save.
$ export PROJECT_ID=<your-project-id>
The command to create the service account is:
$ gcloud iam service-accounts create <account-name> --project=$PROJECT_ID
so if I'm going to use the 'm4a-service-account' as the name, the command should look like this
$ gcloud iam service-accounts create m4a-service-account --project=$PROJECT_ID
after the account is created, we can refer to it later using the email address with the format
<service-account-name>@<Project-ID>.iam.gserviceaccount.com
might as well store this value in an environment variable to make it easier to reference later. I'll name the variable m4a-sa
export m4a_sa=m4a-service-account@$PROJECT_ID.iam.gserviceaccount.com
We can download the key for this account into a json file using the following command
$ gcloud iam service-accounts keys create m4a-key.json --iam-account=$m4a_sa \
> --project=$PROJECT_ID
$ gcloud container clusters create migration-cluster --project=$PROJECT_ID \
> --zone=us-central1-a --num-nodes 3 \
> --subnetwork "projects/$PROJECT_ID/regions/us-central1/subnetworks/default"
Download the cluster's credentials to be able to access it later:
$ gcloud container clusters get-credentials migration-cluster --zone us-central1-a
$ gcloud projects add-iam-policy-binding $PROJECT_ID \
> --member="serviceAccount:$m4a\_sa" --role="roles/storage.admin"
Now, we need to use the migctl command-line tool to start the installation using the key of the service account that we've prepared
$ migctl setup install --json-key=m4a-key.json
You can check the installation using the command $migctl doctor; it may take a while before the installation is complete; just keep checking until you see the first three items with a green check. As you can see in the figure below, the source status is not configured yet. We'll take care of that in the next set of steps
Grant the service account the ability to view the GCE instance and access its storage by creating a policy binding that connects the service account to the compute.viewer role and the compute.storageAdmin role
$ gcloud projects add-iam-policy-binding $PROJECT_ID \
> --member="serviceAccount:$m4a_sa" --role="roles/compute.viewer"
$ gcloud projects add-iam-policy-binding $PROJECT_ID \
> --member="serviceAccount:$m4a_sa" --role="roles/compute.storageAdmin"
Now we can create a compute engine (ce) source object using the key of the service account
$ migctl source create ce <object-name> --project $PROJECT_ID \
> --json-key=m4a-key.json
so if I'm going to name this object gce-source-obj the command should look like this:
$ migctl source create ce gce-source-obj --project $PROJECT_ID \
> --json-key=m4a-key.json
After the source object is create, we can see that the source status is now checked
$ migctl migration create wordpress-migration \
> --source <name-of-source-object> --vm-id <name-of-gce> --intent Image
$ migctl migration create wordpress-migration \
> --source gce-source-obj --vm-id wordpress-webserver --intent Image
Keep checking the object's status using the command below until it's ready.
$ migctl migration status wordpress-migration
A migration plan is automatically created and ready to use. We can download it as a YAML file using the command
$ migctl migration get wordpress-migration
If we would like to customize the migration plan, we can just edit that file then upload it to m4a using the command
$ migctl migration update wordpress-migration
By asking m4a to create the artifacts based on the generated plan
$ migctl migration generate-artifacts wordpress-migration
Again, keep checking the status until the artifacts are ready
$ migctl migration status wordpress-migration
Download the generated artifacts using the following command
$ migctl migration get-artifacts wordpress-migration
The artifacts generated include the Dockerfile to create the image and a YAML (deployment_spec.yaml) file to describe the configuration for the Kubernetes deployment and service objects
Open the deployment_spec.yaml in an editor like vi and add the following service object specifications to it
apiVersion: v1
kind: Service
metadata:
name: wordpress-lb-service
spec:
selector:
app: wordpress-webserver
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer
$ kubect apply -f deployment_spec.yaml
Wait for the external-ip to be generated, then send an HTTP request to it to see the new deployment
You should be able to see the WordPress home page. However, the picture is missing, the format is off, and if you click on any link, you'll get a TIME_OUT error as the requests from the links will be sent to the old IP address stored in the database.
Connect to the DB server through the client
$ mysql -h <ip-of-the-sql-instance> -u wordpress --password=<wordpress-client-user>
Switch to the WordPress database schema
MySQL [(none)]> use wordpress
Update the IP value in the wordpress.wp_options
MySQL [(wordpress)]> update wordpress.wp_options
set option_value = '<LoadBalancer IP>'
where option_name in ('siteurl','home');
commit;
Verify that the values were updated by selecting the rows we just updated
MySQL [wordpress]> select * from wordpress.wp_options where option_name in ('siteurl','home');
Now, if we send a request to that IP, we should be able to see a properly functioning application.
$ kubectl scale deployment wordpress-webserver-mig-test --replicas=10
In this chapter, we discussed the concepts related to cloud migration, including the general process and the common strategies used for different systems. For the Hands-On component of the chapter, we migrated the WordPress application that we deployed in chapter 4 to a Kubernetes cluster using migctl tool.
[GCP Screenshots] "Google and the Google logo are registered trademarks of Google LLC, used with permission."
Unless otherwise stated, all images in this chapter were created by the author Shaimaa Ali using either MS PowerPoint or MS Visio or both. Code screenshot made using MS VSCode.
© Shaimaa Ali 2022