This content originally appeared on DEV Community and was authored by Akingbade Omosebi
Part 2 – Automating the Pipeline
In Part 1
of this series, I explained how I wanted my personal portfolio to be more than just a few HTML files sitting on GitHub Pages.
I wanted it to behave like a production-grade application: built, scanned, and deployed automatically with security woven into the process.
This is the part where things got interesting — the pipeline.
The App Itself
Let’s keep it real: my app is not a full-stack system.
It’s a portfolio website — plain and simple.
- HTML for structure
- CSS for styling
- JavaScript for a little interactivity
That’s it.
But what made it special was how I treated it:
- I Dockerized it using an NGINX base image to serve static files.
- I pushed that image to AWS Elastic Container Registry (ECR).
- Then, I deployed it to Azure Container Apps using Terraform.
Even though the app was static, the pipeline was dynamic.
The Pipeline Workflow
Here’s how the GitHub Actions workflow was designed:
- Checkout code from GitHub
- Build Docker image (NGINX serving my HTML/CSS/JS)
- Tag and push the image to AWS ECR
- Run security scans:
- Trivy → scan Docker image for vulnerabilities
- TFSEC → scan Terraform code
- SonarCloud → check code quality
- Deploy with Terraform to Azure Container Apps
The Roadblocks
It wasn’t smooth sailing at first.
Here are some of the biggest challenges I hit:
- SonarCloud Failures
- Initially it was configuration issue, till i understood it clearly and passed its project key, token, and needs into Repo-Env-Secrets & Variables.
- Then next; SonarCloud kept failing the Quality Gate.
- Why? Because my project had no backend logic — just HTML, CSS, and JS.
- That meant 0% test coverage (and SonarCloud hates that).
My fix: I kept SonarCloud in the pipeline, but marked it so failures didn’t block the build.
That way, I still got visibility on quality checks, but my deployments weren’t stopped.
2.** Docker “latest” Tag Problem**
- At first, I tagged my image as latest.
- The issue? If nothing in the image changed, ECR wouldn’t show a new version.
- It felt like my push was “skipped,” even though the workflow ran.
My fix: I switched to unique tags using Git commit SHA.
Here is my code block for that from my actions.
docker build -t my-portfolio:${{ github.sha }} .
docker push my-portfolio:${{ github.sha }}
This way, every commit created a brand new image version in ECR.
No confusion, easy rollback.
** Trivy Misconfiguration**
- My first Trivy scan failed with an invalid image reference error.
- I had forgotten to include the repository name before the image hash.
My fix: I updated the scan step to reference the full ECR image path.
Once fixed, Trivy scanned the image and reported vulnerabilities clearly.
- Terraform Secrets
- Terraform needed my ECR token and Azure credentials.
- Storing them in plain text was not an option.
My fix: I stored them securely in Terraform Cloud as sensitive variables. That way, I avoided exposing secrets in GitHub Actions or in my repo.
The Working Pipeline
After fixing those issues, my pipeline looked like this:
Commit to GitHub
↓
GitHub Actions kicks off
↓
Build Docker image (NGINX + portfolio files)
↓
Push image to AWS ECR (tagged with commit SHA)
↓
Run scans (SonarCloud, TFSEC, Trivy)
↓
Deploy with Terraform to Azure Container Apps
And the best part? Every push = automatic build + scan + deploy.
Why This Matters
Even though my app is just static HTML/CSS/JS, the pipeline is enterprise-grade.
It shows that:
- I can build CI/CD pipelines from scratch
- I can integrate security tools (DevSecOps mindset)
- I can work across AWS + Azure
- I can solve real-world problems like failing quality gates, versioning issues, and secret management.
This is the stuff hiring managers love to see — not just “I can write code,” but “I can run a secure DevOps workflow.”
** Next Up**
In Part 3, I’ll walk through the Terraform setup and how I provisioned Azure Container Apps with IaC.
Spoiler: Terraform Cloud made my life much easier, but it came with its own surprises.
Stay tuned.
This content originally appeared on DEV Community and was authored by Akingbade Omosebi