Take the capstone live on the internet — and fully automate the deploy.
Module 13 (Bonus) · Free-tier VM + k3s. The only module that touches a cloud account.
Bonus Cloud ~75 minThis is the one module that uses a cloud account. Free tiers are generous but not unlimited — leaving resources running, or picking the wrong size, can cost money. Follow the Cost & Safety section: set a billing alert, use free-tier-eligible sizes only, and destroy everything when you're done. You've been warned, kindly. ๐
Prerequisites: Module 12 (Capstone) finished — you'll deploy that exact project.
Everything you built ran on your laptop. The cloud is just someone else's computers you rent — but a few things genuinely change once your app is on the public internet:
| On your laptop | In the cloud |
|---|---|
localhost | A real public IP (and maybe a domain name) |
| Only you can reach it | The whole internet can — so security matters |
| Free, always | Metered — you pay (or use free tier) for what runs |
| GitHub runners can't reach it | They can — so auto-deploy finally works |
Remember the deploy step we deferred in Modules 9 and 12? It only works against a cluster GitHub can reach. A cloud VM has a public address — so now git push can deploy all the way to production. That's the whole point of this module.
| Term | What it is |
|---|---|
| Region / Zone | Physical data-center location. Pick one near you (and your users). |
| Compute / VM / Instance | A rented virtual server (AWS EC2, GCP Compute Engine, Azure VM). |
| Public IP | The internet address your app is reachable at. |
| Firewall / Security Group | Rules for which ports are open to the world. Lock this down. |
| Free tier | A free allowance (always-free or 12-month). Stay inside it to pay $0. |
| Managed service | The cloud runs it for you (e.g. managed Kubernetes) — convenient, but usually not free. |
| Managed K8s (EKS/GKE/AKS) | VM + k3s (this lab) | |
|---|---|---|
| Setup | Cloud runs the control plane | You install lightweight k3s yourself |
| Cost | Usually not free (~$70+/mo) | Fits a free-tier VM ($0) |
| Best for | Real production at scale | Learning, small apps, this course |
k3s is a fully-compliant Kubernetes distribution stripped down to a single small binary. It runs happily on a tiny free-tier VM, and your Module 8 manifests work on it unchanged — so you get a real, reachable cluster for $0.
Oracle Cloud "Always Free" (generous ARM VM, no time limit), GCP e2-micro (always-free in some regions), or AWS EC2 t3.micro / Azure B1s (12-month free). Any one works — the steps below are deliberately provider-neutral.
We'll provision a free-tier VM, install k3s, deploy the capstone, and wire up auto-deploy. Commands are provider-neutral; substitute your cloud's console or CLI where noted.
In your cloud console, launch a VM: pick a free-tier-eligible size, an Ubuntu image, and create/download an SSH key pair. Open ports 22 (SSH), 80 (HTTP), and 6443 (the k3s API, so CI can reach it).
The IaC skills transfer directly. An AWS example — same init/plan/apply loop you already know:
Use SSH keys, never passwords. Open only the ports you need. Keep the OS updated. Never paste real secrets into a public repo. These habits matter the moment you're on the public internet.
One command installs a complete Kubernetes cluster on the VM:
k3s writes its kubeconfig on the server. Copy it locally and point it at the public IP so your laptop's kubectl controls the cloud cluster:
Your Module 8 manifests work as-is. Make sure your image is pullable — the simplest path is making the GHCR package public (or add an image pull secret). Then:
k3s ships with a built-in load balancer, so a Service of type LoadBalancer gets the VM's IP. Either set the web Service's type: LoadBalancer, or quickly expose it:
Open http://<PUBLIC_IP> in your browser — your notes app is live on the internet. ๐โ
The exact app and manifests you ran locally on Minikube now serve real traffic on a public address — no code changes. That portability is the promise of containers + Kubernetes.
Now make CI deploy here on every push. Add your kubeconfig as a repo secret: Settings → Secrets and variables → Actions → New secret named KUBECONFIG (paste the file contents with the public-IP server line). Then enable the deploy job from the Capstone:
Push a change to main. Watch Actions test it, build a new image, publish it, and roll it out to your cloud cluster — then refresh the public URL and see your change live. That is the complete DevOps loop you set out to build.
The most important step. When you're done exploring, delete everything so nothing keeps running (or billing):
Every cloud lets you set a budget/billing alert (e.g. notify me at $1). Do this first. It's your safety net against a forgotten resource quietly running up a bill.
| Rule | Why |
|---|---|
| Use only free-tier-eligible sizes | A bigger instance bills by the hour, even idle. |
| Destroy resources when done | "I'll delete it later" is how surprise bills happen. |
| Watch for hidden costs | Public IPs, disks, and load balancers can bill separately from the VM. |
| Least privilege on credentials | Never use root/owner keys in CI; scope tokens to what they need. |
| Never commit secrets | Keys in a public repo get scraped by bots within minutes. |
| Rotate anything exposed | If a credential leaks, revoke and replace it immediately. |
| Command | What it does |
|---|---|
ssh -i key.pem ubuntu@<ip> | Connect to the VM |
curl -sfL https://get.k3s.io | sh - | Install k3s Kubernetes |
sudo cat /etc/rancher/k3s/k3s.yaml | Get the cluster's kubeconfig |
export KUBECONFIG=./kubeconfig | Point kubectl at your cloud cluster |
kubectl apply -f k8s/ | Deploy your manifests |
kubectl get svc web | Find the public IP/port |
terraform destroy | Delete all provisioned infra |
| Symptom | Likely cause & fix |
|---|---|
| SSH connection refused/timeout | Port 22 not open in the firewall, or wrong key/user (ubuntu vs ec2-user). |
kubectl can't connect from laptop | kubeconfig still says 127.0.0.1; change it to the public IP, and open port 6443. |
Pods stuck ImagePullBackOff | GHCR image is private — make the package public or add an image pull secret. |
| App not reachable in browser | Port 80 closed in the firewall, or Service isn't LoadBalancer. |
| CI deploy job fails to auth | KUBECONFIG secret missing/wrong, or it points at 127.0.0.1. |
| Unexpected charges | A resource is still running — check the console for VMs, IPs, disks; destroy them. |
destroy it.You started not knowing what a container was. You can now containerize an app, orchestrate it on Kubernetes, automate its testing and deployment, define its infrastructure as code, monitor it in production — and deploy the whole thing to the real cloud with a single git push. That's a working DevOps skill set.
Where to go next: deepen one tool (Kubernetes, Terraform), learn a cloud provider in depth for a certification, or explore advanced topics like service meshes, GitOps (Argo CD), and security (DevSecOps). But first — polish that capstone repo and put it in front of people. You earned it. ๐