
Why projects matter more than you think
A certificate tells a recruiter you studied. A project tells a hiring manager you can do the work. When someone is looking through a pile of CVs for a junior cloud or DevOps role, most of the candidates will list the same courses and the same entry-level certificates. The ones who get called are often the ones with a link the reviewer can open and understand in a few minutes.
Good portfolio projects are small, finished and well explained. They show that you can make decisions, deal with things going wrong, and describe what you did in plain language. That is most of the job.
This guide walks through five projects that, together, cover what cloud and DevOps employers commonly look for: automated delivery, infrastructure as code, containers, monitoring, and cost and security awareness. They are designed to be built one on top of the other, so by the end you have a single coherent system rather than five unrelated toys. It also covers how to keep your cloud bill near zero, how to present the work, a realistic 12-week plan, and the mistakes that quietly sink otherwise good portfolios.
Before you start: set up so you do not get a surprise bill
Cloud bills are charged in dollars, and many Nigerian debit cards either fail on international payments or carry tight limits. A forgotten load balancer or Kubernetes cluster can cost more in a week than you expected to spend in a month. Do these things on day one.
- Create a budget alert on whichever provider you use. Set it low, for example 5 or 10 dollars, with email alerts at 50%, 80% and 100%.
- Turn on multi-factor authentication for the root or owner account, and do your daily work as a separate user, not the root account.
- Use free tiers and credits deliberately. AWS, Azure and Google Cloud all offer free tiers or starter credits for new accounts. Read the current terms on the official site, because what is free and for how long changes.
- Tag everything with something like
project=portfolioso you can find and delete it later. - Destroy what you are not using. If you build with Terraform (project 2),
terraform destroyat the end of each session becomes a habit.
On AWS, a budget can be created from the command line:
aws budgets create-budget \
--account-id 123456789012 \
--budget '{"BudgetName":"portfolio-cap","BudgetLimit":{"Amount":"10","Unit":"USD"},"TimeUnit":"MONTHLY","BudgetType":"COST"}' \
--notifications-with-subscribers '[{"Notification":{"NotificationType":"ACTUAL","ComparisonOperator":"GREATER_THAN","Threshold":80,"ThresholdType":"PERCENTAGE"},"Subscribers":[{"SubscriptionType":"EMAIL","Address":"you@example.com"}]}]'On Azure, use Cost Management + Billing > Budgets in the portal and attach an email action group. If you want to understand cost properly rather than just avoid it, our FinOps Practitioner track covers this in depth.
Power and internet. Plan for interruptions. Work in short commits so an outage never costs you more than an hour of work. Much of this can be done locally (Docker, kind or minikube for Kubernetes, Terraform plans) and only pushed to the cloud when you have a stable connection. Browser-based labs such as CloudArcade are useful for practising on a phone or a slow laptop.
Pick one simple app and reuse it
Do not invent a new app for each project. Choose one small application and carry it through all five. Good choices:
- A static personal site or CV page (HTML and CSS)
- A small API in Python (Flask or FastAPI) or Node.js (Express) with one or two endpoints, such as a "currency notes" or "bus fare" lookup
- A to-do or notes app with a small database
A tiny API is the best choice because it gives you something to health-check, containerise, scale and monitor. Here is a complete starting point in Python:
# app.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/health")
def health():
return {"status": "ok"}
@app.get("/fares/{route}")
def fare(route: str):
fares = {"ikeja-cms": 1500, "yaba-lekki": 2000}
return {"route": route, "fare_ngn": fares.get(route, "unknown")}The point is not the app. The point is everything you build around it.
Project 1: a website or API deployed with CI/CD
Goal: every time you push to the main branch, your code is tested and deployed automatically.
Steps:
- Put the app in a GitHub (or GitLab) repository with a simple test.
- Choose a hosting target. Low-cost options include a static site on Amazon S3 with CloudFront, Azure Static Web Apps, Azure App Service on a free or basic tier, or a single small virtual machine.
- Write a pipeline that installs dependencies, runs tests, and deploys only if tests pass.
- Store cloud credentials as pipeline secrets, never in the repository. Where you can, use OpenID Connect (OIDC) so the pipeline gets short-lived credentials instead of long-lived keys.
- Break a test on purpose and show that the deploy is blocked.
A minimal GitHub Actions workflow:
# .github/workflows/deploy.yml
name: test-and-deploy
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install -r requirements.txt pytest
- run: pytest
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy
run: ./scripts/deploy.sh
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}If you prefer GitLab, the same idea lives in .gitlab-ci.yml with test and deploy stages. The workflow is the same.
What it proves: you understand automated delivery, which is the centre of DevOps work.
Stretch goals: add a linting step, a staging environment that deploys automatically and a production environment that needs a manual approval, and a status badge in your README.
Project 2: the same infrastructure as code
Goal: recreate the hosting from project 1 with Terraform, so the whole environment can be destroyed and rebuilt with one command.
Steps:
- Write Terraform for the network (or resource group), the compute or app service, and storage.
- Store Terraform state remotely (an S3 bucket with locking, or an Azure Storage account), not on your laptop.
- Use variables for anything that changes between environments, and outputs for useful values such as the site URL.
- Run
terraform fmt,terraform validateandterraform planin your pipeline on every pull request. - Destroy everything, rebuild it, and record how long it took.
A small Azure example:
# main.tf
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0"
}
}
}
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "rg" {
name = "rg-portfolio-dev"
location = var.location
tags = { project = "portfolio" }
}
resource "azurerm_storage_account" "site" {
name = "stportfolio${var.suffix}"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
account_tier = "Standard"
account_replication_type = "LRS"
}terraform init
terraform plan -out plan.tfplan
terraform apply plan.tfplan
terraform destroy # at the end of every sessionYou can practise the workflow without touching a real cloud account in the Terraform Arena.
What it proves: you manage infrastructure repeatably and reviewably, not by clicking around a console.
Stretch goals: split the code into a reusable module, add dev and prod workspaces or folders, and run a security scanner such as Checkov or tfsec in the pipeline.
Project 3: a containerised app on Kubernetes
Goal: run your app in a container, with two or more copies behind a Service, and roll out a new version without downtime.
Steps:
- Write a Dockerfile. Use a slim base image, run as a non-root user, and keep the image small.
- Push the image to a registry (Docker Hub, GitHub Container Registry, Amazon ECR or Azure Container Registry), tagged with the git commit, not just
latest. - Run Kubernetes locally first with kind or minikube. Only move to a managed service (EKS, AKS or GKE) if you have credits and a budget alert, and delete the cluster when you finish.
- Write a Deployment with readiness and liveness probes pointing at
/health, and resource requests and limits. - Change the app, build a new image, update the Deployment, and show that requests keep succeeding during the rollout.
# Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
RUN useradd -m appuser
USER appuser
EXPOSE 8000
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: fares-api
spec:
replicas: 2
selector:
matchLabels:
app: fares-api
template:
metadata:
labels:
app: fares-api
spec:
containers:
- name: api
image: ghcr.io/yourname/fares-api:abc1234
ports:
- containerPort: 8000
readinessProbe:
httpGet: { path: /health, port: 8000 }
livenessProbe:
httpGet: { path: /health, port: 8000 }
resources:
requests: { cpu: "100m", memory: "128Mi" }
limits: { cpu: "250m", memory: "256Mi" }
---
apiVersion: v1
kind: Service
metadata:
name: fares-api
spec:
selector:
app: fares-api
ports:
- port: 80
targetPort: 8000kind create cluster --name portfolio
kubectl apply -f deployment.yaml
kubectl set image deployment/fares-api api=ghcr.io/yourname/fares-api:def5678
kubectl rollout status deployment/fares-api
kubectl rollout undo deployment/fares-api # show you can roll back tooIf containers are new to you, start with our Kubernetes for beginners guide.
What it proves: you understand containers, scaling, health checks and safe releases.
Stretch goals: package the manifests with Helm or Kustomize, add a HorizontalPodAutoscaler, or deploy through GitOps with Argo CD.
Project 4: monitoring and an alert
Goal: add a dashboard and at least one alert, then break something on purpose and show the alert firing.
Steps:
- Choose a tool. On a budget, a free uptime checker or the provider's own tools (Amazon CloudWatch, Azure Monitor) are fine. On Kubernetes, Prometheus and Grafana via the
kube-prometheus-stackHelm chart is the common learning setup. - Track the basics: is it up, how fast does it respond, how many errors.
- Create an alert that sends an email or a message to a channel you actually read.
- Break it: scale the Deployment to zero, or return errors from the API. Screenshot the alert.
- Write a short runbook: what the alert means, how to check it, how to fix it.
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install monitoring prometheus-community/kube-prometheus-stack
kubectl scale deployment fares-api --replicas=0 # trigger the outageAn example alert rule:
groups:
- name: fares-api
rules:
- alert: FaresApiDown
expr: kube_deployment_status_replicas_available{deployment="fares-api"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "fares-api has no available replicas"What it proves: you think about running systems, not just building them. Interviewers often ask "how would you know if it broke?", and this is your answer.
Project 5: a cost and security review
Goal: write a short, honest report on one of your projects, as if a manager had asked you to review it.
Include:
- Cost: what each resource costs per month (use the provider's pricing calculator), what you would change to make it cheaper, and the budget alert you set.
- Security findings: for example open ports, public storage, secrets in git history, containers running as root, over-permissive IAM roles. Say what you found and how you fixed it.
- Before and after: a small table showing the change.
| Finding | Risk | Fix |
|---|---|---|
| Storage container set to public | Anyone can list files | Made private, served through CDN |
| SSH open to 0.0.0.0/0 | Brute-force attempts | Restricted to my IP, then removed in favour of a bastion or session manager |
| Access key in an old commit | Account takeover | Rotated key, removed from history, switched to OIDC |
| VM running 24/7 | Paying for idle time | Scheduled shutdown outside lab hours |
Useful checks you can run yourself:
git log -p | grep -iE "secret|password|aws_access_key" # rough secrets check
trivy image ghcr.io/yourname/fares-api:abc1234 # container vulnerabilities
checkov -d ./terraform # IaC misconfigurationsWhat it proves: you think like an owner. Few junior candidates do this, so it stands out.
How the five projects compare
| Project | Main skills | Typical cost if done carefully | Time for a beginner | Good for roles |
|---|---|---|---|---|
| 1. CI/CD | Git, pipelines, secrets | Free tier or near zero | 1 to 2 weeks | DevOps, cloud support |
| 2. Terraform | IaC, state, reviews | Near zero if destroyed after use | 2 weeks | Cloud engineer, platform |
| 3. Kubernetes | Containers, scaling, rollouts | Zero locally; managed clusters cost money | 2 to 3 weeks | DevOps, SRE, platform |
| 4. Monitoring | Metrics, alerts, runbooks | Zero locally | 1 week | SRE, operations |
| 5. Cost and security | FinOps, IAM, scanning | Zero | 1 week | Any cloud role, FinOps |
Times are rough and depend on how many hours a week you have.
A realistic 12-week plan
This assumes around 8 to 10 hours a week alongside work or school.
- Weeks 1 to 2: Linux and Git basics, create cloud account with MFA and budget alert, build the small app. If the terminal still feels uncomfortable, read Linux skills for cloud jobs.
- Weeks 3 to 4: Project 1. Get the pipeline green, then break and fix it.
- Weeks 5 to 6: Project 2. Rebuild the hosting in Terraform with remote state.
- Weeks 7 to 9: Project 3. Docker first, then local Kubernetes, then a rolling update.
- Week 10: Project 4. Dashboard, alert, deliberate outage, runbook.
- Week 11: Project 5. Cost and security review.
- Week 12: Polish READMEs, draw diagrams, record a short demo video, write LinkedIn posts, and rehearse explaining each decision out loud.
If a week slips because of work, exams or a power problem, move the plan, do not skip the project. Finishing matters more than speed.
How to present your work
One repository per project, or one well-organised monorepo. Either works if it is easy to navigate. Pin the best ones on your GitHub profile.
A README that answers five questions in this order:
- What is this and what problem does it solve?
- A simple architecture diagram (draw.io or Excalidraw export is fine).
- How to run it, in copy-and-paste commands.
- What decisions you made and why (for example, why App Service and not a VM).
- What you would improve next and what went wrong along the way.
Show evidence. Screenshots of a green pipeline, a rollout, an alert firing, and a cost estimate. A two-minute screen recording is even better, and it helps reviewers who will not run your code.
Keep it tidy. No keys or passwords anywhere, including old commits. Meaningful commit messages. A .gitignore that excludes .terraform/, *.tfstate and .env.
Write about it. A short LinkedIn post per project with a diagram, one thing you learned and one thing that broke reaches recruiters directly and shows communication skills. Remote employers in particular hire on written communication.
Put it on your CV properly. One line per project with the result, not the tool list. "Built a Terraform-managed Azure environment that rebuilds in under 10 minutes, with plan checks on every pull request" says more than "Terraform, Azure, GitHub Actions".
Common mistakes to avoid
- Copying a tutorial line by line and publishing it unchanged. Reviewers recognise popular tutorials. Change the app, add a feature, and document what you did differently.
- Too many unfinished projects. Three finished ones beat ten half-built ones.
- No README, or a README that is just the framework's default.
- Leaving resources running. A managed Kubernetes cluster or NAT gateway left on for a month can produce a bill far larger than you planned for.
- Committing secrets. Bots scan public GitHub for keys. Assume anything pushed is exposed, rotate it, and clean the history.
- Not being able to explain it. If you cannot say why you chose a tool, an interviewer will find out in two questions.
- Ignoring the basics. Many interview failures are about Linux, networking (DNS, ports, HTTP) or SQL, not fancy tools. Close those gaps early.
Where certificates fit
Projects and certificates work together. A foundation exam such as AZ-900 (Azure Fundamentals) or AWS Certified Cloud Practitioner (CLF-C02) helps you pass CV filters. An associate exam such as AZ-104 (Azure Administrator) or AWS Solutions Architect Associate (SAA-C03) matches the depth of projects 1 and 2. For Kubernetes, KCNA is the entry point and CKA or CKAD are hands-on exams that line up with project 3. Check each provider's official site for current exam prices and any regional discounts. If you are unsure which cloud to start with, read AWS vs Azure: which to learn first.
Portfolio checklist
- Budget alert and MFA enabled
- One small app reused across all projects
- Pipeline that blocks deploys when tests fail
- Infrastructure rebuilt from Terraform with remote state
- Container image tagged by commit, running as non-root
- Kubernetes rollout and rollback demonstrated
- Dashboard, one alert, and a runbook
- Cost and security report with before-and-after table
- README with diagram, run steps, decisions and improvements
- No secrets in any commit
- LinkedIn post for each project
FAQ
Do I need to pay for cloud to build these?
Not much, if anything. Most of the work can be done locally or on free tiers. The risky parts are managed Kubernetes clusters, load balancers and NAT gateways. Use them briefly, with a budget alert, and destroy them the same day.
AWS or Azure for my portfolio?
Either is fine. Pick the one most common in the job adverts you are applying to and stay with it for all five projects. Showing depth in one cloud is better than shallow work in three.
My card keeps failing on cloud sign-up. What can I do?
Try a dollar-denominated virtual card from a reputable provider, or check with your bank about enabling international transactions. Until it works, keep building locally and in browser labs so you do not lose momentum.
Can I put a group or bootcamp project in my portfolio?
Yes, if you are clear about what you personally did. Interviewers will ask, and honesty about your part reads better than claiming the whole thing.
How many projects do I need before applying?
Start applying once you have two or three finished and well documented. Keep building while you apply. For more on landing that first role, see our guide to cloud jobs for beginners in Africa.
How SKILL.SCH helps
Every SKILL.SCH track is built around projects like these, with mentors who review your pipelines, Terraform and READMEs the way an employer would. At the end of your cohort you join the SSLabs virtual internship to work on real systems, and that work becomes evidence you can show in interviews. You can browse the options on our courses page.
If you want help choosing which projects to start with, which cloud to use, or how to fit this around your job, book a free consultation and we will plan your portfolio with you.

