In this article, I will explain why you should resize images in your websites, and how you can leverage Google Cloud Functions with GCP Load Balancer and Cloud CDN to deliver on-the-fly resized images to improve your website performance, save expensive storage space and improve your website loading time.
Almost every major website resizes the photos displayed on the site, and thatโs for three primary reasons:
- Downloading large images leads to high bandwidth usage and high data transfer costs.
- Scaling down images via HTML requires the client browser to download the entire image and then spend CPU time resizing it, leading to slower loading time of your website.
- Without resizing on-the-fly, you need to store different sizes of the same image for your website's Desktop, Mobile, Tablet and email (newsletter), as storage costs in the cloud start at $0.02/GB per month, which could be expensive.
Read more about image optimization in Steve Souders' book,ย Even Faster Web Sites, Chapter 10.
Using Google Cloud Content Delivery Network (CDN) allows us to provide faster loading times to our static content, as the objects are cached at the edge network, which is spread globally.

The solution in this article uses the following services:
- Google Cloud Storage โ to store the images in full size.
- Cloud Function โ to resize the objects on the fly.
- Google Cloud Load Balancer with Cloud CDN enabled โ the users will access the load balancer to retrieve the images.
We create a GCP Cloud Load Balancer (LB) and configure it to invoke a Cloud Function, the function pulls an image from Google Cloud Storage (GCS), resize it, and the LB reply with the resized image and save the image at the edge for future requests.
How to deploy
We create a Google Cloud Storage (GCS) Bucket and upload all the objects (images) in their original size.
We set a name for the bucket and configure a regional location, and click on theย Createย button:
We uploaded an image, for example, nasdaq.jpg (of the Nasdaq building in Times Square, which I took in 2019) to this bucket in its original size, 6.3 MB.
The next step is to create a function. Go to the Cloud Functions console and click onย Write a function.
If this is the first time you use Cloud Functions, you might see a message โCloud Functions API is enabledโ. This means that Cloud Functions features are being enabled in your project at no extra cost.
In this step, we need to configure the function:
- We use the inline editor.
- Set a name for the function.
- Choose the region โ that should be theย same as the GCS region.
- Set the runtime. In this demo, we work with Python.
- And uncheck the IAM authentication so the LB can invoke the function.
Now click on theย Createย button, and if itโs the first time you use GCP services, you might need to enable a few more APIs:

Now itโs the fun part, We need to write the code that actually pulls the file from GCS, resizes it and returns the resized file.
We wanted to see if this could be done entirely by ChatGPT, so I had a few iterations with the LLM, after writing the following prompts:
โWrite Python code to resize jpg png images to x,y based on the string provided.โ
โLetโs assume itโs google cloud function that pass the params as query string and the file needs to be loaded from gcs and the result should be sent to a load balancer with the appropriate mime type.โ
โWhat should I put in requirements.txt for this code?โ
โNow I'm getting โError processing image: module โPIL.Imageโ has no attribute โANTIALIASโโโ
The result is the following code. In line 9, set the bucket that we use:
This is theย requirements.txtย file to configure Cloud Functions, which Python libraries it should use to build the container:
When we update the code inย main.pyย and the libraries inย requirements.txt, we see a warning that โThe specified function (entry point) might not be present in your source code. Please ensure the entry point in your code matches the input field.โ
This is because the function is calling theย resize_imageย function, and Cloud Functions default function name isย hello_http:
We change theย Function entry pointย toย resize_imageย and clickย Save and redeploy.
Cloud Functions builds the container of our code. It might take a couple of minutes, and we can track the status of the build at the top of the dashboard:
Note: Cloud Function invokes a function. The function usesย Compute Engine Default Service Account, which grants the function access to all the GCS Buckets in the project. We will not cover this in the article, but as a best practice, you should use a dedicated service account with the least privileged access.
The next step is to create a Load Balancer. Search for โLoad Balancerโ in the search console, access the Load Balancer dashboard and click onย Create load balancer:
We want to create a Global, Public Facing, Application Load Balancer, Under the type of the load balancer, chooseย Application Load Balancer (HTTP/HTTPS):
We want our users from around the world to be able to access the load balancer, so we chooseย Public Facing (external):
We chose the Global load balancer to leverage the Google Cloud CDN feature, which allows us to cache the resized image at the edge server (at no extra cost).
Then we choose the latest Load Balancer generation and click theย Nextย andย Createย button.
To simplify this stage, we create an HTTPย frontendย endpoint for the Load Balancer.
Set a name for the Load Balancer and the frontend IP.
Click onย Backend Configuration,ย and in theย Backend services & backend bucketsย box, click onย Create a backend service.

Set a name and a description for the backend service, and change theย Backend typeย toย Serverless network endpoint group.
Scroll down to theย Backendsย area. Under New backend, click on the Serverless network endpoint groups and click onย Create Serverless network endpoint group.
Set the Name for the Endpoint and choose the region where you create the Cloud Function.
If you have never invoked the function before, this error pop up:
Go to the link in the error and enable Cloud Function API:
Go back to the Serverless network endpoint page, set a name for the endpoint, the Region where the function is located, and choose Cloud Run (It might be confusing, but Cloud Functions are now called Cloud Run Functions, and use the same underlying technology).
Select the function and click onย Create.
In the backend page, we can configure Cloud CDN cache settings:
We can configure the CDN to cache the response for the duration (1 hour from row 54 in the script), or a longer duration.
I want to highlight thatย CDN uses a warm cache, meaning that only frequently requested content is stored in the CDN cache. If you set a 1-year cache for your content, but there are no frequent requests to the content, you can expect that after some time the CDN will pull the content from the origin (the function).
See the Logging feature (marked with the arrow above). It is great for debugging and tracking usage, but also costly ($512 for 1 TB of logs).
If you generate a lot of requests, you can set theย Sample rateย toย 0.01ย to log one request out of every 100 requests.
Letโs scroll down toย Security:
By default, Google enablesย Cloud Armor, the Web Application Firewall (WAF), for our backend, but since there isย additional costย and this is a demo, we disable it by clicking on theย Cloud Armor backend security policyย and changing it toย None.
The next step is to click onย Create, and in the Load Balancer dashboard, click onย Createย again.
Note: Creating and updating a Load Balancer in GCP can take up to 15 minutes to propagate.
Now, once the load balancer is ready, click on the name of the load balancer and you see the IP that was generated:
We access this IP and specify the name of the image and the height and width:
http://34.49.21.153/?image=nasdaq.jpg&size=500x600
The result: Instead of a 6.5 MB file, we received a smaller, resized image, weighing 63 KB.
My job is to guide customers in using the cloud. Come see what we can do for you atย doit.com/services





























