An app modernization story — Part 2 (Lift & Shift)

In part 1 of app modernization series, I introduced a simple news aggregator and some of the challenges in its initial architecture. In part 2, I’ll talk about the journey to the cloud and some unexpected benefits and learnings along the way.

Why Cloud?

The initial backend had many issues that I outlined in part 1. After about 1 year, in late 2016, we decided to look into moving it to a more stable home. Our main goal was to improve resiliency of the app, as the IIS host kept crashing, but we didn’t want to rewrite or re-architecture the app in a major way. Around the same time, I started working at Google and was learning all about Google Cloud. We decided to give it a try and see what it took to move the app there.

Lift & Shift

Our app was Windows based, so, the only option on Google Cloud at the time was to deploy it to a Windows Server VM on Compute Engine. (There are more options for Windows apps now but we’ll talk about that in the next post.)

Google Cloud has a marketplace with solutions ready to deploy. We used ASP.NET Framework solution to get a Windows VM with IIS, SQL Express, ASP.NET already installed. It was literally a single click.

Once we had the Windows VM, publishing from Visual Studio to Compute Engine was quite straightforward. This was partly because our architecture was very simple with no persistence. We lifted & shifted our app to the cloud without actually knowing the term at the time.

Initial Cloud Architecture

This is how architecture looked like after the initial lift & shift:

We kept things to a minimum with an instance group of 2 load-balanced Compute Engine VMs running our app. This way, we achieved our main goal of redundancy and basic load balancing.

Unexpected Benefits

We then started looking into what Compute Engine offered.

We discovered instance templates which allowed us to go from an existing VM to a template and from that template, create instance groups, a fleet of identical and load-balanced VMs. Instance groups has nice additional features like re-creating crashed VMs, auto-healing VMs when possible, spreading VMs across multiple zones, load balancing and autoscaling.

We discovered that persistent disks can be attached to VMs and later you can take snapshots of these disks quite easily for backups.

The DevEx on Google Cloud was much better than our previous host. Being able to RDP into VMs from browser with a single click, ability to see and search application logs in Stackdriver, ability to stop/pause VMs to save costs and more.

There are many small gems like this in Compute Engine infrastructure. Admittedly, we didn’t need most of these features yet but we definitely felt upgraded to an enterprise grade environment right away.

Lessons Learned

These are the main lessons for the lift & shift phase our app:

  1. Lift & shift does not have to be hard: We were pleasantly surprised how easy it was to move the existing app to the cloud. Sure, we had a simple architecture and we had to do some research to figure how things worked in the cloud but in the end, we didn’t have to change much.
  2. Cloud is much more than hosting: We just wanted a stable environment for our app and we got much with the cloud, again without really changing anything about our app.
  3. There’s no free lunch: We went from a single machine to a couple of load-balanced machines running on VMs. Not surprisingly, this was more expensive than the primitive IIS host we had before. We felt like we got our money’s worth and the free tier helped but our monthly bill was more than we wanted for our small app. This is something we wanted to tackle later.


Our first cloud architecture served us well for about 2 years. In the meantime, the tech scene was changing rapidly with multi-platform .NET Core, containers with Docker and more. In the next post, I’ll talk about how these technologies transformed our Windows-only VM app into a containerized app that can run anywhere.

See also