From bc2af1dca79ba5134990d25cd9cd5d51016cc49c Mon Sep 17 00:00:00 2001 From: samin tausif Date: Mon, 12 May 2025 00:04:36 +0600 Subject: [PATCH 1/9] Adding Dockerfile for Dev-Branch --- Dockerfile | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4ce332f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +# Use a specific Node.js version as the base image +FROM node:16-alpine + +# Set environment variables for development and production environments +ARG ENV=development +ENV NODE_ENV $ENV + +# Set the working directory in the container +WORKDIR /usr/src/app + +# Copy package.json and package-lock.json (if available) +COPY package*.json ./ + +# Install dependencies +RUN npm install + +# Copy the rest of the application code into the container +COPY . . + +# Expose the port that your app will run on +EXPOSE 3000 + +# Set the default command to run your app +CMD ["npm", "start"] From 08df878169e7763e91d0863614605f37d22b3341 Mon Sep 17 00:00:00 2001 From: samin tausif Date: Mon, 12 May 2025 00:23:21 +0600 Subject: [PATCH 2/9] Adding Jenkinsfile to dev-branch --- Jenkinsfile | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..f79a353 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,62 @@ +pipeline { + agent any + environment + { + // Define environment variables here + DOCKER_REGISTRY = "localhost:5000" + DOCKER_IMAGE = "node-express-app" + BRANCH = "dev-branch" + GIT_URL = "https://github.com/SaminAhsanTausif/node-express-hello-devfile-no-dockerfile" + } + stages { + stage('Clone Repository') { + steps { + script { + // Clone the repository + echo "Cloning repository from ${GIT_URL} on branch ${BRANCH}" + git branch: "${BRANCH}", url: "${GIT_URL}" + } + } + } + stage('Build and Tage Docker Image') { + steps { + script { + // Build the Docker image + echo "Building Docker image ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" + sh "docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE} ." + } + } + stage('Push Docker Image') { + steps { + script { + // Push the Docker image to the registry + echo "Pushing Docker image ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" + //sh docker login ${DOCKER_REGISTRY} --username admin --password admin + sh "docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" + } + } + } + stage('Deploy and Test Docker Image'){ + steps{ + script{ + echo "Running Docker image locally to verify" + sh "docker pull ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" + sh "docker stop ${IMAGE_NAME} || true" + sh "docker rm ${IMAGE_NAME} || true" + sh "docker run -d -p 3000:3000 --name ${IMAGE_NAME} ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" + sh "docker ps" + } + } + } + } + } + post { + always { + echo 'Pipeline execution completed.' + } + failure { + echo 'Pipeline execution failed!' + } + } + +} \ No newline at end of file From 39d8d2d30c6880b621c3a6bf9b50ec18be4be7be Mon Sep 17 00:00:00 2001 From: samin tausif Date: Mon, 12 May 2025 01:14:49 +0600 Subject: [PATCH 3/9] Adding Jenkinsfile version:2 to dev-branch --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index f79a353..b343f87 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -6,7 +6,7 @@ pipeline { DOCKER_REGISTRY = "localhost:5000" DOCKER_IMAGE = "node-express-app" BRANCH = "dev-branch" - GIT_URL = "https://github.com/SaminAhsanTausif/node-express-hello-devfile-no-dockerfile" + GIT_URL = "https://github.com/SaminAhsanTausif/node-express-hello-devfile-no-dockerfile.git" } stages { stage('Clone Repository') { From a19c1cc65eb503476f1a90290590bb7a7d4f19e4 Mon Sep 17 00:00:00 2001 From: samin tausif Date: Mon, 12 May 2025 01:53:30 +0600 Subject: [PATCH 4/9] Resolving syntax errors in Jenkinsfile --- Jenkinsfile | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index b343f87..f203111 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -26,7 +26,8 @@ pipeline { sh "docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE} ." } } - stage('Push Docker Image') { + } + stage('Push Docker Image') { steps { script { // Push the Docker image to the registry @@ -35,8 +36,8 @@ pipeline { sh "docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" } } - } - stage('Deploy and Test Docker Image'){ + } + stage('Deploy and Test Docker Image'){ steps{ script{ echo "Running Docker image locally to verify" @@ -47,9 +48,9 @@ pipeline { sh "docker ps" } } - } + } } - } + // Post actions post { always { echo 'Pipeline execution completed.' From 20e8b876305046720c2d4b19b47c518450faa89a Mon Sep 17 00:00:00 2001 From: samin tausif Date: Mon, 12 May 2025 02:16:09 +0600 Subject: [PATCH 5/9] Including IMAGE_NAME in Jenkinsfile --- Jenkinsfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index f203111..33925a5 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -7,6 +7,7 @@ pipeline { DOCKER_IMAGE = "node-express-app" BRANCH = "dev-branch" GIT_URL = "https://github.com/SaminAhsanTausif/node-express-hello-devfile-no-dockerfile.git" + IMAGE_NAME = "${DOCKER_REGISTRY}/${DOCKER_IMAGE}" // Combine the registry and image name } stages { stage('Clone Repository') { @@ -18,7 +19,7 @@ pipeline { } } } - stage('Build and Tage Docker Image') { + stage('Build and Tag Docker Image') { steps { script { // Build the Docker image From ae2c0a927f7e01b1b081b1f46b0947eaa769aea5 Mon Sep 17 00:00:00 2001 From: samin tausif Date: Mon, 12 May 2025 02:25:21 +0600 Subject: [PATCH 6/9] Resolving container name issue --- Jenkinsfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 33925a5..87ae1fc 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -7,7 +7,6 @@ pipeline { DOCKER_IMAGE = "node-express-app" BRANCH = "dev-branch" GIT_URL = "https://github.com/SaminAhsanTausif/node-express-hello-devfile-no-dockerfile.git" - IMAGE_NAME = "${DOCKER_REGISTRY}/${DOCKER_IMAGE}" // Combine the registry and image name } stages { stage('Clone Repository') { @@ -43,9 +42,10 @@ pipeline { script{ echo "Running Docker image locally to verify" sh "docker pull ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" - sh "docker stop ${IMAGE_NAME} || true" - sh "docker rm ${IMAGE_NAME} || true" - sh "docker run -d -p 3000:3000 --name ${IMAGE_NAME} ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" + def containerName = "node-express-container" + sh "docker stop ${containerName} || true" + sh "docker rm ${containerName} || true" + sh "docker run -d -p 3000:3000 --name ${containerName} ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" sh "docker ps" } } From aedfb49338625cff0a21575ae88ae808bf7e1f59 Mon Sep 17 00:00:00 2001 From: samin tausif Date: Tue, 13 May 2025 15:44:05 +0600 Subject: [PATCH 7/9] Avoiding hardcoded values and including parameters in Jenkinsfile --- Jenkinsfile | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 87ae1fc..ccbddb0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -3,10 +3,14 @@ pipeline { environment { // Define environment variables here - DOCKER_REGISTRY = "localhost:5000" - DOCKER_IMAGE = "node-express-app" - BRANCH = "dev-branch" - GIT_URL = "https://github.com/SaminAhsanTausif/node-express-hello-devfile-no-dockerfile.git" + CONTAINER_NAME = "node-express-container" + } + parameters { + string(name: 'BRANCH', description: 'Branch to build') + string(name: 'GIT_URL', description: 'Git repository URL') + string(name: 'DOCKER_REGISTRY', description: 'Docker registry URL') + string(name: 'DOCKER_IMAGE', description: 'Docker image name') + credentials(name: 'DOCKER_CREDENTIALS', description: 'Credentials for Docker registry') } stages { stage('Clone Repository') { @@ -42,10 +46,9 @@ pipeline { script{ echo "Running Docker image locally to verify" sh "docker pull ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" - def containerName = "node-express-container" - sh "docker stop ${containerName} || true" - sh "docker rm ${containerName} || true" - sh "docker run -d -p 3000:3000 --name ${containerName} ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" + sh "docker stop ${CONTAINER_NAME} || true" + sh "docker rm ${CONTAINER_NAME} || true" + sh "docker run -d -p 3000:3000 --name ${CONTAINER_NAME} ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" sh "docker ps" } } From dc87a23e4f1f2b673000c32b55420f23d248ec1c Mon Sep 17 00:00:00 2001 From: samin tausif Date: Tue, 13 May 2025 15:53:21 +0600 Subject: [PATCH 8/9] Parameterizing Container name --- Jenkinsfile | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index ccbddb0..f2e8deb 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,16 +1,13 @@ pipeline { agent any - environment - { - // Define environment variables here - CONTAINER_NAME = "node-express-container" - } parameters { + // Define environment variables here string(name: 'BRANCH', description: 'Branch to build') string(name: 'GIT_URL', description: 'Git repository URL') string(name: 'DOCKER_REGISTRY', description: 'Docker registry URL') string(name: 'DOCKER_IMAGE', description: 'Docker image name') - credentials(name: 'DOCKER_CREDENTIALS', description: 'Credentials for Docker registry') + string(name: 'CONTAINER_NAME', description: 'Docker container name') + //credentials(name: 'DOCKER_CREDENTIALS', description: 'Credentials for Docker registry') } stages { stage('Clone Repository') { @@ -46,9 +43,9 @@ pipeline { script{ echo "Running Docker image locally to verify" sh "docker pull ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" - sh "docker stop ${CONTAINER_NAME} || true" - sh "docker rm ${CONTAINER_NAME} || true" - sh "docker run -d -p 3000:3000 --name ${CONTAINER_NAME} ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" + sh "docker stop ${params.CONTAINER_NAME} || true" + sh "docker rm ${params.CONTAINER_NAME} || true" + sh "docker run -d -p 3000:3000 --name ${params.CONTAINER_NAME} ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" sh "docker ps" } } From 6c9dfb93f40cbd36f99b15803735d5c76b896df3 Mon Sep 17 00:00:00 2001 From: Tausif <146830817+SaminAhsanTausif@users.noreply.github.com> Date: Tue, 13 May 2025 20:27:44 +0600 Subject: [PATCH 9/9] Update readme.md --- readme.md | 240 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 229 insertions(+), 11 deletions(-) diff --git a/readme.md b/readme.md index 40b697c..be3940f 100644 --- a/readme.md +++ b/readme.md @@ -1,18 +1,236 @@ -``` -npm install +#### Explanation of Key Sections of Dockerfile: -npm start +##### FROM node:16-alpine +##### Uses an official Node.js image based on Alpine Linux, which is lightweight and efficient. -curl localhost:8080 -``` +##### ARG ENV=development +##### Defines an argument that defaults to development. You can pass production during build time if needed. -OR for interactive development +##### ENV NODE_ENV $ENV +##### Sets the environment variable NODE_ENV to development or production based on the argument passed. -``` -npm install nodemon -g +##### WORKDIR +##### Sets the working directory for your app in the container. -npm run dev +##### *COPY package.json ./** +##### Copies only package.json and package-lock.json first, so that npm install runs faster by utilizing cached layers. -curl localhost:8080 -``` \ No newline at end of file +##### RUN npm install +##### Installs all dependencies defined in package.json. + +##### COPY . .: Copies the rest of the project files into the container. + +##### EXPOSE 3000: Exposes the port that your app will run on (adjust if needed). + +##### CMD ["npm", "start"] +##### The default command to start the app. Make sure npm start is configured in package.json + +#### Docker Registry Setup + +##### Step 1: Pull the Docker Registry Image +##### sudo docker pull registry:2 +##### This will download the latest version of the official Docker registry image from Docker Hub. + +##### Step 2: Run the Docker Registry Container +##### To start a local Docker registry on port 5000, use the following command: +##### docker run -d -p 5000:5000 --name registry registry:2 + +##### Explanation: + +##### -d: Run in detached mode + +##### -p 5000:5000: Maps port 5000 on local machine to port 5000 inside the container (-p 5000:5000). + +##### --name registry: Name the container 'registry +##### Uses the Docker registry version 2 image (registry:2). + +##### Step 3: Verify the Registry is Running + +##### Check if the registry is up and running: +##### sudo docker ps +##### We should see a container with the name registry running on port 5000. + +##### Inspect logs for issues: sudo docker logs registry + +##### Run Jenkins inside a Docker container +##### 1. Pull the Jenkins Docker Image +##### First, we'll need to pull the official Jenkins Docker image from Docker Hub. +##### Jenkins provides an official image that we can easily use. + +##### To do this, open the terminal and run the following command: docker pull jenkins/jenkins:lts +##### jenkins/jenkins:lts: This is the official Jenkins image, and lts stands for the Long-Term Support version of Jenkins, which is recommended for stability and security. + +##### This command will download the Jenkins image to local machine. + +##### 2. Create a Jenkins Container +##### Once the Jenkins image has been downloaded, we can run it in a container. +##### We need to use the following command to start Jenkins: +##### docker run -d --name jenkins -p 8080:8080 -p 50000:50000 --volume jenkins_home:/var/jenkins_home jenkins/jenkins:lts + +##### Explanation of the command: +##### 1. docker run -d: This runs the Jenkins container in detached mode (in the background). +##### 2. --name jenkins: Assigns the name jenkins to the container for easier management. +##### 3. -p 8080:8080: Maps port 8080 on your host machine to port 8080 in the container. +##### Jenkins’ web UI will be accessible on port 8080. +#####4. -p 50000:50000: Maps port 50000 for Jenkins agents to communicate with the Jenkins master. +##### 5. --volume jenkins_home:/var/jenkins_home +##### This mounts a persistent volume to store Jenkins data (e.g., job configurations, plugins, and build history). The volume is named jenkins_home. +#####6. jenkins/jenkins:lts: The Docker image you're using for the Jenkins container (LTS version). + +##### Unlock Jenkins +##### When we first access Jenkins, it will ask for an unlock key. +##### To find this key, we need to run the following command to get the container’s logs: +##### docker logs jenkins + +#### Manage Jenkins (Start/Stop) +##### Start Jenkins: If you stop the Jenkins container, you can restart it using: docker start jenkins +##### Stop Jenkins: To stop the container, run: docker stop jenkins +##### Remove Jenkins container: docker rm jenkins +##### To view Jenkins logs for debugging purposes, use: docker logs jenkins + +#### Jenkins Pipeline for Docker Image Automation +##### This Jenkins pipeline automates the process of building, tagging, pushing, deploying, and testing a Docker image from a Git repository. The pipeline is designed to be flexible by using parameterized inputs, making it easy to customize the build and deployment process. + +#### Pipeline Structure +##### The pipeline consists of the following key components: + +##### 1. Agent Definition: +##### pipeline { +##### agent any +##### Uses agent any to execute the pipeline on any available Jenkins agent. + +##### 2. Parameterized Inputs: +##### parameters { +##### string(name: 'BRANCH', description: 'Branch to build') +##### string(name: 'GIT_URL', description: 'Git repository URL') +##### string(name: 'DOCKER_REGISTRY', description: 'Docker registry URL') +##### string(name: 'DOCKER_IMAGE', description: 'Docker image name') +##### string(name: 'CONTAINER_NAME', description: 'Docker container name') +##### } +##### Uses the parameters block to allow users to input the following values: + +##### BRANCH: Git branch to be cloned. + +##### GIT_URL: URL of the Git repository. + +##### DOCKER_REGISTRY: Docker registry where the image will be pushed. + +##### DOCKER_IMAGE: Name of the Docker image to be created. + +##### CONTAINER_NAME: Name of the Docker container when running the image. + +##### This flexible approach avoids hardcoding values, promoting reusability. + +##### 3. Stages: +##### The pipeline is divided into four primary stages: + +##### a. Clone Repository: +##### stage('Clone Repository') { +##### steps { +##### script { + ##### echo "Cloning repository from ${GIT_URL} on branch ${BRANCH}" + ##### git branch: "${BRANCH}", url: "${GIT_URL}" + ##### } +##### } +##### } +##### Clones the specified branch from the given Git repository. + +##### b. Build and Tag Docker Image: +##### stage('Build and Tag Docker Image') { +##### steps { +##### script { +##### echo "Building Docker image ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" + ##### sh "docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE} ." + ##### } +##### } +##### } +##### Uses docker build to create a Docker image and tag it using the specified registry and image name. + +##### c. Push Docker Image: +##### stage('Push Docker Image') { +##### steps { +##### script { +##### echo "Pushing Docker image ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" +##### sh "docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" +##### } +##### } +##### } +##### Pushes the built image to the specified Docker registry. + +##### Optionally, Docker login can be performed (commented out for security). + +##### d. Deploy and Test Docker Image: +##### stage('Deploy and Test Docker Image') { +##### steps { +##### script { +##### echo "Running Docker image locally to verify" +##### sh "docker pull ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" +##### sh "docker stop ${params.CONTAINER_NAME} || true" + ##### sh "docker rm ${params.CONTAINER_NAME} || true" +##### sh "docker run -d -p 3000:3000 --name ${params.CONTAINER_NAME} ${DOCKER_REGISTRY}/${DOCKER_IMAGE}" + ##### sh "docker ps" +##### } +##### } +##### } +##### Deploys the image locally to verify successful creation. + +##### Stops and removes any existing container with the same name to avoid conflicts. + +##### Runs the new container and checks the running containers list. + +##### 4. Post Actions: +##### post { +##### always { +##### echo 'Pipeline execution completed.' +##### } +##### failure { +##### echo 'Pipeline execution failed!' +##### } +##### } +##### Ensures that completion or failure messages are logged after pipeline execution. + +#### How to Run the Pipeline via SCM in Jenkins: +##### Setup: +##### 1. Make sure your GitHub repository contains the Jenkinsfile in the root directory. +##### 2. The Jenkinsfile should be present in the dev-branch or main branch. + +#### Jenkins Configuration: +##### 1. Create a new Pipeline job in Jenkins. +##### 2. Under Pipeline settings, select Pipeline script from SCM. +##### 3. Choose Git as the SCM type. +##### 4. Provide the Repository URL from your GitHub repository. +##### 5. Set the Branch Specifier to the desired branch (e.g., */dev-branch or */main). +##### 6. Jenkins will automatically pull the Jenkinsfile from the specified branch when triggered. + +##### Execution: +##### 1. Once the pipeline is configured, Jenkins will automatically clone the repository and run the pipeline script as defined in the Jenkinsfile. +##### 2. You can manually trigger the pipeline from the Jenkins dashboard or set up a webhook for automatic triggers. + +##### Why Use SCM for Jenkins Pipeline: +##### 1. Automatic Updates: Any updates to the Jenkinsfile in the GitHub branch will be automatically picked up in subsequent builds. +##### 2. Version Control: Keeps track of pipeline changes along with code changes. +##### 3. Consistency: Ensures that the same pipeline script is used across different environments when switching branches. + +##### Potential error during Jenkins pipeline build: +##### "Building Docker image localhost:5000/node-express-app +##### [Pipeline] sh + docker build -t localhost:5000/node-express-app . +##### /var/jenkins_home/workspace/Test Project@tmp/durable-4a91558e/script.sh.copy: 1: docker: not found" + +#### How to resolve if we face this error? +##### Explanation: +##### 1. Ensure Docker is Installed on the Host Machine. +##### Run the following command on the host machine to check if Docker is installed: +##### docker --version +##### 2. Test the Docker Command Inside the Container +##### To further debug, we need to enter the container's shell and manually check if Docker is available and configured properly. +##### Run: docker exec -it /bin/bash +##### Then, inside the container, try running: docker --version +##### 3. Install Docker Inside the Jenkins Container. +##### Manually install Docker inside the Jenkins container by running the following commands: +##### apt-get update +##### apt-get install -y docker.io +##### After installing Docker, check the version: docker --version +##### 4. Verify Docker Socket to ensure that the Docker socket is correctly mounted from the host system to the Jenkins container. +##### This is necessary for Jenkins to communicate with the Docker daemon + ##### running on the host. Run the following command inside the Jenkins container: docker ps