{"slug": "jenkins-ci-cd-pipeline-for-a-dockerized-node-js-application-manual-trigger-vs", "title": "Jenkins CI/CD Pipeline for a Dockerized Node.js Application: Manual Trigger vs Automatic Trigger Using GitHub Webhooks", "summary": "This article provides a step-by-step guide on building a CI/CD pipeline for a Dockerized Node.js application using Jenkins. It explains the transition from a manual deployment process, where a Jenkins job must be triggered by clicking \"Build Now,\" to a fully automated system using GitHub webhooks that automatically triggers builds and deployments upon code pushes. The guide also covers essential setup steps, including installing Docker, granting Jenkins Docker permissions, and configuring GitHub authentication with personal access tokens.", "body_md": "Have you ever pushed code to GitHub and wished your application could automatically build and deploy itself without logging into a server or clicking a button in Jenkins? In this article, you'll learn how to build a complete CI/CD pipeline for a Dockerized Node.js application using Jenkins, starting with manual deployments and progressing to fully automated deployments using GitHub webhooks.\n\nWe will cover:\n\n- Creating a Jenkins pipeline\n- Building a Docker image\n- Deploying a container\n- Triggering builds manually\n- Triggering builds automatically\n- GitHub Personal Access Tokens\n- Fine-grained vs Classic Tokens\n- Jenkins credentials\n- GitHub webhooks\n- Required Jenkins plugins\n- Common errors and troubleshooting The goal is to understand not only how to configure everything but also why each component is needed.\n\nNode.js Application Repo URL-\n\n[https://github.com/omkarsharma2821/Node.js-App-Deploy-Github-Action]\n\n## Architecture Overview\n\nThe complete flow looks like this:\n\n```\nDeveloper\n    |\n    | Git Push\n    v\nGitHub Repository\n    |\n    | Webhook\n    v\nJenkins\n    |\n    | Build Docker Image\n    v\nDocker\n    |\n    | Run Container\n    v\nApplication Running\n```\n\nWithout webhooks:\n\n```\nDeveloper\n    |\n    | Git Push\n    v\nGitHub Repository\n\nJenkins Build Now (Manual Trigger)\n    |\n    v\nBuild and Deploy\n```\n\nWith webhooks:\n\n```\nDeveloper\n    |\n    | Git Push\n    v\nGitHub Repository\n    |\n    v\nWebhook\n    |\n    v\nJenkins\n    |\n    v\nBuild and Deploy Automatically\n```\n\n## Prerequisites\n\nBefore starting, ensure you have:\n\n- Ubuntu Server\n- Jenkins installed\n- Docker installed\n- Git installed\n- GitHub repository\n- Node.js application with Dockerfile Verify installations:\n\n```\njenkins --version\ndocker --version\ngit --version\n```\n\n## Installing Docker on Jenkins Server\n\nInstall Docker:\n\n```\nsudo apt update\nsudo apt install docker.io -y\n```\n\nEnable Docker:\n\n```\nsudo systemctl enable docker\nsudo systemctl start docker\n```\n\nVerify:\n\n```\ndocker --version\n```\n\n## Allow Jenkins to Use Docker\n\nBy default Jenkins cannot execute Docker commands.\n\nAdd Jenkins user to Docker group:\n\n```\nsudo usermod -aG docker jenkins\n```\n\nRestart Jenkins:\n\n```\nsudo systemctl restart jenkins\n```\n\nVerify:\n\n```\nsudo su - jenkins\ndocker ps\n```\n\nIf Docker works without sudo, Jenkins is ready.\n\n## Creating the Pipeline\n\nInitially we created a Jenkins pipeline that manually clones the repository.\n\nExample:\n\n```\npipeline {\n    agent any\n\n    stages {\n\n        stage('Clone Repository') {\n            steps {\n                sh '''\n                    mkdir -p devops\n                    cd devops\n                    rm -rf Node.js-App-Deploy-Github-Action\n                    git clone -b main https://github.com/username/repository.git\n                '''\n            }\n        }\n\n        stage('Build Image') {\n            steps {\n                sh '''\n                    cd devops/Node.js-App-Deploy-Github-Action\n                    docker build -t node-app .\n                '''\n            }\n        }\n\n        stage('Deploy') {\n            steps {\n                sh '''\n                    docker run -d -p 8000:8080 node-app\n                '''\n            }\n        }\n    }\n}\n```\n\nThis works, but every deployment requires manually clicking:\n\n```\nBuild Now\n```\n\n## Problem with Multiple Deployments\n\nSuppose the application is already running.\n\nRunning:\n\n```\ndocker run -d -p 8000:8080 node-app\n```\n\nagain will fail because port 8000 is already occupied.\n\nError:\n\n```\nBind for 0.0.0.0:8000 failed\n```\n\n## Better Deployment Approach\n\nBefore starting a new container, remove the old one.\n\n```\ndocker rm -f node-app-container || true\n```\n\nThen start a new container:\n\n```\ndocker run -d --name node-app-container -p 8000:8080 node-app\n```\n\n## Understanding docker rm -f node-app-container || true\n\nLet's break it down.\n\n## docker rm\n\nRemoves a container.\n\n```\ndocker rm node-app-container\n```\n\nWorks only if container is stopped.\n\n### -f\n\nForce remove.\n\n```\ndocker rm -f node-app-container\n```\n\nThis:\n\n- Stops container\n- Removes container\n\n### ||\n\nOR operator.\n\nSyntax:\n\n```\ncommand1 || command2\n```\n\nIf command1 fails, command2 executes.\n\n### true\n\nAlways returns success.\n\n```\ntrue\n```\n\nExit code:\n\n```\n0\n```\n\n### Final Meaning\n\n```\ndocker rm -f node-app-container || true\n```\n\nIf container exists:\n\n```\nRemove it\n```\n\nIf container doesn't exist:\n\n```\nIgnore error and continue\n```\n\nThis prevents Jenkins from failing.\n\n## Manual Triggering\n\nThe simplest approach is manual execution.\n\nNavigate to:\n\n```\nJenkins Job\n|\n└── Build Now\n```\n\nAdvantages:\n\n- Easy to understand\nGood for learning\n\nDisadvantages:Requires human intervention\n\nNot real CI/CD\n\n## Automatic Triggering\n\nThe goal of CI/CD is:\n\n```\nCode Push\n    |\n    v\nAutomatic Build\n    |\n    v\nAutomatic Deployment\n```\n\nThis is where GitHub webhooks come into play.\n\n## **Required Jenkins Plugins**\n\nInstall the following Jenkins plugins before configuring the CI/CD pipeline:\n\n### **1. Git Plugin**\n\n- Enables Jenkins to interact with Git repositories.\n- Allows Jenkins to clone repositories, fetch changes, and checkout specific branches.\n- Required for integrating Jenkins with GitHub repositories.\n\n### **2. GitHub Plugin**\n\n- Provides integration between Jenkins and GitHub.\n- Allows Jenkins to communicate with GitHub repositories and services.\n- Supports GitHub-related features within Jenkins.\n\n### **3. GitHub Integration Plugin**\n\n- Enables GitHub webhook support.\n- Allows Jenkins to automatically trigger builds when code is pushed to GitHub.\n- Essential for implementing automated CI/CD workflows.\n\n### **4. Pipeline Plugin**\n\n- Enables support for Jenkins Pipelines.\n- Allows execution of Jenkinsfiles written in Declarative or Scripted Pipeline syntax.\n- Required for defining CI/CD workflows as code.\n\n### **5. Credentials Plugin**\n\n- Provides secure storage for sensitive information.\n- Allows storing:\n- GitHub Personal Access Tokens (PATs)\n- Usernames and passwords\n- SSH keys\n- API tokens\n\n- Prevents hardcoding secrets in Jenkins jobs and pipelines.\n\n## **GitHub Authentication**\n\nWhen Jenkins needs to access a GitHub repository, authentication requirements depend on the repository type.\n\n### **Public Repository**\n\n- Can typically be cloned without authentication.\n\nExample:\n\n```\ngit clone https://github.com/username/repository.git\n```\n\n### **Private Repository**\n\n- Requires authentication.\n- GitHub no longer supports account passwords for Git operations.\n- A Personal Access Token (PAT) must be used instead of a password.\n\n### **Why Use a Personal Access Token (PAT)?**\n\n- More secure than passwords.\n- Allows granular permission control.\n- Can be revoked without affecting your GitHub account password.\n- Recommended by GitHub for all Git operations requiring authentication.\n\n## Classic Personal Access Token\n\nOlder token type.\n\nAdvantages:\n\n- Simple\nEasy to configure\n\nDisadvantages:Broad permissions\n\nLess secure\n\nExample scopes:\n\n```\nrepo\nworkflow\nadmin:repo_hook\n```\n\n## Fine-Grained Personal Access Token\n\nNewer and recommended approach.\n\nAdvantages:\n\n- Repository-level access\n- Better security\n- Granular permissions Example:\n\n```\nRepository Access:\nOnly selected repositories\n```\n\nPermissions:\n\n```\nContents: Read and Write\nMetadata: Read\nWebhooks: Read and Write\n```\n\n## Fine-Grained vs Classic Token\n\n| Feature | Fine-Grained | Classic |\n|---|---|---|\n| Security | High | Lower |\n| Repository Scope | Specific | Broad |\n| Permission Control | Granular | Broad |\n| Recommended | Yes | Legacy |\n\nFor modern projects, prefer Fine-Grained tokens.\n\n## Adding GitHub Token to Jenkins\n\nNavigate to:\n\n```\nManage Jenkins\n|\nCredentials\n```\n\nSelect:\n\n```\nGlobal Credentials\n```\n\nChoose:\n\n```\nAdd Credentials\n```\n\nKind:\n\n```\nUsername with Password\n```\n\nExample:\n\n```\nUsername: GitHub Username\nPassword: Personal Access Token\n```\n\nID:\n\n```\ngithub-creds\n```\n\nSave.\n\n## Pipeline Script vs Pipeline Script from SCM\n\nMany beginners get confused here.\n\n## Pipeline Script\n\nPipeline stored inside Jenkins UI.\n\nExample:\n\n```\npipeline {\n    agent any\n}\n```\n\nAdvantages:\n\nQuick setup\n\nDisadvantages:Not version controlled\n\nDifficult to maintain\n\n## Pipeline Script from SCM\n\nPipeline stored in GitHub repository.\n\nRepository structure:\n\n```\nproject/\n|\n|-- Dockerfile\n|-- package.json\n|-- app.js\n|-- Jenkinsfile\n```\n\nJenkins automatically downloads Jenkinsfile.\n\nAdvantages:\n\n- Version controlled\n- Industry standard\n- Easier maintenance Recommended approach.\n\n## Configuring Pipeline from SCM\n\nCreate Jenkins job.\n\nSelect:\n\n```\nPipeline\n```\n\nUnder Definition:\n\n```\nPipeline script from SCM\n```\n\nSCM:\n\n```\nGit\n```\n\nRepository URL:\n\n```\nhttps://github.com/username/repository.git\n```\n\nBranch:\n\n```\n*/main\n```\n\nScript Path:\n\n```\nJenkinsfile\n```\n\nSave.\n\n## Creating GitHub Webhook\n\nNavigate to:\n\n```\nGitHub Repository\n|\nSettings\n|\nWebhooks\n|\nAdd Webhook\n```\n\nPayload URL:\n\n```\nhttp://JENKINS_PUBLIC_IP:8080/github-webhook/\n```\n\nContent Type:\n\n```\napplication/json\n```\n\nEvent:\n\n```\nJust the push event\n```\n\nSave webhook.\n\n## Configuring Jenkins Trigger\n\nOpen job configuration.\n\nUnder Build Triggers:\n\nSelect:\n\n```\nGitHub hook trigger for GITScm polling\n```\n\nSave.\n\n## Testing the Webhook\n\nPush code:\n\n```\ngit add .\ngit commit -m \"testing webhook\"\ngit push origin main\n```\n\nExpected flow:\n\n```\nGitHub Push\n    |\n    v\nWebhook\n    |\n    v\nJenkins\n    |\n    v\nPipeline Starts\n```\n\nNo manual click required.\n\n## Common Troubleshooting\n\n## Webhook Returns 404\n\nCause:\n\n```\nWrong webhook URL\n```\n\nCorrect:\n\n```\nhttp://SERVER-IP:8080/github-webhook/\n```\n\n## Webhook Returns 403\n\nCause:\n\n```\nAuthentication or security issue\n```\n\nVerify:\n\n- GitHub plugin\n- GitHub integration plugin\n\n## Webhook Returns 200 But Build Doesn't Start\n\nCommon cause:\n\n```\nPipeline Script instead of Pipeline Script from SCM\n```\n\nor\n\n```\nRepository mapping issue\n```\n\n## Dockerfile Not Found\n\nExample:\n\n```\nunable to evaluate symlinks in Dockerfile path\n```\n\nCause:\n\nWrong working directory.\n\nCheck:\n\n```\npwd\nls -la\n```\n\nVerify Dockerfile location.\n\n## Permission Denied While Running Docker\n\nCause:\n\n```\nJenkins not in docker group\n```\n\nFix:\n\n```\nsudo usermod -aG docker jenkins\nsudo systemctl restart jenkins\n```\n\n## Final Jenkinsfile\n\n```\npipeline {\n    agent any\n\n    stages {\n\n        stage('Build Image') {\n            steps {\n                sh '''\n                    docker build -t node-app .\n                '''\n            }\n        }\n\n        stage('Deploy') {\n            steps {\n                sh '''\n                    docker rm -f node-app-container || true\n                    docker run -d --name node-app-container -p 8000:8080 node-app\n                '''\n            }\n        }\n    }\n}\n```\n\n## Conclusion\n\nA Jenkins pipeline can be triggered manually or automatically. Manual triggering is useful for learning and testing, but real CI/CD begins when code pushes automatically trigger builds and deployments.\n\nThe recommended production approach is:\n\n- Store the Jenkinsfile in GitHub.\n- Use Pipeline Script from SCM.\n- Configure GitHub credentials using a Personal Access Token.\n- Enable GitHub webhook integration.\n- Use Docker for packaging and deployment.\n- Remove old containers before deploying new versions. With this setup, every code push automatically builds a Docker image, deploys a fresh container, and updates the application without requiring any manual intervention.\n\n✍️ **Author**: *Omkar Sharma*\n\n📬 *Feel free to connect on LinkedIn or explore more on GitHub*", "url": "https://wpnews.pro/news/jenkins-ci-cd-pipeline-for-a-dockerized-node-js-application-manual-trigger-vs", "canonical_source": "https://dev.to/omkarsharma2821/jenkins-cicd-pipeline-for-a-dockerized-nodejs-application-manual-trigger-vs-automatic-trigger-1j5b", "published_at": "2026-05-23 08:32:33+00:00", "updated_at": "2026-05-23 09:04:48.738532+00:00", "lang": "en", "topics": ["developer-tools", "open-source", "cloud-computing", "enterprise-software"], "entities": ["Jenkins", "GitHub", "Docker", "Node.js", "omkarsharma2821"], "alternates": {"html": "https://wpnews.pro/news/jenkins-ci-cd-pipeline-for-a-dockerized-node-js-application-manual-trigger-vs", "markdown": "https://wpnews.pro/news/jenkins-ci-cd-pipeline-for-a-dockerized-node-js-application-manual-trigger-vs.md", "text": "https://wpnews.pro/news/jenkins-ci-cd-pipeline-for-a-dockerized-node-js-application-manual-trigger-vs.txt", "jsonld": "https://wpnews.pro/news/jenkins-ci-cd-pipeline-for-a-dockerized-node-js-application-manual-trigger-vs.jsonld"}}