Blue/Green deploy stage

This commit is contained in:
ebracho 2017-09-19 11:10:32 -07:00
parent 6cae399590
commit b5b7a35f88
5 changed files with 253 additions and 168 deletions

195
Jenkinsfile vendored
View file

@ -1,19 +1,182 @@
#!/bin/env groovy
@Library('ldop-shared-library@ad8185bec5a1999d144ec6c8fdadf9a62ab0506e') _
pipeline { pipeline {
agent none agent none
stages {
stage('Build') { environment {
agent { IMAGE = "liatrio/petclinic-tomcat"
docker { }
image 'maven:3.5.0'
args '-e INITIAL_ADMIN_USER -e INITIAL_ADMIN_PASSWORD --network=${LDOP_NETWORK_NAME}' stages {
}
} stage('Build') {
steps { agent {
configFileProvider( docker {
[configFile(fileId: 'nexus', variable: 'MAVEN_SETTINGS')]) { image 'maven:3.5.0'
sh 'mvn -s $MAVEN_SETTINGS clean deploy -DskipTests=true -B' args '-e INITIAL_ADMIN_USER -e INITIAL_ADMIN_PASSWORD --network=${LDOP_NETWORK_NAME}'
} }
} }
} steps {
configFileProvider(
[configFile(fileId: 'nexus', variable: 'MAVEN_SETTINGS')]) {
sh 'mvn -s $MAVEN_SETTINGS clean deploy -DskipTests=true -B'
}
}
} }
stage('Sonar') {
agent {
docker {
image 'sebp/sonar-runner'
args '-e SONAR_ACCOUNT_LOGIN -e SONAR_ACCOUNT_PASSWORD -e SONAR_DB_URL -e SONAR_DB_LOGIN -e SONAR_DB_PASSWORD --network=${LDOP_NETWORK_NAME}'
}
}
steps {
sh '/opt/sonar-runner-2.4/bin/sonar-runner -e -D sonar.login=${SONAR_ACCOUNT_LOGIN} -D sonar.password=${SONAR_ACCOUNT_PASSWORD} -D sonar.jdbc.url=${SONAR_DB_URL} -D sonar.jdbc.username=${SONAR_DB_LOGIN} -D sonar.jdbc.password=${SONAR_DB_PASSWORD}'
}
}
stage('Get Artifact') {
agent {
docker {
image 'maven:3.5.0'
args '-e INITIAL_ADMIN_USER -e INITIAL_ADMIN_PASSWORD --network=${LDOP_NETWORK_NAME}'
}
}
steps {
sh 'mvn clean'
script {
pom = readMavenPom file: 'pom.xml'
getArtifact(pom.groupId, pom.artifactId, pom.version, 'petclinic')
}
}
}
stage('Build container') {
agent any
steps {
script {
if ( env.BRANCH_NAME == 'master' ) {
pom = readMavenPom file: 'pom.xml'
TAG = pom.version
} else {
TAG = env.BRANCH_NAME
}
sh "docker build -t ${env.IMAGE}:${TAG} ."
}
}
}
stage('Run local container') {
agent any
steps {
sh 'docker rm -f petclinic-tomcat-temp || true'
sh "docker run -d --network=${LDOP_NETWORK_NAME} --name petclinic-tomcat-temp ${env.IMAGE}:${TAG}"
}
}
stage('Smoke-Test & OWASP Security Scan') {
agent {
docker {
image 'maven:3.5.0'
args '--network=${LDOP_NETWORK_NAME}'
}
}
steps {
sh "cd regression-suite && mvn clean -B test -DPETCLINIC_URL=http://petclinic-tomcat-temp:8080/petclinic/"
}
}
stage('Stop local container') {
agent any
steps {
sh 'docker rm -f petclinic-tomcat-temp || true'
}
}
stage('Push to dockerhub') {
agent any
steps {
withCredentials([usernamePassword(credentialsId: 'dockerhub', passwordVariable: 'dockerPassword', usernameVariable: 'dockerUsername')]){
script {
sh "docker login -u ${env.dockerUsername} -p ${env.dockerPassword}"
sh "docker push ${env.IMAGE}:${TAG}"
}
}
}
}
stage('Deploy to dev') {
agent any
steps {
script {
deployToEnvironment("ec2-user", "dev.petclinic.liatr.io", "petclinic-deploy-key", env.IMAGE, TAG, "spring-petclinic", "dev.petclinic.liatr.io")
}
}
}
stage('Smoke test dev') {
agent {
docker {
image 'maven:3.5.0'
args '--network=${LDOP_NETWORK_NAME}'
}
}
steps {
sh "cd regression-suite && mvn clean -B test -DPETCLINIC_URL=https://dev.petclinic.liatr.io/petclinic"
echo "Should be accessible at https://dev.petclinic.liatr.io/petclinic"
}
}
stage('Deploy to qa') {
when {
branch 'master'
}
agent any
steps {
deployToEnvironment("ec2-user", "qa.petclinic.liatr.io", "petclinic-deploy-key", env.IMAGE, TAG, "spring-petclinic", "qa.petclinic.liatr.io")
}
}
stage('Smoke test qa') {
when {
branch 'master'
}
agent {
docker {
image 'maven:3.5.0'
args '--network=${LDOP_NETWORK_NAME}'
}
}
steps {
sh "cd regression-suite && mvn clean -B test -DPETCLINIC_URL=https://qa.petclinic.liatr.io/petclinic"
echo "Should be accessible at https://qa.petclinic.liatr.io/petclinic"
input 'Deploy to Prod?'
}
}
stage('Blue/Green deploy to prod') {
/*
when {
branch 'master'
}
*/
agent {
dockerfile {
filename "blue-green/Dockerfile"
}
}
steps {
withCredentials([
usernamePassword(credentialsId: 'aws', usernameVariable: 'AWS_ACCESS_KEY_ID', passwordVariable: 'AWS_SECRET_ACCESS_KEY'),
file(credentialsId: 'petclinic-deploy-key', variable: 'DEPLOY_KEY_PATH')
]) {
script {
sh "TAG=${TAG} blue-green/blue-green-deploy"
}
}
}
}
}
} }

7
blue-green/Dockerfile Normal file
View file

@ -0,0 +1,7 @@
FROM maven:3.5.0
RUN apt-get update -y && apt-get install -y awscli jq
# Jenkins workspace runs with UID 1000
RUN useradd -ms /bin/bash -u 1000 jenkins
USER jenkins

66
blue-green/blue-green-deploy Executable file
View file

@ -0,0 +1,66 @@
#!/bin/bash -xe
# This script executes a blue/green deployment on the petclinic production infrastructure.
#
# Production infrastructure consists of:
# - An application load balancer (prod-petclinic)
# - Two target groups (proda-petclinic, prodb-petclinic)
# - A single t2.micro ec2 instance in each target group (proda.petclinic.liatr.io, prodb.petclinic.liatr.io)
#
# One of the two target groups should be attached to the ALB at any given time via a Listener
#
# To perform a blue/green deployment, we:
# - Figure out which target group is detached
# - Deploy the application to each instance in the detached target group (only 1 instance in this case)
# - Run smoke tests on the newly deployed applications
# - Delete the current attached listener
# - Attach a new listener that forwards to the target group we deployed to.
#
# Expected environment variables:
# - DEPLOY_KEY_PATH Private key used to shell deploy to petclinic prod instances
# - AWS_ACCESS_ID_ID
# - AWS_SECRET_ACCESS_KEY For modifying load balancer resources
# - IMAGE Dockerhub repo to deploy from
# - TAG Version of image to deploy
#
export AWS_DEFAULT_REGION='us-west-2'
deploy() {
FQDN="$1"
ssh -i ${DEPLOY_KEY_PATH} -o StrictHostKeyChecking=no ec2-user@${FQDN} "docker rm -f petclinic || true"
ssh -i ${DEPLOY_KEY_PATH} -o StrictHostKeyChecking=no ec2-user@${FQDN} "docker run -d -p 80:8080 --name petclinic ${IMAGE}:${TAG}"
}
smoke_test() {
FQDN="$1"
cd ./regression-suite && mvn clean -B test -DPETCLINIC_URL="${FQDN}" && cd -
}
LOAD_BALANCER_ARN=$(aws elbv2 describe-load-balancers --names prod-petclinic | jq -r '.LoadBalancers|.[0]|.LoadBalancerArn')
ATTACHED_LISTENER_ARN=$(aws elbv2 describe-listeners --load-balancer-arn "${LOAD_BALANCER_ARN}" | jq -r '.Listeners|.[0]|.ListenerArn')
ATTACHED_LISTENER_TARGET_GROUP_ARN=$(aws elbv2 describe-listeners --load-balancer-arn "${LOAD_BALANCER_ARN}" | jq -r '.Listeners|.[0]|.DefaultActions|.[0]|.TargetGroupArn')
PRODA_TARGET_GROUP_ARN=$(aws elbv2 describe-target-groups --names proda-petclinic | jq -r '.TargetGroups|.[0]|.TargetGroupArn')
PRODB_TARGET_GROUP_ARN=$(aws elbv2 describe-target-groups --names prodb-petclinic | jq -r '.TargetGroups|.[0]|.TargetGroupArn')
if [[ "${ATTACHED_LISTENER_TARGET_GROUP_ARN}" == "${PRODA_TARGET_GROUP_ARN}" ]]; then
NEW_TARGET_GROUP_ARN=${PRODB_TARGET_GROUP_ARN}
deploy "prodb.petclinic.liatr.io"
smoke_test "http://prodb.petclinic.liatr.io/petclinic"
else
NEW_TARGET_GROUP_ARN=${PRODA_TARGET_GROUP_ARN}
deploy "proda.petclinic.liatr.io"
smoke_test "http://proda.petclinic.liatr.io/petclinic"
fi
if [[ "${ATTACHED_LISTENER_ARN}" != "null" ]]; then
echo "Deleting previous listener: ${ATTACHED_LISTENER_ARN}"
aws elbv2 delete-listener --listener-arn "${ATTACHED_LISTENER_ARN}"
fi
echo "Attaching listener with target group: ${NEW_TARGET_GROUP_ARN}"
aws elbv2 create-listener \
--load-balancer-arn "${LOAD_BALANCER_ARN}" \
--protocol "HTTP" \
--port "80" \
--default-actions "Type=forward,TargetGroupArn=${NEW_TARGET_GROUP_ARN}"

View file

@ -1,151 +0,0 @@
#!/bin/env groovy
pipeline {
agent none
environment {
IMAGE = "liatrio/petclinic-tomcat"
}
stages {
stage('Build') {
agent {
docker {
image 'maven:3.5.0'
args '-e INITIAL_ADMIN_USER -e INITIAL_ADMIN_PASSWORD --network=${LDOP_NETWORK_NAME}'
}
}
steps {
configFileProvider(
[configFile(fileId: 'nexus', variable: 'MAVEN_SETTINGS')]) {
sh 'mvn -s $MAVEN_SETTINGS clean deploy -DskipTests=true -B'
}
}
}
stage('Sonar') {
agent {
docker {
image 'sebp/sonar-runner'
args '-e SONAR_ACCOUNT_LOGIN -e SONAR_ACCOUNT_PASSWORD -e SONAR_DB_URL -e SONAR_DB_LOGIN -e SONAR_DB_PASSWORD --network=${LDOP_NETWORK_NAME}'
}
}
steps {
sh '/opt/sonar-runner-2.4/bin/sonar-runner -e -D sonar.login=${SONAR_ACCOUNT_LOGIN} -D sonar.password=${SONAR_ACCOUNT_PASSWORD} -D sonar.jdbc.url=${SONAR_DB_URL} -D sonar.jdbc.username=${SONAR_DB_LOGIN} -D sonar.jdbc.password=${SONAR_DB_PASSWORD}'
}
}
stage('Get Artifact') {
agent {
docker {
image 'maven:3.5.0'
args '-e INITIAL_ADMIN_USER -e INITIAL_ADMIN_PASSWORD --network=${LDOP_NETWORK_NAME}'
}
}
steps {
sh 'mvn clean'
script {
pom = readMavenPom file: 'pom.xml'
getArtifact(pom.groupId, pom.artifactId, pom.version)
}
}
}
stage('Build container') {
agent any
steps {
script {
sh "docker build -t liatrio/petclinic-tomcat:${env.BRANCH_NAME} ."
if ( env.BRANCH_NAME == 'master' ) {
pom = readMavenPom file: 'pom.xml'
containerVersion = pom.version
sh "docker build -t liatrio/petclinic-tomcat:${containerVersion} ."
}
}
}
}
stage('Run local container') {
agent any
steps {
sh 'docker rm -f petclinic-tomcat-temp || true'
sh "docker run -d --network=${LDOP_NETWORK_NAME} --name petclinic-tomcat-temp liatrio/petclinic-tomcat:${env.BRANCH_NAME}"
}
}
stage('Smoke-Test & OWASP Security Scan') {
agent {
docker {
image 'maven:3.5.0'
args '--network=${LDOP_NETWORK_NAME}'
}
}
steps {
sh "cd regression-suite && mvn clean -B test -DPETCLINIC_URL=http://petclinic-tomcat-temp:8080/petclinic/"
}
}
stage('Stop local container') {
agent any
steps {
sh 'docker rm -f petclinic-tomcat-temp || true'
}
}
stage('Push to dockerhub') {
agent any
steps {
withCredentials([usernamePassword(credentialsId: 'dockerhub', passwordVariable: 'dockerPassword', usernameVariable: 'dockerUsername')]) {
script {
sh "docker login -u ${env.dockerUsername} -p ${env.dockerPassword}"
if ( env.BRANCH_NAME == 'master' ) {
sh "docker push liatrio/petclinic-tomcat:${containerVersion}"
}
else {
sh "docker push liatrio/petclinic-tomcat:${env.BRANCH_NAME}"
}
}
}
}
}
stage('Deploy to dev') {
agent any
steps {
script {
if ( env.BRANCH_NAME == 'master' ) {
deployToEnvironment("ec2-user", "dev.petclinic.liatr.io", "petclinic-deploy-key", "${env.IMAGE}", "${containerVersion}", "spring-petclinic", "dev.petclinic.liatr.io")
}
else{
deployToEnvironment("ec2-user", "dev.petclinic.liatr.io", "petclinic-deploy-key", "${env.IMAGE}", "${env.BRANCH_NAME}", "spring-petclinic", "dev.petclinic.liatr.io")
}
}
}
}
stage('Smoke test dev') {
agent {
docker {
image 'maven:3.5.0'
args '--network=${LDOP_NETWORK_NAME}'
}
}
steps {
sh "cd regression-suite && mvn clean -B test -DPETCLINIC_URL=https://dev.petclinic.liatr.io/petclinic"
echo "Should be accessible at https://dev.petclinic.liatr.io/petclinic"
}
}
stage('Deploy to qa') {
when {
branch 'master'
}
agent any
steps {
deployToEnvironment("ec2-user", "qa.petclinic.liatr.io", "petclinic-deploy-key", "${env.IMAGE}", "${containerVersion}", "spring-petclinic", "qa.petclinic.liatr.io")
}
}
stage('Smoke test qa') {
when {
branch 'master'
}
agent {
docker {
image 'maven:3.5.0'
args '--network=${LDOP_NETWORK_NAME}'
}
}
steps {
sh "cd regression-suite && mvn clean -B test -DPETCLINIC_URL=https://qa.petclinic.liatr.io/petclinic"
echo "Should be accessible at https://qa.petclinic.liatr.io/petclinic"
}
}
}
}

View file

@ -12,7 +12,7 @@ input[type="text"] {
} }
.navbar .nav > li > a { .navbar .nav > li > a {
color: #000000; color: #000000
} }
.form-horizontal .control-label { .form-horizontal .control-label {