DEV Community

Cover image for The Zero-Cost Cloud Engineer Part 3: Decoupled Messaging with Pub/Sub on the Always Free Tier
Mohammad Awwaad
Mohammad Awwaad

Posted on

The Zero-Cost Cloud Engineer Part 3: Decoupled Messaging with Pub/Sub on the Always Free Tier

The Zero-Cost Cloud Engineer

Part 3: Asynchronous Messaging and the "Lite" Trap

In [Part 2], we established our "Secure Island" foundation—a private Compute Engine VM with no external IP and centralized logging. However, a single VM is a monolith. To build a resilient, cloud-native ecosystem, we need decoupled communication.

This tutorial covers the implementation of an asynchronous messaging loop using Google Cloud Pub/Sub and Spring Boot, strictly within the 10 GB/month Always Free allotment.


Step 1: Provisioning the Pub/Sub Infrastructure

When configuring messaging in Google Cloud, beginners often face a critical choice in the console: Pub/Sub vs. Pub/Sub Lite.

🚨 The FinOps Trap: "Lite" sounds perfect for small-scale zero-cost projects, but it requires provisioned throughput capacity. Google bills you for that reserved capacity immediately, even if you send zero messages. Standard Pub/Sub is serverless, scales to zero, and includes a generous free tier of 10 GB/month.

To set up the zero-cost infrastructure in the GCP Console:

  1. Create a Topic: Navigate to Pub/Sub > Topics and click Create Topic. Name it demo-topic. Uncheck the default subscription option.
  2. Create a Subscription: Under Pub/Sub > Subscriptions, click Create Subscription. Name it demo-subscription and link it to your demo-topic.
  3. Configure Delivery: Select Pull delivery. Ensure "Exactly-Once Delivery" remains unchecked, as guarantees outside of "at-least-once" delivery can fall outside the Always Free tier. We handle message deduplication (idempotency) within our application logic instead to maintain a zero-cost profile.

Step 2: Granting Identity-Aware Permissions (IAM)

Our VM identity (the Compute Engine default service account) has no inherent permission to interact with Pub/Sub.

What happens if you skip this? If you deploy your Spring Boot app now, it will crash immediately with a PermissionDeniedException. We must explicitly "stamp its passport" for messaging.

  1. Navigate to IAM & Admin > IAM in the GCP Console.
  2. Locate the principal named: [PROJECT_NUMBER]-compute@developer.gserviceaccount.com.
  3. Click the pencil icon (Edit Principal) next to it.
  4. Click Add Another Role and attach these two specific roles:
    • Pub/Sub Publisher
    • Pub/Sub Subscriber
  5. Click Save.

Step 3: Integrating Spring Boot

To enable Pub/Sub in your Spring Boot application, include the Spring Cloud GCP Pub/Sub Starter in your pom.xml.

(Architect's Note: If you are building on a modern stack like **Spring Boot 4.x* and Java 25, you must align with Spring Cloud GCP 8.x or newer. Earlier versions use legacy package structures incompatible with modern auto-configuration).*

The Publisher

Implement a simple REST endpoint to broadcast messages:

import org.springframework.web.bind.annotation.*;
import com.google.cloud.spring.pubsub.core.PubSubTemplate;

@RestController
public class PubSubController {
    private final PubSubTemplate pubSubTemplate;

    public PubSubController(PubSubTemplate pubSubTemplate) {
        this.pubSubTemplate = pubSubTemplate;
    }

    @GetMapping("/publish")
    public String publish(@RequestParam("message") String message) {
        pubSubTemplate.publish("demo-topic", message);
        return "Message published: " + message;
    }
}
Enter fullscreen mode Exit fullscreen mode

The Subscriber

Implement a background service to pull and acknowledge messages:

import org.springframework.stereotype.Service;
import com.google.cloud.spring.pubsub.core.PubSubTemplate;
import jakarta.annotation.PostConstruct;

@Service
public class PubSubSubscriber {
    private final PubSubTemplate pubSubTemplate;

    public PubSubSubscriber(PubSubTemplate pubSubTemplate) {
        this.pubSubTemplate = pubSubTemplate;
    }

    @PostConstruct
    public void subscribe() {
        pubSubTemplate.subscribe("demo-subscription", (msg) -> {
            String data = msg.getPubsubMessage().getData().toStringUtf8();
            System.out.println("Received message: " + data);
            // Process message and acknowledge
            msg.ack();
        });
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: The Secure Island Deployment

Since our VM is isolated from the public internet, we deploy using the Identity-Aware Proxy (IAP) tunnel.

Deployment Workflow:

  1. Cleanup: Before uploading, connect to your VM via IAP SSH and ensure a clean environment by stopping existing processes and removing old artifacts (like the jar from Part 2):

    pkill -9 java
    rm -f ~/*.jar
    
  2. Transfer the Artifact: Build your application locally (mvn clean package) and transfer the artifact from your laptop's local terminal:

    gcloud compute scp target/hello-gcp.jar free-tier-vm:~/ --tunnel-through-iap
    
  3. Run with Observability: Execute the application on the VM, piping output to the syslog file (which we configured the Ops Agent to read in Part 2) to ensure visibility in Cloud Logging:

    java -jar ~/hello-gcp.jar 2>&1 | logger -t spring-boot &
    

Step 5: End-to-End Verification

To verify the messaging loop, we need to hit the /publish REST endpoint to trigger the process.

🚨 The Network Trap: Because the VM has no public IP, you cannot simply curl http://<VM_IP>:8080/publish. The connection will be refused.

To bridge our local machine to the private VM without exposing it to the internet, we establish a Local Port Forwarding Tunnel:

  1. Establish a Local Tunnel from your laptop terminal:

    gcloud compute ssh free-tier-vm --tunnel-through-iap -- -L 8080:localhost:8080
    
  2. Trigger the Publisher: Use your laptop's web browser or local curl to hit the mapped port:
    http://localhost:8080/publish?message=HelloZeroCost

  3. Validate in Logs Explorer: Navigate to the GCP Logs Explorer in the console and query for your specific message:
    jsonPayload.message:"Received message: HelloZeroCost"

If the log appears, your decoupled architecture is successfully operating entirely within the "Secure Island" constraints!


Summary

We have successfully moved from a standalone VM to a decoupled messaging architecture without incurring a single cent in costs. By choosing the serverless Standard Pub/Sub model over Lite, managing permissions through IAM, and implementing a robust local-tunnel verification workflow, we maintain a production-grade environment within the Always Free tier.

In Part 4, we will solve the storage bottleneck of our 30GB persistent disk by offloading files securely to Google Cloud Storage (GCS).

Top comments (0)