Migrating legacy apps to Google Cloud Platform

Cloud platforms are awesome for deploying software without having to maintain the underlying infrastructure. We can choose from a variety of services and forget about operating systems and servers, so we can focus in delivering high quality software instead of solving infrastructure issues.

First of all we have to plan and design, so we can build a new more robust and easy-to-maintain infra for our app. This might involve some code changes and/or architecture changes.

On legacy applications this is quite challenging. On today’s case, we have a 2.x php app made with codeigniter framework. As this version is deprecated, we needed to update the framework. In sum, to use php7, which doesn’t support mysql php module anymore which is a codeigniter 2 requirement.

Latest codeigniter (3.x) supports PDO which is not also supported by php 7 but also the recommended driver for databases. This migration didn’t was too hard, but it was time consuming.

First of all, we need to change model and controllers filenames. Recent codeigniter requires controller and model files to start with a capital letter. It doesn’t make much sense to me, but who cares, right?

Running the bash snippet below we can rename all files in a breeze.

Codeigniter matches urls with controller classes and methods, for example the controller below will respond to /<location_id> as well as /location/<location_id>.

Notice the location method that makes a call to index method. Without location method the url will not behave as CI 2.x. So we have to make this change to preserve functionality after the migration.

After all needed controllers are updated, we need to make some database config changes. Php 7 recommends to use PDO functions to connect to a database. Luckily CI 3.x support this driver too, but the configuration required to do this is not very well documented.

This example configures a mysql database with pdo. dsn field must be blank.

With this config we also get persistent connections that perform much more efficiently than if we open and close the connection for each php script.

Application setup is right and now our application should be working on Google Cloud. We could finish here, but more optimizations can be achieved with not so much effort.

Stage 1

Move the database to other host

Google cloud has specific instances for databases which are fully managed. That saves a lot setup and maintenance work (and time!).

So instead of installing the database engine in the VM instance, we are going to create a SQL instance. By creating it in the same zone that our app instances we will have less latency.

Stage 1.5

Enable slow SQL log and optimize all slow queries when possible

We can optimize the database a little bit so your cloud platform bill is cheaper. This is optional at this stage, but we could be enable slow query log and optimize slow queries. This will allow to grow faster and also to have less to worry about in the near future.

Stage 2

Add a load balancer

A load balancer will serve all traffic and it can provide an SSL endpoint too, so the server instance doesn’t need to do that. This piece of infrastructure is the first requirement to scale VM instances horizontally.

Long story short: this means more saving on server instances resources, and again less maintenance, as you now have to update the SSL certificate in only one place (and yes, it can be automated).

Stage 2.5

Add a instance template, a group and enable auto-scaling

Adding a template, a group and adding the server instance to that group are requirements to enable auto-scaling feature, that means that the cloud provider will now create or delete instances depending on the traffic detected at the load balancer. Set a minimum value of 1 or 2 and a maximum value of 3 or 4 servers for example.

Then we adjust these values later, and scale even more. But database is normally will be a bottleneck first.

Stage 3

Database horizontal scaling

Database instances are really easy to replicate, we just need to make a slave instance which will only be used for reading. For writing the database we are going to need to contact the master server. It’s possible to configure the slave instance to route such queries. This way, the app configuration is much easier and doesn’t require us to consider in the application code two connections: one for reading and other for writing.

Conclusion

Following a few simple steps, we now have a production grade and highly scalable architecture that will allow us to keep our focus on really important things like adding value to our users.

Happy coding!