Automating a simple CI/CD Pipeline with GitHub Actions
A step-by-step guide to setting up a CI/CD pipeline for a Node.js app using GitHub Actions and Docker.
This post details my process of automating a CI/CD pipeline for a Node.js app using GitHub Actions and Docker. By setting up a workflow to build and test the app on every code push, I ensured consistent deployments and early error detection—key practices for reliable DevOps and SRE workflows.
Setting Up the Prerequisites
I installed Node.js for the app, Docker for containerization, and set up a GitHub repository to host the pipeline.
Install Node.js:
- Go to nodejs.org and download the LTS version (e.g., 18.x).
- Install it on your system (macOS, Windows, or Linux).
- Verify:
node --version
(should show v18.x.x).
Install Docker:
- Download Docker Desktop from docker.com/get-started.
- Install and start Docker.
- Verify:
docker --version
.
GitHub Repository: I created a repository named ci cd demo
on GitHub, using the Node.js .gitignore
template to exclude files like node_modules
.
Verify tool versions (
node --version
,docker --version
) before proceeding to avoid setup issues.
Building the Node.js App
I set up a Node.js app with Express to serve a “Hello, DevOps!” message on port 3000
.
Create the app In app.js
:
1
2
3
4
const express = require('express');
const app = express();
app.get('/', (req, res) => res.send('Hello, DevOps!'));
app.listen(3000, () => console.log('Running on 3000'));
Define Dependencies In package.json
:
1
2
3
4
5
6
7
8
9
10
{
"name": "ci-cd-demo",
"version": "1.0.0",
"dependencies": {
"express": "^4.18.2"
},
"scripts": {
"start": "node app.js"
}
}
Containerize the App In Dockerfile
:
1
2
3
4
5
6
7
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
I tested locally:
1
2
docker build -t ci-cd-demo .
docker run -p 3000:3000 ci-cd-demo
Visiting http://localhost:3000
displayed “Hello, DevOps!”, confirming the app was ready for automation.
Setting Up the CI/CD Pipeline with GitHub Actions
I created a GitHub Actions workflow to build and test the Docker image on pushes to the main
branch. In .github/workflows/deploy.yml
:
1
2
3
4
5
6
7
8
9
10
11
12
13
name: CI/CD Pipeline
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Docker Image
run: docker build -t ci-cd-demo .
- name: Test
run: docker run -d -p 3000:3000 ci-cd-demo && sleep 5 && curl http://localhost:3000
This workflow builds the image and tests the app by running the container and verifying the response with curl.
I pushed the code to GitHub:
1
2
3
git add .
git commit -m "feat(app): add Node.js app with CI/CD pipeline"
git push origin main
Ensure the container has enough startup time before testing—adjust the sleep duration (e.g., 10 seconds) if curl fails with “Connection refused.”
Verifying the Pipeline
An initial failure due to a “Connection refused” error was fixed by increasing the sleep duration to 10 seconds. I checked the pipeline run in the “Actions” tab of my GitHub repository. The workflow succeeded, with the test step logging “Hello, DevOps!”. GitHub Actions log showing successful test output
Visualizing the CI/CD Pipeline
I created a diagram using draw.io to illustrate the flow from code push to testing:
Cleaning Up
I stopped local Docker containers after testing:
1
2
docker ps # Find the container ID
docker stop <container-id>
Always stop unused containers to free up system resources and avoid port conflicts.
Conclusion
This CI/CD pipeline automated the build and test process for a Node.js app using GitHub Actions and Docker. Adjusting steps like the sleep duration ensured a stable workflow. It’s a straightforward setup for applying automation in DevOps and SRE practices.