The Zero-Cost Cloud Engineer: Mastering GCP on the Always Free Tier
Part 2: Observability and the "Where are my logs?" Problem
In [Part 1], we successfully spun up our "Always Free" e2-micro VM, secured it by removing the public IP address, and learned how to access it via the GCP Console's Identity-Aware Proxy (IAP) SSH button.
But a secure VM is useless if we can't see what's happening inside it. If our application crashes or our tiny 1GB of memory maxes out, we need to know instantly. We need Observability.
The Dream: Centralized Logging
Why not just read logs directly in the SSH terminal? While easier for a single VM, "The Cloud Way" treats servers as disposable cattle, not beloved pets:
- VMs die unexpectedly: If your VM crashes and its hard drive is wiped, your terminal logs vanish. If logs are streamed to a central dashboard, you can investigate why it crashed post-mortem.
- Horizontal Scaling: When your app scales to 10 VMs, you can't manually scan 10 SSH terminals. You need one aggregated window.
- Automated Alerting: A central dashboard can automatically email you if the word "Exception" appears. A raw terminal cannot.
This is exactly how Netflix and Uber manage their fleets. Google Cloud's centralized dashboard is called Cloud Logging (generously free up to 50 GiB/month) and Cloud Monitoring (free for massive metric allotments).
We just need to install the Google Cloud Ops Agent on our VM to ship the data there.
The GUI Trap: OS Policies on a Tiny VM
Following our rule of prioritizing the "ease of the UI," you naturally navigate to the VM details page in the GCP Console, click the Observability tab, and click the cheerful Install Agent button.
Instantly, an error pops up: "The following instance is not eligible for installing or updating Ops Agent via OS policy assignment."
What Happened?
The GUI installer is actually a massive enterprise feature under the hood called "OS Config Policies," designed for forcing software updates across fleets of thousands of VMs simultaneously. An e2-micro VM is simply too small to run these heavy background synchronization services reliably, so the GUI bulk installer rejects it.
We have to fall back to the terminal.
The Terminal Trap: A VM without Internet
You click the SSH button in the Console to open the terminal and paste the official manual installation command:
curl -sSO https://dl.google.com/cloudagents/add-google-cloud-ops-agent-repo.sh && sudo bash add-google-cloud-ops-agent-repo.sh --also-install
The terminal hangs. Ten seconds pass. Thirty seconds pass. Nothing prints to the screen.
What Happened?
Remember our security posture from Part 1? We explicitly removed the External IP address to avoid getting billed. Because of that, the VM has zero outbound internet access. The curl command is desperately trying to reach the internet to download the script, and the VPC network is silently dropping it.
The Solution: Private Google Access
How do private, disconnected servers download critical updates?
We use a 100% free Google networking feature called Private Google Access. This incredibly powerful feature acts as a secure internal tunnel, allowing isolated VMs to reach Google's internal services (like OS package repositories and Cloud Storage) without needing the public internet.
Let's fix it using the UI:
- In the GCP Console search bar, type VPC networks.
- Click on the subnet matching your VM's region (e.g.,
defaultinus-east1). - Click EDIT at the top.
- Locate the Private Google Access toggle, turn it ON, and hit Save. (Ignore any promotional popups or overlapping IP warnings).
- Go back to your VM's SSH terminal, cancel the hanging command with
Ctrl+C, and run it again.
It immediately succeeds! Google's internal traffic routing kicks in. If you wait a minute and refresh the Observability tab on the VM details page, beautiful CPU and Memory graphs will begin populating.
Deploying Spring Boot
Let's test our setup.
Instead of dealing with Maven commands on a tiny VM—which wouldn't work anyway because our secure VM has no internet access to download dependencies from Maven Central—use the incredibly easy Spring Initializr UI (start.spring.io) or your local IDE (IntelliJ/Eclipse) to generate a basic Spring Boot project on your laptop. Add a simple @Scheduled task that prints a log every 5 seconds.
Build the .jar locally on your laptop, and transfer it over the secure IAP tunnel directly from your local terminal:
gcloud compute scp target/demo-0.0.1-SNAPSHOT.jar <YOUR_VM_NAME>:~/ --zone=<YOUR_VM_ZONE> --tunnel-through-iap
Back in the VM's SSH window, run it:
java -jar ~/demo-0.0.1-SNAPSHOT.jar
The Final Boss: "Where are my logs?"
The app prints logs securely to your SSH terminal. Excellent.
Now, open the Logs Explorer in the GCP Console to view them centrally.
The page is entirely blank. Your Spring Boot logs are nowhere to be found.
What Happened?
The Ops Agent doesn't monitor foreground terminal processes. Furthermore, in newer versions of the agent, Google turned off text logging by default to protect massive clients from accidentally sending petabytes of logs and racking up huge bills. It only collects metrics out of the box.
We must forcefully configure it.
- First, stop your terminal process and change how you execute the app. Pipe the standard output to the central Linux diary (
/var/log/syslog) using theloggertool:
java -jar ~/demo-0.0.1-SNAPSHOT.jar 2>&1 | logger -t spring-boot
- Second, tell the Ops Agent to listen to the syslog. In the SSH terminal, edit
/etc/google-cloud-ops-agent/config.yamlto include exactly this:
logging:
receivers:
syslog:
type: files
include_paths:
- /var/log/syslog
service:
pipelines:
default_pipeline:
receivers: [syslog]
- Restart the agent:
sudo systemctl restart google-cloud-ops-agent.
Now, go back to the Logs Explorer and query for:
logName=~".*syslog"
jsonPayload.message=~"spring-boot"
Boom! Your Java application is now reporting enterprise-grade, centralized logs entirely from a secure, internet-less server—and you haven't been charged a single cent.
In Part 3, we'll explore Pub/Sub and decouple our architecture.
Top comments (0)