pipeline { agent any parameters { string(name: 'ROLLBACK_TAG', defaultValue: '', description: 'Khaali = normal build. Purana build number (jaise 2) = seedha us image par rollback, bina rebuild ke') } environment { REGISTRY = '51.195.4.170:5000' IMAGE_NAME = 'swim/demo-app' IMAGE_TAG = "${params.ROLLBACK_TAG?.trim() ? params.ROLLBACK_TAG : env.BUILD_NUMBER}" // Jenkins container ke andar workspace /var/jenkins_home/... hai, // par docker daemon HOST par chalta hai jahan wahi folder // /opt/devops/data/jenkins/... par hai. -v ke liye HOST ka path chahiye. JENKINS_HOME_CONTAINER = '/var/jenkins_home' JENKINS_HOME_HOST = '/opt/devops/data/jenkins' } options { timestamps() buildDiscarder(logRotator(numToKeepStr: '20')) timeout(time: 20, unit: 'MINUTES') } stages { stage('Checkout') { steps { checkout scm sh 'echo "commit: $(git rev-parse --short HEAD)"' } } stage('Test') { when { expression { !params.ROLLBACK_TAG?.trim() } } steps { sh ''' # container ka path -> host ka path badlo HOST_WS=$(echo "$PWD" | sed "s|^${JENKINS_HOME_CONTAINER}|${JENKINS_HOME_HOST}|") echo "container workspace : $PWD" echo "host workspace : $HOST_WS" docker run --rm -v "$HOST_WS":/src -w /src python:3.12-slim sh -c " pip install --quiet -r requirements-dev.txt && python -m pytest tests/ -v " ''' } } stage('Build image') { when { expression { !params.ROLLBACK_TAG?.trim() } } steps { sh ''' docker build \ --build-arg APP_VERSION=${IMAGE_TAG} \ -t ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG} \ -t ${REGISTRY}/${IMAGE_NAME}:latest . docker images ${REGISTRY}/${IMAGE_NAME} ''' } } stage('Smoke test image') { when { expression { !params.ROLLBACK_TAG?.trim() } } steps { sh ''' CID=$(docker run -d -P ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}) sleep 5 docker exec $CID python -c " import urllib.request, json, sys r = json.loads(urllib.request.urlopen('http://127.0.0.1:8000/version').read()) print('version endpoint:', r) assert r['version'] == '${IMAGE_TAG}', 'version galat!' " docker rm -f $CID ''' } } stage('Push to registry') { when { expression { !params.ROLLBACK_TAG?.trim() } } steps { withCredentials([usernamePassword(credentialsId: 'registry-creds', usernameVariable: 'REG_USER', passwordVariable: 'REG_PASS')]) { sh ''' echo "$REG_PASS" | docker login ${REGISTRY} -u "$REG_USER" --password-stdin docker push ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG} docker push ${REGISTRY}/${IMAGE_NAME}:latest docker logout ${REGISTRY} ''' } } } stage('Deploy to VM') { steps { withCredentials([usernamePassword(credentialsId: 'registry-creds', usernameVariable: 'REG_USER', passwordVariable: 'REG_PASS')]) { sh ''' export ANSIBLE_HOST_KEY_CHECKING=False export IMAGE_TAG=${IMAGE_TAG} ansible-galaxy collection install community.docker --force -q || true ansible-playbook -i deploy/inventory.ini deploy/deploy.yml ''' } } } } post { always { sh 'docker image prune -f --filter "until=24h" || true' cleanWs() } success { echo "BUILD ${env.BUILD_NUMBER} SAFAL -> ${env.REGISTRY}/${env.IMAGE_NAME}:${env.IMAGE_TAG}" } failure { echo "BUILD ${env.BUILD_NUMBER} FAIL" } } }