This document provides comprehensive, detailed, and professional CI/CD pipeline configurations for GitHub Actions, GitLab CI, and Jenkins. Each configuration is designed to automate the software delivery process, covering essential stages such as linting, testing, building, and deployment.
We will use a common scenario: a Node.js application that is containerized using Docker and deployed to a generic server environment. This allows for clear demonstration of the core CI/CD principles across different platforms.
To provide concrete and actionable examples, we'll base all pipeline configurations on the following assumptions:
npm run lint command).npm run test command). * Node.js dependencies (npm install).
* Application build step (e.g., npm run build for frontend assets, or just ensuring dependencies are installed for a backend service).
* Docker image creation for containerization.
* Staging Environment: Deploys automatically on successful merges to main/master.
* Production Environment: Deploys manually or on a tag/release, after successful staging deployment.
GitHub Actions provides a flexible and powerful CI/CD solution directly integrated into GitHub repositories.
This GitHub Actions workflow will:
main branch and pull requests..github/workflows/main.ymlname: Node.js CI/CD with Docker
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch: # Allows manual trigger for specific jobs
env:
NODE_VERSION: '18.x' # Specify Node.js version
DOCKER_IMAGE_NAME: my-nodejs-app # Name for your Docker image
DOCKER_REGISTRY: docker.io # Or your specific registry, e.g., ghcr.io
jobs:
lint:
name: Lint Code
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
test:
name: Run Tests
needs: lint # Ensures linting passes before testing
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run Jest tests
run: npm run test -- --coverage # Example with coverage report
build_and_push_docker_image:
name: Build & Push Docker Image
needs: test # Ensures tests pass before building
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.image_tag.outputs.tag }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Get current date for image tag
id: date
run: echo "::set-output name=date::$(date +'%Y%m%d%H%M%S')"
# Note: '::set-output' is deprecated, use 'echo "output_name=value" >> $GITHUB_OUTPUT' in newer versions
# For compatibility with older runners/actions, this example uses the older syntax.
# For GHA runner version >= 2.297.0, use: echo "date=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_OUTPUT
- name: Get commit SHA for image tag
id: sha
run: echo "::set-output name=sha::$(echo ${{ github.sha }} | cut -c1-7)"
# For GHA runner version >= 2.297.0, use: echo "sha=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
${{ env.DOCKER_REGISTRY }}/${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:latest
${{ env.DOCKER_REGISTRY }}/${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:${{ steps.sha.outputs.sha }}
${{ env.DOCKER_REGISTRY }}/${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:${{ steps.date.outputs.date }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Set image tag output
id: image_tag
run: echo "::set-output name=tag::${{ env.DOCKER_REGISTRY }}/${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:${{ steps.sha.outputs.sha }}"
# For GHA runner version >= 2.297.0, use: echo "tag=${{ env.DOCKER_REGISTRY }}/${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:${{ steps.sha.outputs.sha }}" >> $GITHUB_OUTPUT
deploy_staging:
name: Deploy to Staging
needs: build_and_push_docker_image
runs-on: ubuntu-latest
environment: Staging # Link to a GitHub Environment for protection rules
steps:
- name: Deploy to Staging Server
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.STAGING_SSH_HOST }}
username: ${{ secrets.STAGING_SSH_USER }}
key: ${{ secrets.STAGING_SSH_PRIVATE_KEY }}
script: |
# Navigate to application directory (adjust as needed)
cd /opt/my-nodejs-app-staging
# Log in to Docker registry on the server
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin ${{ env.DOCKER_REGISTRY }}
# Pull the new Docker image
docker pull ${{ needs.build_and_push_docker_image.outputs.image_tag }}
# Stop existing container (if running)
docker stop my-nodejs-app-staging || true
docker rm my-nodejs-app-staging || true
# Run new container
docker run -d --name my-nodejs-app-staging -p 80:3000 ${{ needs.build_and_push_docker_image.outputs.image_tag }}
echo "Deployment to Staging successful!"
deploy_production:
name: Deploy to Production
needs: deploy_staging # Ensures staging deployment is successful
runs-on: ubuntu-latest
environment: Production # Link to a GitHub Environment for protection rules
if: github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main' # Only allow manual trigger or on main branch push
# Note: For production, it's common to require manual approval or a tag/release trigger.
# The 'workflow_dispatch' allows manual trigger, which can be configured with required approvals in GitHub Environments.
steps:
- name: Deploy to Production Server
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.PROD_SSH_HOST }}
username: ${{ secrets.PROD_SSH_USER }}
key: ${{ secrets.PROD_SSH_PRIVATE_KEY }}
script: |
# Navigate to application directory (adjust as needed)
cd /opt/my-nodejs-app-prod
# Log in to Docker registry on the server
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin ${{ env.DOCKER_REGISTRY }}
# Pull the new Docker image (using 'latest' for simplicity, but commit SHA tag is safer for prod)
docker pull ${{ env.DOCKER_REGISTRY }}/${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:latest
# Stop existing container (if running)
docker stop my-nodejs-app-prod || true
docker rm my-nodejs-app-prod || true
# Run new container
docker run -d --name my-nodejs-app-prod -p 80:3000 ${{ env.DOCKER_REGISTRY }}/${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:latest
echo "Deployment to Production successful!"
This document presents a comprehensive analysis of the infrastructure considerations essential for designing and implementing a robust, efficient, and scalable CI/CD pipeline. As the foundational step in generating your custom DevOps pipeline configuration, understanding your underlying infrastructure, current processes, and future goals is paramount. This analysis aims to identify key requirements, potential challenges, and strategic recommendations to ensure the generated pipeline perfectly aligns with your operational landscape.
To deliver an optimal CI/CD pipeline configuration (GitHub Actions, GitLab CI, or Jenkins), a thorough understanding of your infrastructure is critical. This initial analysis identifies the core pillars of a successful CI/CD ecosystem: Source Code Management (SCM), application architecture, build environments, testing frameworks, deployment targets, and security protocols. Without specific customer input on existing infrastructure, this document outlines the crucial data points required for effective pipeline generation.
Key trends emphasize cloud-native solutions, containerization, Infrastructure as Code (IaC), and integrated security ("Shift Left"). Our recommendations focus on modularity, automation, security, and cost-efficiency. The immediate next step is to gather specific details regarding your current and desired infrastructure, which will directly inform the subsequent pipeline design phase.
To generate an effective CI/CD pipeline, we need to gather specific details about your environment. Below is a framework outlining the critical information required.
* GitHub (GitHub.com, GitHub Enterprise)
* GitLab (GitLab.com, GitLab Self-Managed)
* Bitbucket (Cloud, Server/Data Center)
* Azure DevOps Repos
* Other (e.g., AWS CodeCommit, self-hosted Git)
* GitHub Actions
* GitLab CI/CD
* Jenkins
* Azure Pipelines
* CircleCI, Travis CI, etc.
Note: If no preference, we can recommend based on SCM.*
* Monolith
* Microservices (number of services, inter-service communication)
* Serverless (Functions, APIs)
* Mobile (iOS, Android, React Native, Flutter)
* Desktop (Windows, macOS, Linux)
* Static Website/SPA (React, Angular, Vue)
* Other (e.g., IoT, Embedded)
* Java (Spring Boot, Quarkus, Maven, Gradle)
* Python (Django, Flask, FastAPI, Poetry, Pipenv)
* Node.js (Express, NestJS, React, Angular, Vue, NPM, Yarn)
* Go (Gin, Echo, Go Modules)
* .NET (C#, ASP.NET Core, NuGet)
* Ruby (Rails, Bundler)
* PHP (Laravel, Symfony, Composer)
* Other (e.g., Rust, Scala, Kotlin)
* Relational: PostgreSQL, MySQL, SQL Server, Oracle, MariaDB
* NoSQL: MongoDB, Cassandra, DynamoDB, Redis, Elasticsearch
* Data Warehousing: Snowflake, Redshift, BigQuery
* Are you currently using Docker?
* Are you planning to containerize your applications?
* Are you using Virtual Machines (VMs) for development/production?
* Terraform, CloudFormation, Azure ARM Templates, Pulumi, Ansible.
* Existing IaC practices?
* Managed/Cloud-hosted runners (e.g., GitHub-hosted runners, GitLab Shared Runners, Jenkins agents on cloud VMs)
* Self-hosted runners (on-premises, custom cloud VMs)
* Specific OS requirements for builds (Linux, Windows, macOS)?
* Specific hardware requirements (e.g., GPU for ML models)?
* Unit Testing: JUnit, Pytest, Jest, GoConvey, NUnit
* Integration Testing: Testcontainers, Mockito, Cypress
* End-to-End (E2E) Testing: Selenium, Playwright, Cypress, Puppeteer
* Performance Testing: JMeter, K6, LoadRunner
* Security Testing: SAST (SonarQube, Snyk), DAST (OWASP ZAP), SCA (Dependabot, Snyk)
* Container Registries: Docker Hub, AWS ECR, Azure Container Registry, Google Container Registry, GitLab Container Registry.
* Package Registries: Nexus, Artifactory, npm registry, Maven Central.
* AWS (EC2, ECS, EKS, Lambda, S3, Amplify, Lightsail)
* Azure (VMs, AKS, Azure Functions, App Service, Static Web Apps)
* Google Cloud Platform (GCE, GKE, Cloud Functions, App Engine, Cloud Run)
* Other (DigitalOcean, Heroku, Vercel, Netlify, Render)
* Virtual Machines (VMware, Hyper-V, KVM)
* Kubernetes Clusters (OpenShift, Rancher, bare-metal K8s)
* Bare Metal Servers
* Rolling Updates
* Blue/Green Deployments
* Canary Releases
* Feature Flags
* Serverless deployments
* Cloud-native solutions (AWS Secrets Manager, Azure Key Vault, GCP Secret Manager)
* HashiCorp Vault
* Environment variables, CI/CD platform secrets
* How are permissions managed for CI/CD tools to access cloud resources? (IAM Roles, Service Principals, Service Accounts)
The DevOps landscape is continuously evolving. Understanding key trends helps in designing a future-proof CI/CD pipeline.
Insight*: 70% of organizations are leveraging cloud-native architectures for new applications (CNCF Survey).
Insight*: Over 90% of enterprises using containers are using Kubernetes in production (Red Hat State of Kubernetes report).
Insight*: Organizations using IaC report 2-3x faster infrastructure provisioning times.
Insight*: Fixing security vulnerabilities in the design phase costs 10x less than fixing them in production.
Based on the general principles of modern DevOps and the outlined infrastructure considerations, we recommend the following strategic approaches:
To proceed with generating the precise and effective CI/CD pipeline configurations, we require detailed information about your specific infrastructure.
Action Required from Customer:
Please provide specific answers to the questions outlined in Section 1: Understanding Your Current & Desired Infrastructure (Framework for Analysis). The more detailed and accurate your responses, the more tailored and effective the generated CI/CD pipeline will be.
Once we receive this critical information, we will move to Step 2: Generate Pipeline Configurations,
name: The name of the workflow.on: Defines when the workflow runs. * push to main: Triggers on every push to the main branch.
* pull_request to main: Triggers on pull requests targeting main.
* workflow_dispatch: Allows manual triggering of the workflow from the GitHub UI.
env: Global environment variables for the workflow.jobs: A workflow run is made up of one or more jobs. * lint:
* runs-on: ubuntu-latest: Specifies the runner environment.
* uses: actions/checkout@v4: Checks out your repository code.
* uses: actions/setup-node@v4: Sets up the Node.js environment.
* npm ci: Installs dependencies from package-lock.json (recommended for CI).
* npm run lint: Executes the linting script defined in package.json.
* test:
* needs: lint: Ensures this job only runs after lint completes successfully.
* Similar setup to lint, then runs npm run test.
* build_and_push_docker_image:
* needs: test: Ensures this job only runs after test completes successfully.
* uses: docker/setup-buildx-action@v3: Sets up Docker Buildx for advanced Docker features.
* uses: docker/login-action@v3: Logs into Docker Hub using secrets.
steps.date & steps.sha: Generate dynamic tags for the Docker image (timestamp and short commit SHA). Note the comment about ::set-output deprecation.*
* uses: docker/build-push-action@v5: Builds the Docker image and pushes it to Docker Hub with multiple tags (latest, commit SHA, timestamp).
* outputs: image_tag: Makes the generated image tag available to subsequent jobs.
* deploy_staging:
* needs: build_and_push_docker_image: Depends on the Docker image being built and pushed.
* environment: Staging: Links to a GitHub Environment, allowing for protection rules (e.g., required
This document provides detailed, professional, and actionable CI/CD pipeline configurations for three leading platforms: GitHub Actions, GitLab CI, and Jenkins. Each configuration includes essential stages such as linting, testing, building, and deployment, designed to establish a robust and automated software delivery process. These templates are generic and designed to be highly customizable for various project types (e.g., Node.js, Python, Java, Go, Dockerized applications).
Automating the software delivery lifecycle is crucial for modern development teams. This deliverable provides foundational CI/CD pipeline configurations that streamline your development workflow, enhance code quality, accelerate deployments, and improve overall team efficiency. By integrating linting, testing, building, and deployment into an automated pipeline, you ensure consistent quality and faster time-to-market.
Key Benefits:
Each pipeline configuration adheres to the following core CI/CD principles, breaking down the process into distinct, manageable stages:
* Purpose: Improve code readability, maintainability, and catch common mistakes early.
* Purpose: Ensure new features work as expected and existing functionality remains unbroken.
* Purpose: Create a consistent, versioned output ready for deployment.
* Purpose: Enable rapid and reliable delivery of applications to users. This stage often includes environment-specific configurations and approval gates for production.
Below are comprehensive templates for GitHub Actions, GitLab CI, and Jenkins. Each template is heavily commented to explain its purpose and includes placeholders for easy customization.
Overview: GitHub Actions provides a powerful and flexible CI/CD platform directly integrated with your GitHub repositories. Workflows are defined in YAML files (.github/workflows/) and can be triggered by various GitHub events.
Key Features:
push, pull_request, schedule, workflow_dispatch (manual), etc.pipeline.yml Example:
# .github/workflows/pipeline.yml
name: CI/CD Pipeline
# Controls when the workflow will run
on:
push:
branches:
- main
- develop
pull_request:
branches:
- main
- develop
workflow_dispatch: # Allows manual trigger
# Define reusable environment variables
env:
NODE_VERSION: '18.x' # Example for Node.js project
DOCKER_IMAGE_NAME: your-app-name # Replace with your application name
DOCKER_REGISTRY: ghcr.io/${{ github.repository_owner }} # Or your Docker Hub/ECR/GCR registry
jobs:
# --------------------------------------------------------------------------------------------------
# Stage 1: Linting
# --------------------------------------------------------------------------------------------------
lint:
name: Lint Code
runs-on: ubuntu-latest # Specify the runner environment
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js (if applicable)
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm' # Caches npm dependencies
- name: Install dependencies (if applicable)
run: npm ci # Or 'yarn install' for Yarn
- name: Run Linter (e.g., ESLint, Prettier, Flake8)
# Replace with your specific linting command
run: npm run lint || true # '|| true' allows the job to succeed even if lint errors are found, but logs them. Remove for strict enforcement.
# Example for Python: pip install flake8 && flake8 .
# Example for Go: go vet ./...
# --------------------------------------------------------------------------------------------------
# Stage 2: Testing
# --------------------------------------------------------------------------------------------------
test:
name: Run Tests
runs-on: ubuntu-latest
needs: lint # This job depends on the 'lint' job completing successfully
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js (if applicable)
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies (if applicable)
run: npm ci
- name: Run Unit and Integration Tests
# Replace with your specific test command
run: npm test # Or 'jest', 'pytest', 'go test ./...'
- name: Upload test results (e.g., for coverage reports)
if: always() # Always run this step even if tests fail
uses: actions/upload-artifact@v4
with:
name: test-results
path: ./coverage # Example path, adjust as needed
# --------------------------------------------------------------------------------------------------
# Stage 3: Building (and potentially Dockerizing)
# --------------------------------------------------------------------------------------------------
build:
name: Build Application
runs-on: ubuntu-latest
needs: test # This job depends on the 'test' job completing successfully
outputs:
# Pass the generated image tag to subsequent jobs
image_tag: ${{ steps.docker_build_and_push.outputs.image_tag }}
steps:
- name: Checkout code
uses: actions/checkout@v4
# --- Conditional steps for non-Dockerized builds (e.g., JAR, npm package) ---
- name: Set up Node.js (if applicable for non-Docker build)
if: false # Set to true if building a non-Docker Node.js artifact
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies (if applicable for non-Docker build)
if: false # Set to true if building a non-Docker Node.js artifact
run: npm ci
- name: Build application artifact (e.g., Vue/React build, Java JAR)
if: false # Set to true if building a non-Docker artifact
# Replace with your specific build command
run: npm run build # Example: 'mvn package', 'go build -o app'
- name: Upload application artifact
if: false # Set to true if building a non-Docker artifact
uses: actions/upload-artifact@v4
with:
name: ${{ env.DOCKER_IMAGE_NAME }}-artifact
path: ./dist # Example path to your built artifact
# --- Conditional steps for Dockerized builds ---
- name: Log in to Docker Registry
if: true # Set to false if not building a Docker image
uses: docker/login-action@v3
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} # Use GITHUB_TOKEN for GHCR, or a specific secret for others
- name: Set up Docker BuildX
if: true
uses: docker/setup-buildx-action@v3
- name: Build and push Docker image
id: docker_build_and_push
if: true
uses: docker/build-push-action@v5
with:
context: . # Path to the Dockerfile context
file: ./Dockerfile # Path to your Dockerfile
push: true
tags: |
${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE_NAME }}:${{ github.sha }}
${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE_NAME }}:latest # Optional: push 'latest' tag on main branch
build-args: |
# Example build arg: ENV_VAR=value
cache-from: type=gha
cache-to: type=gha,mode=max
# --------------------------------------------------------------------------------------------------
# Stage 4: Deployment to Development/Staging Environment
# --------------------------------------------------------------------------------------------------
deploy-dev:
name: Deploy to Development
runs-on: ubuntu-latest
needs: build # This job depends on the 'build' job completing successfully
environment:
name: Development # Define an environment for better visibility and protection rules
url: https://dev.your-app.com # Optional: URL to the deployed application
# Only deploy to dev/staging on pushes to 'develop' branch or manual trigger
if: github.ref == 'refs/heads/develop' || github.event_name == 'workflow_dispatch'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download artifact (if not using Docker)
if: false # Set to true if deploying a non-Docker artifact
uses: actions/download-artifact@v4
with:
name: ${{ env.DOCKER_IMAGE_NAME }}-artifact
path: ./deploy-artifact
- name: Deploy to Development Server (e.g., SSH, Kubernetes, AWS ECS/EC2)
# Replace with your specific deployment commands
run: |
echo "Deploying ${{ needs.build.outputs.image_tag || 'artifact' }} to development..."
# Example for SSH deployment:
# ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no user@${{ secrets.DEV_SERVER_IP }} "
# docker pull ${{ needs.build.outputs.image_tag }} &&
# docker stop ${{ env.DOCKER_IMAGE_NAME }} || true &&
# docker rm ${{ env.DOCKER_IMAGE_NAME }} || true &&
# docker run -d --name ${{ env.DOCKER_IMAGE_NAME }} -p 80:80 ${{ needs.build.outputs.image_tag }}
# "
# Example for Kubernetes (using kubectl):
# kubectl config use-context your-k8s-cluster-dev
# kubectl set image deployment/your-app-dev your-container=${{ needs.build.outputs.image_tag }} -n your-namespace-dev
env:
DEV_SERVER_IP: ${{ secrets.DEV_SERVER_IP }} # Store sensitive data in GitHub Secrets
SSH_KEY: ${{ secrets.DEV_SSH_PRIVATE_KEY }} # Store SSH key in secrets
# --------------------------------------------------------------------------------------------------
# Stage 5: Deployment to Production Environment (with manual approval)
# --------------------------------------------------------------------------------------------------
deploy-prod:
name: Deploy to Production
runs-on: ubuntu-latest
needs: deploy-dev # Production deployment should ideally follow successful staging deployment and testing
environment:
name: Production
url: https://your-app.com
# Only deploy to production on pushes to 'main' branch or manual trigger, AND after successful staging
if: github.ref == 'refs/heads/main' && github.event_name == 'push' || github.event_name == 'workflow_dispatch'
# Requires manual approval before proceeding
environment:
name:
\n