⚙️ 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
ordocker
(depending on your setup). I'll go withshell
.
📌 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
Key | Value | Masked ✅ | Protected ✅ |
DOCKERHUB_USER | your-docker-username | ✅ | ✅ |
DOCKERHUB_PASSWORD | your-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.
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!