# Building an Event-Driven Image Thumbnail Application

One of the things I have been enjoying about learning cloud computing is seeing how different AWS services can work together to solve a practical problem.

I recently completed a hands-on lab on **AWS Lambda**, where I built and tested a simple event-driven image processing workflow using **Amazon S3, AWS Lambda, and Amazon CloudWatch**.

The lab was designed to demonstrate how Lambda can execute code in response to events without requiring me to manage a traditional server. In this particular exercise, the event was an image being uploaded to an Amazon S3 bucket.

The result was a simple but practical workflow:

**Upload image → S3 detects event → Lambda runs → Image is resized → Thumbnail is stored in another S3 bucket**

This hands-on experience helped me understand serverless computing beyond the definition and see how event-driven architectures actually work.

## Understanding AWS Lambda

AWS Lambda is a compute service that runs code in response to events while AWS manages the underlying compute resources.

Instead of provisioning and maintaining a virtual server just to execute a small piece of code, Lambda allows the code to run when an event occurs.

The lab describes events such as image uploads, application activity, website interactions, and output from connected devices as examples of events that can trigger Lambda functions.

This is one of the key ideas behind **serverless computing**.

The developer focuses on the function and its logic, while the cloud platform handles the underlying compute infrastructure.

## The Application I Built

For the practical exercise, I worked with an **image thumbnail application**.

The workflow involved two Amazon S3 buckets:

*   An input bucket for the original images
    
*   An output bucket for the resized images
    

The process was straightforward.

When an image was uploaded to the input bucket, Amazon S3 generated an object-created event. That event triggered the Lambda function.

Lambda then received information about the bucket and object, downloaded the image, resized it, and uploaded the resulting thumbnail to the output bucket.

This gave me a practical example of how separate AWS services can be connected together to create an automated workflow.

## Creating the Amazon S3 Buckets

I started by creating two S3 buckets.

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/a6de8b7f-2da9-4853-9633-f2a449683c62.png align="center")

The first bucket was used to store the original images, while the second bucket was used to store the resized versions.

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/59dbfdbb-b8a7-4a93-9c46-71c84eb18cb5.png align="center")

The lab required globally unique bucket names, so a random number was added to the bucket name. The second bucket used the same naming pattern with `-resized` appended to it.

I then uploaded an image called **HappyFace.jpg** to the input bucket.

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/8d19250f-ad17-4d36-953a-65fd215efe74.png align="center")

The image became the object that would eventually trigger the Lambda function.

At this point, nothing was happening automatically yet. I had the storage layer, but I still needed the compute function that would process the image.

## Creating the Lambda Function

Next, I created an AWS Lambda function called:

**Create-Thumbnail**

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/d6a584a5-d9e4-42bc-8f1b-472bd636ca77.png align="center")

For the runtime, I selected **Python 3.12**.

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/8139011a-03f6-4bb0-a130-e52a50683251.png align="center")

I also configured an existing execution role called `lambda-execution-role`. This role provided the permissions required for the Lambda function to access Amazon S3 and read and write the images.

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/4528601b-beab-49a2-8a3b-ef764ce2a3ab.png align="center")

The function was also attached to the VPC, subnet, and security group provided by the lab environment.

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/d75e3921-69a9-45e4-a0e2-719b6d60de48.png align="center")

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/59cc015b-6380-4fcd-ac78-adea4d1c6af5.png align="center")

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/df23ba24-25d2-4b10-a005-e3bd4c491da8.png align="center")

This was an interesting part of the exercise because it showed that a Lambda function can interact with networking configurations and AWS resources while still operating within a serverless model.

## Connecting S3 to Lambda

Creating the Lambda function alone wasn't enough.

I needed to tell AWS **when the function should run**.

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/1dd76834-a85a-4ad3-8341-47e7e78d8a0e.png align="center")

This was done by configuring Amazon S3 as the Lambda event source.

I added an S3 trigger to the function and configured it to respond to **all object-create events** in the input bucket.

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/1b0f89ba-3431-4240-b4b5-7e14f6f4846a.png align="center")

This created the automation I was looking for.

Instead of manually running the Lambda function every time an image needed to be processed, an upload to the S3 bucket could initiate the process.

That is where the event-driven nature of Lambda became much clearer to me.

## Looking at the Lambda Code

The Lambda function used Python and the **Pillow** library to process the image.

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/99ce1264-777e-43db-8fc1-c163523b3174.png align="center")

At a high level, the function performed four main operations:

1.  Receive the event information from Amazon S3.
    
2.  Download the uploaded image.
    
3.  Resize the image using Pillow.
    
4.  Upload the resized image to the output S3 bucket.
    

The lab's sample function uses the S3 event data to identify the source bucket and object key, downloads the image into temporary storage, creates a thumbnail with dimensions up to **128 × 128**, and uploads the result to the `-resized` bucket.

This was a good demonstration of how relatively small pieces of code can perform useful tasks when connected to cloud events.

## Testing the Function

After configuring the function and trigger, I tested the workflow.

Rather than waiting for another upload event, I created a test event using the **S3 Put** template.

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/bff912e3-7222-418f-ba50-c279ca06dd22.png align="center")

I modified the sample event data to reference the bucket I had created and the `HappyFace.jpg` object.

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/f564e9f5-b874-43db-9633-c4823a40c40c.png align="center")

I then executed the test.

The function completed successfully, and the execution details provided information such as:

*   Execution time
    
*   Configured resources
    
*   Maximum memory used
    
*   Log output
    

The resulting resized image was then available in the output S3 bucket.

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/7d570aa0-2d69-47e7-ac98-a68e3f50987d.png align="center")

This was the moment where the architecture really came together.

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/b43927c0-fba2-42c2-9a6a-59c0b6cdd16c.png align="center")

A file went into one storage location, an event was generated, Lambda processed the event, and the resulting file appeared in another storage location—all without manually running a server.

## Monitoring with Amazon CloudWatch

Building the function was only part of the exercise.

I also explored how to monitor Lambda.

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/c7a9e4e6-69c5-4e0a-a62d-23a672c722e4.png align="center")

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/b1189a40-b25c-4935-86ce-3b5c3e29447e.png align="center")

![](https://cdn.hashnode.com/uploads/covers/631edab3f73f4734bc059f39/e08baedb-dce5-48a9-95b2-ca045b2d1afe.png align="center")

The Lambda monitoring dashboard provides information about different aspects of function execution, including:

*   Invocations
    
*   Duration
    
*   Error count
    
*   Success rate
    
*   Throttles
    
*   Concurrent executions
    

Lambda log messages are retained in **Amazon CloudWatch Logs**, where execution details can be examined for troubleshooting and debugging.

The logs can provide useful information such as the request ID, execution duration, billed duration, configured memory, maximum memory used, and application log messages.

This reinforced an important lesson for me:

**A working application is not enough. You also need visibility into what the application is doing.**

Monitoring and logging are essential when troubleshooting failures, investigating unexpected behavior, and understanding application performance.

## A Simple Architecture, but an Important Concept

The architecture from this lab can be represented simply as:

**User**

↓

**Amazon S3 — Input Bucket**

↓

**Object Created Event**

↓

**AWS Lambda**

↓

**Image Processing with Python + Pillow**

↓

**Amazon S3 — Resized Bucket**

↓

**Amazon CloudWatch — Monitoring & Logs**

What makes this interesting is that the workflow is **event-driven**.

The system doesn't need a continuously running server waiting for an image.

Instead, the event causes the required computation to happen

This AWS Lambda lab helped me move from simply knowing what serverless computing means to understanding how an event-driven serverless workflow can actually be implemented.

I created an S3-based image processing workflow, configured a Lambda function using Python 3.12, connected S3 to Lambda as an event source, tested the function, and monitored its execution through CloudWatch. These are the core outcomes documented in the completed lab.

What stood out to me most was how little infrastructure management was required to create something functional.

There was no traditional web server to configure for the image-processing task. Instead, the workflow was built around an event and a function that responded to that event.

This experience also helped me better understand why serverless architectures can be useful for applications where workloads are event-driven and don't necessarily require a continuously running compute environment.

As I continue building my cloud and cybersecurity skills, I'm particularly interested in understanding not just how these services work individually, but how they can be securely combined to build reliable cloud architectures.

**Another hands-on lab completed. Another cloud concept turned from theory into practice.**
