This project implements a complete CI/CD pipeline for deploying a Dockerized Node.js service using Ansible and GitHub Actions. It follows the project requirements from roadmap.sh's Dockerized Service Deployment project with some additional enhancements.
We built a Node.js service that:
- Serves a "Hello, world!" message at the root endpoint
- Has a protected
/secret
endpoint with Basic Authentication - Includes a
/health
endpoint for health checks - Is containerized using Docker
- Is deployed using Ansible and GitHub Actions
- Uses Nginx as a reverse proxy
// Basic Express app with three endpoints:
- GET / → Returns "Hello, world!"
- GET /secret → Protected endpoint (Basic Auth)
- GET /health → Health check endpoint
- Created
Dockerfile
for the Node.js application - Multi-stage build for optimized image size
- Uses Node.js 18 Alpine base image
- Proper security practices (non-root user, minimal dependencies)
- Created playbooks for automated deployment:
docker-setup.yml
: Installs Docker and Nginxinventory.ini
: Defines control and target nodestemplates/nginx.conf.j2
: Nginx configuration template
- Automated CI/CD pipeline that:
- Builds Docker image
- Pushes to GitHub Container Registry
- Deploys to target EC2 instance
- Uses secrets for secure credential management
- Enhanced Security:
- UFW firewall configuration
- Proper permission management
- Environment variable handling
- Infrastructure Management:
- Separate control and target nodes
- Nginx reverse proxy setup
- Docker container lifecycle management
dockerized-service-deployment/
├── app/
│ ├── app.js # Main application code
│ ├── Dockerfile # Docker configuration
│ ├── package.json # Node.js dependencies
│ └── .env.example # Environment variables template
├── ansible/
│ ├── docker-setup.yml # Ansible playbook
│ ├── inventory.ini # Server inventory
│ └── templates/
│ └── nginx.conf.j2 # Nginx configuration template
├── .github/
│ └── workflows/
│ └── deploy.yml # GitHub Actions workflow
└── README.md # Project documentation
-
Application Development
# Initialize Node.js project npm init -y npm install express basic-auth
-
Docker Configuration
# Multi-stage build FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . FROM node:18-alpine WORKDIR /app COPY --from=builder /app . EXPOSE 3000 CMD ["node", "app.js"]
-
Ansible Setup
# docker-setup.yml - name: Setup Docker and Nginx hosts: target become: yes tasks: - name: Install Docker - name: Configure Nginx - name: Deploy application
-
GitHub Actions Configuration
# deploy.yml name: Deploy Dockerized Service on: push: branches: [ main ] jobs: build-and-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Build and push Docker image - name: Deploy to target node
Here are the test results showing our working implementation:
- Health Check Endpoint
// GET http://34.238.146.221:3000/health
{"status":"healthy","timestamp":"2025-02-10T09:58:17.768Z"}
- Root Endpoint
// GET http://34.238.146.221:3000/
{"message":"Hello, world!","timestamp":"2025-02-10T09:58:26.676Z"}
- Protected Endpoint
// GET http://34.238.146.221:3000/secret (with Basic Auth)
{"message":"'This is a secret message'","timestamp":"2025-02-10T09:58:35.283Z"}
-
Docker Best Practices
- Multi-stage builds
- Security considerations
- Environment variable management
-
Ansible Automation
- Infrastructure as Code
- Configuration management
- Role-based automation
-
CI/CD with GitHub Actions
- Automated workflows
- Secret management
- Container registry integration
-
Security Considerations
- Basic Authentication
- Environment variables
- Firewall configuration (UFW)
- Nginx as reverse proxy
-
Infrastructure Management
- AWS EC2 instance management
- Network security groups
- SSH key management
-
Port Access Issues
- Problem: Application not accessible after deployment
- Solution: Configured both UFW and AWS security groups
-
Process Management
- Problem: Port conflicts with existing processes
- Solution: Proper process cleanup and Docker container management
-
GitHub Actions Authentication
- Problem: Container registry access
- Solution: Proper secret management and permissions
roadmap.sh Dockerized Service Deployment
- Add HTTPS support with Let's Encrypt
- Implement container health checks
- Add monitoring and logging solutions
- Implement blue-green deployment strategy
- Add automated backups and disaster recovery