All Modules Why Cloud Concepts Hands-on Lab Cost & Safety

Deploy to the Real Cloud

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 min

Read this first: real money is possible

This 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. ๐Ÿ™‚

What You'll Learn

  • Understand core cloud concepts: regions, compute, public IPs, firewalls, free tiers
  • Provision a free-tier VM — via the console or Terraform (Module 10)
  • Install lightweight k3s Kubernetes on it and deploy the capstone
  • Expose the app on a public IP and reach it from anywhere
  • Complete the CI/CD loop: every push auto-deploys to the cloud
  • Practice cloud hygiene: billing alerts, least privilege, and tearing down

Prerequisites: Module 12 (Capstone) finished — you'll deploy that exact project.

What Changes in the Cloud

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 laptopIn the cloud
localhostA real public IP (and maybe a domain name)
Only you can reach itThe whole internet can — so security matters
Free, alwaysMetered — you pay (or use free tier) for what runs
GitHub runners can't reach itThey can — so auto-deploy finally works

The payoff: the loop closes

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.

Cloud Concepts & Your Options

TermWhat it is
Region / ZonePhysical data-center location. Pick one near you (and your users).
Compute / VM / InstanceA rented virtual server (AWS EC2, GCP Compute Engine, Azure VM).
Public IPThe internet address your app is reachable at.
Firewall / Security GroupRules for which ports are open to the world. Lock this down.
Free tierA free allowance (always-free or 12-month). Stay inside it to pay $0.
Managed serviceThe cloud runs it for you (e.g. managed Kubernetes) — convenient, but usually not free.

Managed Kubernetes vs. a VM + k3s

Managed K8s (EKS/GKE/AKS)VM + k3s (this lab)
SetupCloud runs the control planeYou install lightweight k3s yourself
CostUsually not free (~$70+/mo)Fits a free-tier VM ($0)
Best forReal production at scaleLearning, small apps, this course

Why k3s

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.

Free-tier-friendly VM options

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.

Hands-on Lab: Go Live

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.

1

Create a free-tier VM

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).

Or provision with Terraform (Module 10)

The IaC skills transfer directly. An AWS example — same init/plan/apply loop you already know:

provider "aws" { region = "us-east-1" } resource "aws_instance" "app" { ami = "ami-0c7217cdde317cfec" # Ubuntu 22.04 (region-specific) instance_type = "t3.micro" # free-tier eligible key_name = "my-key" tags = { Name = "notes-app" } } output "public_ip" { value = aws_instance.app.public_ip }
2

SSH in and secure the basics

ssh -i my-key.pem ubuntu@<PUBLIC_IP> sudo apt update && sudo apt upgrade -y

Security minimums

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.

3

Install k3s

One command installs a complete Kubernetes cluster on the VM:

curl -sfL https://get.k3s.io | sh - sudo k3s kubectl get nodes # one node, Ready
4

Get the kubeconfig onto your laptop

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:

# on the VM: sudo cat /etc/rancher/k3s/k3s.yaml # copy that text to your laptop as kubeconfig, then replace # the server line 127.0.0.1 with your VM's public IP: # server: https://<PUBLIC_IP>:6443 export KUBECONFIG=./kubeconfig kubectl get nodes # now talking to the cloud!
5

Deploy the capstone

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:

kubectl apply -f k8s/ kubectl get pods -w # wait for Running
6

Expose it to the world

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:

kubectl patch svc web -p '{"spec":{"type":"LoadBalancer"}}' kubectl get svc web # note the EXTERNAL-IP / port

Open http://<PUBLIC_IP> in your browser — your notes app is live on the internet. ๐ŸŒโœ…

The "aha!" moment

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.

7

Close the loop: automatic deployment

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:

deploy: needs: build-and-push runs-on: ubuntu-latest steps: - name: Set up kubeconfig run: | mkdir -p $HOME/.kube echo "${{ secrets.KUBECONFIG }}" > $HOME/.kube/config - name: Roll out the new image run: | kubectl set image deployment/web \ web=ghcr.io/${{ github.repository }}:${{ github.sha }} kubectl rollout status deployment/web

Full CI/CD, for real

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.

8

Tear it all down ๐Ÿงน

The most important step. When you're done exploring, delete everything so nothing keeps running (or billing):

# if you used Terraform: terraform destroy # otherwise: terminate the VM in the console and # delete its disk, public IP, and any leftover resources.

Cost & Safety (Don't Skip)

Set a billing alert before anything else

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.

RuleWhy
Use only free-tier-eligible sizesA 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 costsPublic IPs, disks, and load balancers can bill separately from the VM.
Least privilege on credentialsNever use root/owner keys in CI; scope tokens to what they need.
Never commit secretsKeys in a public repo get scraped by bots within minutes.
Rotate anything exposedIf a credential leaks, revoke and replace it immediately.

Cheat Sheet

CommandWhat 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.yamlGet the cluster's kubeconfig
export KUBECONFIG=./kubeconfigPoint kubectl at your cloud cluster
kubectl apply -f k8s/Deploy your manifests
kubectl get svc webFind the public IP/port
terraform destroyDelete all provisioned infra

Troubleshooting

SymptomLikely cause & fix
SSH connection refused/timeoutPort 22 not open in the firewall, or wrong key/user (ubuntu vs ec2-user).
kubectl can't connect from laptopkubeconfig still says 127.0.0.1; change it to the public IP, and open port 6443.
Pods stuck ImagePullBackOffGHCR image is private — make the package public or add an image pull secret.
App not reachable in browserPort 80 closed in the firewall, or Service isn't LoadBalancer.
CI deploy job fails to authKUBECONFIG secret missing/wrong, or it points at 127.0.0.1.
Unexpected chargesA resource is still running — check the console for VMs, IPs, disks; destroy them.

Your Challenge

  • Provision the whole VM with Terraform (Module 10) instead of the console — then destroy it.
  • Point a free domain name at your public IP so the app has a real URL.
  • Add HTTPS with k3s's built-in Traefik ingress + a Let's Encrypt certificate.
  • Run your Prometheus + Grafana (Module 11) on the cloud cluster and view it remotely.
  • Bonus: try a managed Kubernetes service's free trial to compare it with k3s.
# in your local kubeconfig, change: server: https://127.0.0.1:6443 # to your VM's public IP: server: https://<PUBLIC_IP>:6443 # and make sure port 6443 is open in the cloud firewall.

Course Complete ๐ŸŽ“

Look how far you've come

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. ๐Ÿš€

Deploy to the Cloud

Read First Objectives What Changes Concepts & Options Hands-on Lab Cost & Safety Cheat Sheet Troubleshooting Challenge Course Complete