Files
k3s-gitops/apps/demo-nginx/Jenkinsfile.rollback

356 lines
14 KiB
Plaintext

// Jenkinsfile for Manual Rollback
// This allows rolling back to any previous version
pipeline {
agent any
parameters {
choice(
name: 'ROLLBACK_METHOD',
choices: ['IMAGE_TAG', 'REVISION_NUMBER', 'GIT_COMMIT'],
description: 'Select rollback method'
)
string(
name: 'TARGET_VERSION',
defaultValue: '',
description: '''
Enter target version based on method:
- IMAGE_TAG: main-21, main-20, etc.
- REVISION_NUMBER: 1, 2, 3 (from rollout history)
- GIT_COMMIT: abc123def (git commit SHA)
'''
)
booleanParam(
name: 'SKIP_HEALTH_CHECK',
defaultValue: false,
description: 'Skip health checks (use with caution!)'
)
booleanParam(
name: 'DRY_RUN',
defaultValue: false,
description: 'Dry run - show what would happen without applying'
)
}
environment {
APP_NAME = 'demo-nginx'
CONTAINER_NAME = 'nginx'
NAMESPACE = 'demo-app'
DOCKER_REGISTRY = 'docker.io'
DOCKER_REPO = 'vladcrypto'
GITEA_URL = 'http://gitea-http.gitea.svc.cluster.local:3000'
HEALTH_CHECK_TIMEOUT = '300s'
}
stages {
stage('Validate Input') {
steps {
script {
echo "🔍 Validating rollback request..."
// Trim whitespace from input
env.TARGET_VERSION_CLEAN = params.TARGET_VERSION.trim()
if (env.TARGET_VERSION_CLEAN == '') {
error("❌ TARGET_VERSION cannot be empty!")
}
echo """
📋 Rollback Configuration:
Method: ${params.ROLLBACK_METHOD}
Target: ${env.TARGET_VERSION_CLEAN}
Skip Health Check: ${params.SKIP_HEALTH_CHECK}
Dry Run: ${params.DRY_RUN}
"""
}
}
}
stage('Show Current State') {
steps {
script {
echo "📸 Current Deployment State:"
sh """
echo "=== Current Deployment ==="
kubectl get deployment ${APP_NAME} -n ${NAMESPACE}
echo ""
echo "=== Current Image ==="
kubectl get deployment ${APP_NAME} -n ${NAMESPACE} \
-o jsonpath='{.spec.template.spec.containers[0].image}'
echo ""
echo ""
echo "=== Container Name ==="
kubectl get deployment ${APP_NAME} -n ${NAMESPACE} \
-o jsonpath='{.spec.template.spec.containers[0].name}'
echo ""
echo ""
echo "=== Current Pods ==="
kubectl get pods -n ${NAMESPACE} -l app=${APP_NAME}
echo ""
echo "=== Rollout History ==="
kubectl rollout history deployment/${APP_NAME} -n ${NAMESPACE}
"""
}
}
}
stage('Prepare Rollback') {
steps {
script {
echo "🔄 Preparing rollback to: ${env.TARGET_VERSION_CLEAN}"
if (params.ROLLBACK_METHOD == 'IMAGE_TAG') {
env.TARGET_IMAGE = "${DOCKER_REGISTRY}/${DOCKER_REPO}/${APP_NAME}:${env.TARGET_VERSION_CLEAN}"
sh """
echo "Target image: ${env.TARGET_IMAGE}"
"""
} else if (params.ROLLBACK_METHOD == 'REVISION_NUMBER') {
env.REVISION = env.TARGET_VERSION_CLEAN
sh """
echo "Rolling back to revision: ${env.REVISION}"
# Verify revision exists
kubectl rollout history deployment/${APP_NAME} -n ${NAMESPACE} \
--revision=${env.REVISION}
"""
} else if (params.ROLLBACK_METHOD == 'GIT_COMMIT') {
env.GIT_SHA = env.TARGET_VERSION_CLEAN
echo "Rolling back to git commit: ${env.GIT_SHA}"
}
}
}
}
stage('Execute Rollback') {
when {
expression { !params.DRY_RUN }
}
steps {
script {
echo "🚀 Executing rollback..."
if (params.ROLLBACK_METHOD == 'IMAGE_TAG') {
// Method 1: Update image directly using correct container name
sh """
echo "Setting image to: ${env.TARGET_IMAGE}"
kubectl set image deployment/${APP_NAME} \
${CONTAINER_NAME}=${env.TARGET_IMAGE} \
-n ${NAMESPACE} \
--record
"""
// Update Git manifests
withCredentials([usernamePassword(
credentialsId: 'gitea-credentials',
usernameVariable: 'GIT_USER',
passwordVariable: 'GIT_PASS'
)]) {
sh """
rm -rf k3s-gitops || true
git clone http://\${GIT_USER}:\${GIT_PASS}@gitea-http.gitea.svc.cluster.local:3000/admin/k3s-gitops.git
cd k3s-gitops
git config user.name "Jenkins"
git config user.email "jenkins@thedevops.dev"
sed -i 's|image: .*|image: ${env.TARGET_IMAGE}|' apps/demo-nginx/deployment.yaml
git add apps/demo-nginx/deployment.yaml
git commit -m "rollback(demo-nginx): Manual rollback to ${env.TARGET_VERSION_CLEAN}" || echo "No changes"
git push origin main
"""
}
} else if (params.ROLLBACK_METHOD == 'REVISION_NUMBER') {
// Method 2: Rollback to specific revision
sh """
kubectl rollout undo deployment/${APP_NAME} \
-n ${NAMESPACE} \
--to-revision=${env.REVISION}
"""
} else if (params.ROLLBACK_METHOD == 'GIT_COMMIT') {
// Method 3: Checkout specific git commit
withCredentials([usernamePassword(
credentialsId: 'gitea-credentials',
usernameVariable: 'GIT_USER',
passwordVariable: 'GIT_PASS'
)]) {
sh """
rm -rf k3s-gitops || true
git clone http://\${GIT_USER}:\${GIT_PASS}@gitea-http.gitea.svc.cluster.local:3000/admin/k3s-gitops.git
cd k3s-gitops
git config user.name "Jenkins"
git config user.email "jenkins@thedevops.dev"
# Get image from specific commit
git checkout ${env.GIT_SHA} -- apps/demo-nginx/deployment.yaml
TARGET_IMAGE=\$(grep 'image:' apps/demo-nginx/deployment.yaml | awk '{print \$2}')
git checkout main
git checkout ${env.GIT_SHA} -- apps/demo-nginx/deployment.yaml
git add apps/demo-nginx/deployment.yaml
git commit -m "rollback(demo-nginx): Rollback to commit ${env.GIT_SHA}" || echo "No changes"
git push origin main
echo "Rolled back to image: \${TARGET_IMAGE}"
"""
}
}
echo "✅ Rollback command executed"
}
}
}
stage('Wait for Rollout') {
when {
expression { !params.DRY_RUN }
}
steps {
script {
echo "⏳ Waiting for rollout to complete..."
sh """
kubectl rollout status deployment/${APP_NAME} \
-n ${NAMESPACE} \
--timeout=${HEALTH_CHECK_TIMEOUT}
"""
echo "✅ Rollout completed"
}
}
}
stage('Health Check') {
when {
expression { !params.DRY_RUN && !params.SKIP_HEALTH_CHECK }
}
steps {
script {
echo "🏥 Running health checks..."
sh """
# Check all pods are ready
READY_PODS=\$(kubectl get deployment ${APP_NAME} -n ${NAMESPACE} -o jsonpath='{.status.readyReplicas}')
DESIRED_PODS=\$(kubectl get deployment ${APP_NAME} -n ${NAMESPACE} -o jsonpath='{.spec.replicas}')
echo "Ready pods: \${READY_PODS}/\${DESIRED_PODS}"
if [ "\${READY_PODS}" != "\${DESIRED_PODS}" ]; then
echo "❌ Not all pods are ready!"
exit 1
fi
# Test health endpoint
POD_NAME=\$(kubectl get pods -n ${NAMESPACE} -l app=${APP_NAME} -o jsonpath='{.items[0].metadata.name}')
kubectl exec \${POD_NAME} -n ${NAMESPACE} -- wget -q -O- http://localhost/health
"""
echo "✅ Health checks passed"
}
}
}
stage('Show New State') {
when {
expression { !params.DRY_RUN }
}
steps {
script {
echo "📊 New Deployment State:"
sh """
echo "=== New Deployment ==="
kubectl get deployment ${APP_NAME} -n ${NAMESPACE}
echo ""
echo "=== New Image ==="
kubectl get deployment ${APP_NAME} -n ${NAMESPACE} \
-o jsonpath='{.spec.template.spec.containers[0].image}'
echo ""
echo ""
echo "=== New Pods ==="
kubectl get pods -n ${NAMESPACE} -l app=${APP_NAME}
echo ""
echo "=== Updated Rollout History ==="
kubectl rollout history deployment/${APP_NAME} -n ${NAMESPACE}
"""
}
}
}
stage('Dry Run Summary') {
when {
expression { params.DRY_RUN }
}
steps {
script {
echo """
🔍 DRY RUN SUMMARY
This is what would happen:
Method: ${params.ROLLBACK_METHOD}
Target: ${env.TARGET_VERSION_CLEAN}
Steps that would be executed:
1. Update deployment to target version
2. Update Git manifests
3. Wait for rollout (timeout: ${HEALTH_CHECK_TIMEOUT})
${params.SKIP_HEALTH_CHECK ? '4. (Health check skipped)' : '4. Run health checks'}
No actual changes were made.
"""
}
}
}
}
post {
success {
script {
if (params.DRY_RUN) {
echo "✅ DRY RUN COMPLETED - No changes made"
} else {
echo """
✅ ROLLBACK SUCCESSFUL!
Application: ${APP_NAME}
Container: ${CONTAINER_NAME}
Method: ${params.ROLLBACK_METHOD}
Target: ${env.TARGET_VERSION_CLEAN}
Namespace: ${NAMESPACE}
The application has been rolled back successfully! ✨
"""
}
}
}
failure {
echo """
❌ ROLLBACK FAILED!
Please check the logs and try again.
Manual rollback commands:
kubectl rollout undo deployment/${APP_NAME} -n ${NAMESPACE}
Or set image directly:
kubectl set image deployment/${APP_NAME} ${CONTAINER_NAME}=<image> -n ${NAMESPACE}
"""
}
}
}