⚙️ 2. Real-World GitLab CI/CD Project: Dockerize and Deploy a Node.js App 🚀

Now that you've learned about GitLab like Pipelines, Runners, Variables & Secrets, and Artifacts, it’s time to bring it all together in a practical, real-world project. 🎯

In this project, you’ll:

✅ Build a Docker image of a Node.js app
✅ Push it securely to Docker Hub
✅ Automatically deploy it on your server using Docker Compose

Let’s get our hands dirty with some real DevOps action! 💻🐳


🪜 Step-by-Step Workflow

✅ Step 1: Import Project in GitLab

Start by creating or importing a Node.js application into your GitLab repository.
You can use your own app or fork a public sample Node.js app (e.g., a To-Do app or REST API).

📍 GitLab UI → New Project → Import repository / Create blank project


✅ Step 2: Set Up a Project-Specific Runner (Self-Hosted)

To run your pipeline jobs on your own infrastructure (not GitLab’s shared runners), you need a self-hosted runner.

🛠️ Install GitLab Runner on your Linux/Ubuntu server (EC2, GCP, or local VM):

sudo apt-get update
sudo apt-get install -y curl
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
sudo apt-get install gitlab-runner

🔗 Then register the runner with your GitLab project:

sudo gitlab-runner register

Provide:

  • GitLab URL

  • Registration token (from GitLab → Settings → CI/CD → Runners)

  • Description: this is self hosted runner

  • Tags: linux

  • Executor: shell or docker (depending on your setup). I'll go with shell.

📌 After registration, confirm that the runner is active and listed in your GitLab project under Settings → CI/CD → Runners.


✅ Step 3: Add Secure Variables (Secrets)

To securely log in to Docker Hub, add your credentials as masked and protected variables in GitLab:

📍 Go to → Project → Settings → CI/CD → Variables

KeyValueMasked ✅Protected ✅
DOCKERHUB_USERyour-docker-username
DOCKERHUB_PASSWORDyour-access-token / password

📌 These values will be injected securely into your pipeline and won’t appear in logs.


🛠️ Step 4: Create .gitlab-ci.yml File

Now define your CI/CD pipeline steps using this GitLab configuration file:

stages:
  - build
  - test
  - push
  - deploy

build_job:
  stage: build
  script:
    - echo "Image building"
    - docker build -t node-cicd-app:latest .
  tags:
    - linux  

test_job:
  stage: test
  script:
    - echo "Test job running"
  tags:
    - linux

push_job:
  stage: push
  script:
    - echo "Push to Docker Hub"
    - echo "$DOCKERHUB_PASSWORD" | docker login -u "$DOCKERHUB_USER" --password-stdin
    - docker image tag node-cicd-app:latest $DOCKERHUB_USER/node-cicd-app:latest
    - docker push $DOCKERHUB_USER/node-cicd-app:latest
  tags:
    - linux

deploy_stage:
  stage: deploy
  script:
    - echo "Application Deployment"
    - docker compose up -d
  tags:
    - linux

📘 Explanation of Each Stage

🔧 build_job
Builds a Docker image named node-cicd-app:latest from your Node.js source code.

🧪 test_job
Currently a placeholder. You can integrate tools like Jest, Mocha, or ESLint here later.

📦 push_job
Logs into Docker Hub securely using your secrets, tags the image, and pushes it to your Docker Hub repo.

🚀 deploy_stage
Runs docker compose up -d to deploy your app on the server. Make sure your docker-compose.yml is present in the project root.


🎉 What This Setup Achieves

Automated Build – Code changes instantly build new Docker images.
Secure Credentials – Secrets are stored safely using masked variables.
Push to DockerHub – Images are versioned and uploaded for portability.
Deploy Automatically – No need to SSH into your server manually.

Every commit → builds → tests → pushes → deploys. 🧠👏


🔐 Bonus Tip: Secure Docker Compose

If your docker-compose.yml includes environment variables (e.g., DB credentials), avoid committing them.
Use a .env file and add that as a GitLab CI/CD secret file for more security.


📦 Optional: Add Artifacts

If your build_job generates logs, test reports, or binaries, you can save them as artifacts:

artifacts:
  paths:
    - build/
  expire_in: 1 week

This allows downloading or passing files to other stages like test or deploy.


🧪 Real-Life Use Case

Imagine this scenario:

  • You're building a microservice in Node.js

  • Every push builds a Docker image and stores it on Docker Hub

  • A remote server automatically pulls and runs the latest version using Compose

You just built a mini DevOps pipeline like big companies use! 🚀🔥


✅ Final Thoughts :

This project helps you:

✅ Practice real CI/CD with GitLab
✅ Use secrets securely
✅ Work with Docker, Compose, and automation
✅ Understand the full DevOps lifecycle

🚀 Keep experimenting. Keep optimizing. Because in DevOps—automation isn’t just a tool, it’s a mindset.

0
Subscribe to my newsletter

Read articles from ABHISHEK WAGHMARE directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

ABHISHEK WAGHMARE
ABHISHEK WAGHMARE

An Introduction To DevOps: Where Development And Operations Meet 🔍 My DevOps learner journey has been inspired by a true passion for continual personal development and a genuine curiosity for cloud and automation technologies. With the practice of engaging in numerous online coursework and community threads, I have built a growing comprehension of what is necessary for everyday life in the tools offered from Docker, Jenkins, and Kubernetes, which are mandatories in the IT Society. 🛠 What sets me apart? A commitment to practical application. Through personal projects, I actively implement my learning to solve real-world problems, gaining hands-on experience. This proactive approach helps me not only understand technologies at a surface level but to deeply integrate them into effective solutions. My ultimate goal? To merge innovative DevOps practices with business objectives to streamline operations and boost productivity in any tech landscape. I am eager to bring my fresh perspective and evolving expertise to a vibrant team, where continuous learning is intertwined with company growth. 📨 Let’s connect and explore how we can drive progress together in the fascinating world of DevOps!