Created
May 18, 2017 15:49
-
-
Save nmasse-itix/dece6010f88cfff5fefe2c076e5eade5 to your computer and use it in GitHub Desktop.
Complete Jenkinsfile to do blue/green deployment in OpenShift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!groovy | |
// Define Maven Command. Make sure it points to the correct settings for our | |
// Nexus installation. The file nexus_openshift_settings.xml needs to be in the | |
// Source Code repository. | |
def mvn = "mvn -s ./nexus_openshift_settings.xml" | |
def sonarqube = "http://sonarqube-cicd.app.openshift.test/" | |
def nexusRepo = "openshift-task" | |
def nexusUrl = "http://nexus3-cicd.app.openshift.test/repository/${nexusRepo}/" | |
def credentialsId = "749214e0-4aa1-444b-8b17-599bfa084e3f" | |
def openshiftBuildConfig = "tasks" | |
def gitRepo = 'http://gogs.app.openshift.test/CICDLabs/openshift-tasks.git' | |
def targetAppTestUrl = "http://tasks.test.app.openshift.test" | |
def targetAppProdUrl = "http://tasks.prod.app.openshift.test" | |
// Run this node on a Maven Slave | |
// Maven Slaves have JDK and Maven already installed | |
node('maven') { | |
stage('Checkout Source') { | |
// Get Source Code from SCM (Git) as configured in the Jenkins Project | |
// Next line for inline script, "checkout scm" for Jenkinsfile from Gogs | |
//git url: "${gitRepo}", credentialsId: "${credentialsId}" | |
checkout scm | |
} | |
// The following variables need to be defined at the top level and not inside | |
// the scope of a stage - otherwise they would not be accessible from other stages. | |
// Extract version and other properties from the pom.xml | |
def pom = readMavenPom file: 'pom.xml' | |
def version = pom.version | |
def artifactId = pom.artifactId | |
def groupId = pom.groupId | |
// Using Maven build the war file | |
// Do not run tests in this step | |
stage('Build war') { | |
sh "${mvn} clean install -DskipTests=true" | |
} | |
// Using Maven run the unit tests | |
stage('Unit Tests') { | |
sh "${mvn} test" | |
} | |
// Using Maven call SonarQube for Code Analysis | |
stage('Code Analysis') { | |
sh "${mvn} sonar:sonar -Dsonar.host.url=${sonarqube}" | |
} | |
// Publish the latest war file to Nexus. This needs to go into <nexusurl>/repository/releases. | |
// Using the properties from the pom.xml file construct a filename that includes the version number from the pom.xml file | |
// Also update the Gogs project openshift-tasks-ocp by editing the .s2i/environment file. This file needs to have a line | |
// WAR_FILE_LOCATION=<actual URL of the war file in nexus> | |
// It is also a good idea to add another line like "BUILD_NUMBER=${BUILD_NUMBER}" to the environment file. Otherwise the | |
// push to Gig/Gogs will fail in case the version number didn't change. ${BUILD_NUMBER} is one of the Jenkins built-in | |
// variables. | |
stage('Publish to Nexus') { | |
sh "${mvn} deploy -DskipTests=true -DaltDeploymentRepository=nexus::default::${nexusUrl}" | |
} | |
// Build the OpenShift Image in OpenShift. Make sure to use the "oc new-build" command | |
// for the .s2i/bin/assemble script to retrieve the war file from the environment variable WAR_FILE_LOCATION. | |
// Also tag the image with "TestingCandidate-${version}" - e.g. TestingCandidate-1.5 | |
stage('Build OpenShift Image') { | |
// Determine the war filename that we need to use later in the process | |
String warFileName = "${groupId}.${artifactId}" | |
warFileName = warFileName.replace('.', '/') | |
def WAR_FILE_LOCATION = "${nexusUrl}/${warFileName}/${version}/${artifactId}-${version}.war" | |
echo "Will use WAR at ${WAR_FILE_LOCATION}" | |
// Trigger an OpenShift build in the dev environment | |
openshiftBuild bldCfg: "${openshiftBuildConfig}", checkForTriggeredDeployments: 'false', | |
namespace: "${openshiftBuildConfig}-dev", showBuildLogs: 'true', | |
verbose: 'false', waitTime: '', waitUnit: 'sec', | |
env: [ [ name: 'WAR_FILE_LOCATION', value: "${WAR_FILE_LOCATION}" ] ] | |
// Tag the new build as "x.y.build-z" | |
openshiftTag alias: 'false', destStream: 'tasks', destTag: "${version}.build-${BUILD_NUMBER}", | |
destinationNamespace: 'tasks-dev', namespace: 'tasks-dev', | |
srcStream: 'tasks', srcTag: 'latest', verbose: 'false' | |
} | |
// Deploy the built image to the Development Environment. Pay close attention to WHICH image you are deploying. | |
// Make sure it is the one you just tagged in the previous step. You may need to patch the deployment configuration | |
// of your application. | |
stage('Deploy to Dev') { | |
// Tag the new build as "ready-for-testing" | |
openshiftTag alias: 'false', destStream: 'tasks', srcTag: "${version}.build-${BUILD_NUMBER}", | |
destinationNamespace: 'tasks-dev', namespace: 'tasks-dev', | |
srcStream: 'tasks', destTag: 'ready-for-testing', verbose: 'false' | |
// Trigger a new deployment | |
openshiftDeploy deploymentConfig: 'tasks', namespace: 'tasks-test' | |
} | |
// Run some integration tests. | |
// Once the tests succeed tag the image as ProdReady-${version} | |
stage('Integration Test') { | |
// Run integration tests that are in the GIT repo | |
sh "./run-integration-tests.sh '${targetAppTestUrl}'" | |
} | |
// Blue/Green Deployment into Production | |
// ------------------------------------- | |
// Next two stages could be one. | |
// Make sure to deploy the right version. If green is active then deploy blue, and vice versa. | |
// You will need to figure out which application is active and set the target to the other. | |
stage('Prep Production Deployment') { | |
// Tag the new build as "ready-for-prod" | |
openshiftTag alias: 'false', destStream: 'tasks', srcTag: "${version}.build-${BUILD_NUMBER}", | |
destinationNamespace: 'tasks-dev', namespace: 'tasks-dev', | |
srcStream: 'tasks', destTag: 'ready-for-prod', verbose: 'false' | |
// Yes, this is mandatory for the next command to succeed. Don't know why... | |
sh "oc project tasks-prod" | |
// Extract the route target (tasks-green or tasks-blue) | |
// This will be used by getCurrentTarget and getNewTarget methods | |
sh "oc get route tasks -n tasks-prod -o template --template='{{ .spec.to.name }}' > route-target" | |
} | |
// Deploy the ProdReady-${version} image. Make sure this is the actual tagged image deployed! | |
// Do not activate the new version yet. | |
stage('Deploy new Version') { | |
def newTarget = getNewTarget() | |
// Trigger a new deployment | |
openshiftDeploy deploymentConfig: "${newTarget}", namespace: 'tasks-prod' | |
openshiftVerifyDeployment deploymentConfig: "${newTarget}", namespace: 'tasks-prod' | |
} | |
// Once approved (input step) switch production over to the new version. | |
stage('Switch over to new Version') { | |
def newTarget = getNewTarget() | |
def currentTarget = getCurrentTarget() | |
// Wait for administrator confirmation | |
input "Switch Production from ${currentTarget} to ${newTarget} ?" | |
// Switch blue/green | |
sh "oc patch -n tasks-prod route/tasks --patch '{\"spec\":{\"to\":{\"name\":\"${newTarget}\"}}}'" | |
} | |
} | |
def getCurrentTarget() { | |
def currentTarget = readFile 'route-target' | |
return currentTarget | |
} | |
def getNewTarget() { | |
def currentTarget = getCurrentTarget() | |
def newTarget = "" | |
if (currentTarget == 'tasks-blue') { | |
newTarget = 'tasks-green' | |
} else if (currentTarget == 'tasks-green') { | |
newTarget = 'tasks-blue' | |
} else { | |
echo "OOPS, wrong target" | |
} | |
return newTarget | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment