Migrate your legacy web apps to Azure without the Big Bang: 6 vital steps for a smooth migration

Traditionally, migration of software solutions from one platform to another has been tedious and riskful (do I need to mention all the horror stories of migration of apps between different versions of Windows Server?). And often the only choice is to do a Big Bang migration where the whole newly-migrated system is released and deployed at a single event. Countless are the times where I, as a developer, have been sitting up all night fixing issues caused by a Big Bang migration. You can only test so much – the real test is production (TM).

I have been involved a lot with the assessment and migration of legacy apps to Azure the last couple of years (and especially after I started my company, 2G CLOUD).

The steps presented in this blog post are based on hard-earned experience in the assessment and migration of a lot of legacy apps to Microsoft Azure. You will not find these steps in the Azure Documentation or any books (to my knowledge, at least). Feel to give me some feedback in the comments section.

I use the word “web app” in this blog post to describe a software system which ultimately exposes its functionality through web technologies (e.g. as a website/HTML to a web browser, or as a REST/SOAP APIs to an API client). A “web app” can consist of web apps (e.g., ASP.NET MVC app) or API apps, as well as databases, file share, queues etc.

Step 1: Deploy Azure Application Insights as soon as possible

In this step, your whole legacy web app still runs production on-premises in some non-Azure datacenter. Either in your own data center or at your hosting provider’s data center – or somewhere else. Before deploying (to production) a full migration of your legacy app to Azure, it is important to get accurate insights into how the application runs in production. You can add support for Application Insights (actually, it is now called Azure Monitor, but that’s another story) to many legacy web apps with little or no code changes (especially for .NET and Java apps).

Once you add Azure Application Insights support to the legacy on-prem web app, you get a lot of valuable insights. Here are some things to look out for:

  1. Is the web apps very database-chatty: do the apps perform a lot of small database queries at each request? If so, the web apps often expect the network to the database to be: low-latency, high-bandwidth, and ultra-stable. In these cases, the web app and database are often deployed to the same server, or they reside in the same server rack. If you want to migrate your legacy web app to Azure App Services with Azure SQL as the database, then the on-prem solution will almost always be faster (performance-wise) – but with some modifications, things can turn around (but that’s probably a topic for a future blog post)
  2. Do the web apps call a lot external 3rd-party services: each 3rd-parse service poses an integration risk. Make sure that you can call all 3rd party services from Azure.
  3. Long-running requests that perform long-running database queries: they might be subject for caching or subject for a headache.

 

Step 2: Use Application Gateway for websites and API Management for REST/SOAP APIs

Azure Application Gateway and Azure API Management are “application delivery controllers” (ADC) for websites and API apps (REST, SOAP) respectively.

In this case Application Gateway and API Management provides the following benefits:

  • Shields our web app from the evil, public Internet by applying the needed security measures and network features
  • Works as a reverse proxy thus making us able to switch instantly between on-prem and Azure instances as needed
  • A public endpoint to monitor with, e.g., Application Insights.

 

Step 3: Apply an Azure-based HTTP traffic routing infrastructure

Having a single well-defined endpoint for each web app is important: a consumer of the web app (e.g., a web browser, if it is a website, or a REST client, if it is an API app) knows that if a well-defined endpoint is called, you will always reach the desired web app. Behind the scenes, you might still hit the on-prem web app, or you might hit a newly-migrated Azure instance of the same web app. But the consumer of the web app doesn’t care. The consumer only wants to talk to the web app regardless if it resides in Azure or on-prem.

The traffic routing services that I use the most in this step are:

Common to the above three services is that they all support weighted traffic routing which is needed in Step 5.

Note that Azure Application Gateway and Azure API Management also route HTTP traffic, and in Step 6 you get some hints on how to clean things up, so you don’t end up running redundant services.

Also, note that it requires some work and planning to apply this routing infrastructure to production. But it is not rocket science either.

Step 4: Move the “data layer” to Azure

Most legacy apps use some databases (often MS SQL Server, MySQL or Oracle) to store relational data, and some file shares to store PDF’s or JPG’s (or other files).

In this step, we move the databases and file shares to Azure one-by-one.

I often use:

  • Azure File Storage for file shares (if it is SMB based)
    • Note: Azure File Storage is a bit expensive. Depending on how much data you store, among other factors, you might save a lot on your Azure bill if you migrate to Azure Blob storage (this require code changes).
  • Azure SQL, Azure MySql or Oracle (in Azure VM) for databases

Again, this is not a trivial task and it might not always work in practice. I assume that you have already verified that it works by migrating a non-production environment (e.g., dev, test, QA) to Azure. Also, note that you don’t have to (and probably shouldn’t) move the whole data layer to Azure at once. If your web app consists of independent services with independent data layers, you can introduce them iteratively into production by repeating step 4+5 for each independent service.

A thorough assessment of your whole web app (incl. databases, file shares etc. ) will show the dependencies and priorities of data layer components.

Step 5: Reduce the blast radius

Often your legacy web app (besides the data layer) consists of some websites and some API apps (REST or SOAP).

Instead of deploying all websites and all API at once to production, we can often deploy them one by one. AND we can switch the traffic between the on-prem instance and the Azure instance until we know that the Azure instance can stand on its own feet. That is what I call reducing the blast radius.

So, here is how it is done:

  1. You have based your HTTP traffic routing infrastructure on one of the three services described in Step 3 (Front Door, Traffic Manager, App Service traffic routing)
  2. All of the three service support weighted traffic routing, meaning that you can route, e.g., 5% of the traffic to an Azure-instances (e.g., an Azure App Service Environment) of your web app and 95% on-prem.
  3. So, if the migrated Azure instance of your web app doesn’t work as expected it only happens for 5% of requests; not all of them. And you can switch off the Azure instances within seconds through Application Gateway or API Management (no need to wait for DNS).
  4. You monitor the whole thing closely with Application Insights and Azure Monitor.
  5. Once you are sure that 100% of the requests can go into the migrated Azure instances, you can “turn off” your on-prem servers.

Note that: web apps often also consists of other components, like: batch jobs, windows services, queues, service bus etc. These components are not covered in this blog post but are still important to the migration project.

Step 6: Clean Up

Now that your legacy app has been successfully migrated to Azure you are done, right? Maybe, maybe not. If you follow the above five steps, you might have added more Azure service than you need because you wanted more control and insights into the different migration steps. But once the migration is done, and the old on-prem infrastructure is ready to sunset, you should take a step back and see if your Azure setup needs a clean-up.

Here are some examples:

  1. If you added Azure Font Door in step 3, and also use Azure Application Gateway (or Azure API Management) as advised in step 2
    • If you only use the reverse proxy features of Azure Front Door, then you might use the much-simpler Azure Traffic Manager instead.
  2. If you added Azure Font Door or Traffic Manager in step 3, and use Azure App Service to run your web apps
    • If you only use Azure Front Door or Traffic Manager for weighted traffic routing, then you might suffice with the built-in traffic routing features in Azure App Services.
2