A Developer’s Tale: Crafting a CI/CD Pipeline for My Containerized React Portfolio Using GitHub Actions
Tags: cicd, react, docker, githubactions
Published: 2024-01-28 03:28:18

CI/CD was something I never truly understood, even after reading, listening to, and watching various resources on it — until the day I needed to automate my website. I have a static (for now) portfolio website, www.mointech.dev, where I make occasional updates, particularly to my attached resume.

The process used to be:

1. Make a change.
2. Push the code change to GitHub.
3. Build the React app.
4. Create a Docker image.
5. Push it to DockerHub.
6. Pull the image on my Raspberry Pi hosting the website.
7. Run the container.

This was too many steps for some small changes. Upon further exploration, I came across “CI/CD” — the same mystery I’d been trying to unravel. This time, however, I had a practical application for it, so I delved deeply, using my best tool: CHAT GPT. As the AI it is, it outlined the entire process and provided a crucial GitHub Actions YAML file. While deciphering this YAML file, I began to grasp a significant portion of the CI/CD methodology… sometimes in IT, it takes a while to understand a simple concept.

Before anyone says, _“evErYOne cAn do IT uSIng chAtgpT,”_ I want to clarify: I used ChatGPT as a tool, exactly how it’s meant to be used. It provided a clarified version of what I had already envisioned. Now that we’ve got that out of the way, let’s continue.

My goal was simple:

1. Push changes to the GitHub repo.
2. Trigger a CI/CD pipeline in GitHub Actions to create a Docker image.
3. Push the Docker image to DockerHub.
4. SSH into my web server.
5. Pull the Docker image from DockerHub.
6. Deploy my portfolio container.

This “simple” goal turned out to be akin to level 1000 of the snake game on the old Nokia 3310 (yeah, I was born in 1997 and played that).

I faced a lot… I mean A LOT of errors when I tried it. I’ll mention some notable ones and how I approached each issue and solved it. In the end, it took me 52 failed GitHub Actions to get it right. Buckle up for this ride.


## Issue #1: Container Does Not Reflect Change
This issue had nothing to do with GitHub Actions but more with testing the Docker image, container, and connection to Docker Hub. The problem was that every time I made changes to the code and created an image, the change wasn’t reflected. After almost 2 hours of testing, trying, and cursing, the solution was Ctrl + Shift + R. Yes, you read that right! It was my browser cache that didn’t want to update. This was a wholesome error, to be honest.


##Issue #2: GitHub Shenanigans
This issue was a cluster of many problems. It was my first time using GitHub Actions in my project, so it took me a while to get comfortable with setting secrets, environment variables, SSH keys, and other minor things. One notable issue was that, for some reason, after building the Docker image, the actions VM couldn’t push it due to a two-section build and a weird issue with the system deleting the image file. Later, I realized it was my doing; while executing ‘rm -rf ./dist/*’, I accidentally removed the dist directory itself. Most of the issues I faced with actions were due to my lack of experience using it.

## Issue #3: OS Architecture Mismatch
This was the most challenging issue, the final boss of this whole adventure. The issue was quite unique compared to the others. For context, my Raspberry Pi (web server) runs on Ubuntu 22.04 LTS (arm64v8 architecture), and the GitHub Actions platform also used Ubuntu 22.04, but I wasn’t sure about the architecture. The problem was that the Docker image created on the GitHub Actions platform wasn’t compatible when I tried to run the container on my RPi. After two days of grappling with this, I decided to ditch the idea of using the GitHub platform to create the image, and I’ll explain how I achieved my goal without tearing my hair out.
When you can’t climb a wall, break that sh*t!

I tried, and when I say I tried, I really, really tried to solve this platform mismatch issue. I spent hours on it, attempting to do the whole “CI/CD” in the GitHub Actions way. Then, I realized my goal wasn’t to use a specific tool to automate my web app deployment, but to automate my web app deployment, no matter how I achieved it.

I wrote a bash script to create, push, pull, and deploy the Docker image/container. Things were a bit different, as I needed the git repo on my RPi as well, but in the end, I still used GitHub Actions as a tool to kick-start the automation. Every time I pushed changes to my main branch, I SSH-ed into my web server using GitHub Actions and ran my script that handled all the other steps, consisting of:

1. Pulling the GitHub Repo.
2. Creating the Docker Image.
3. Pushing it to DockerHub (no longer needed, but I kept it).
4. Deploying the web app Container.

It was one heck of an adventure, and I learned a lot. I didn’t need to do all this just for a static portfolio website, but I wanted to, just for fun. And what is life without having fun with complex stuff? ;)

I hope you enjoyed reading about my automation journey. Stay tuned for more!