CICD on OpenShift Part Two


Continue with part one, I will show you the details of the CICD scripts and also the Bamboo plan.

Lets start with the CICD scripts, it can be found in my OpenShift-CICD repository on GitHub. The key parts are two OpenShift configuration files: build.yaml and deploy.yaml. The script is to make a copy from the template file and inject the parameters.

#!/bin/bash

# Project name
PROJECT=dilbert

# User inputs
# Build or deploy
ACTION=$1
VERSION=$2 
ENVIRONMENT=$3
TAG=$(oc -n $PROJECT get is/${PROJECT} -o jsonpath={.status.tags[1].tag})

case $ACTION in
	build)
		# Verson number
		# Assume tags[0] is latest
		if [ -z "${VERSION}" ]; then
			echo Previous version is $TAG
			if [ -z "$TAG" ]; then 
				PREVERSION=v0.1
			else
				PREVERSION=$TAG
			fi
			MAJVERSION=$(echo $PREVERSION | cut -d'.' -f1)
			let MINVERSION=$(echo $PREVERSION | cut -d'.' -f2)+1
			VERSION=${MAJVERSION}.${MINVERSION}
		fi
		echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
		echo "You are buliding version" $VERSION
		sed -e "s/%buildversion%/${VERSION}/g" build-template.yaml > build.yaml
		if [[ $(oc -n $PROJECT get bc | grep -c ${PROJECT}) -gt 0 ]]; then
			oc replace -n $PROJECT -f build.yaml
		else
			oc create -n $PROJECT -f build.yaml
		fi
		BUILDNUBER=$(oc -n $PROJECT start-build ${PROJECT} | cut -d'"' -f2)
		echo "The build job is" $BUILDNUBER
		until [ "$BUILDSTATUS" == "Failed" ] || [ "$BUILDSTATUS" == "Complete" ] ; do
			BUILDSTATUS=$(oc -n $PROJECT get build/$BUILDNUBER -o jsonpath={.status.phase})
			echo $BUILDNUBER status is $BUILDSTATUS
			sleep 5
		done
		if [ "$BUILDSTATUS" == "Failed" ]; then echo "Oops, build failed!"; exit 1; fi
		if [ "$BUILDSTATUS" == "Complete" ]; then 
			echo "Congrats! build completed!"; 
			oc -n $PROJECT tag ${PROJECT}:${VERSION} $PROJECT:latest
			exit 0;
			 fi
		;;
	deploy)
		if [ -z ${VERSION} ] || [ -z ${ENVIRONMENT} ]; then
			echo "You need to specify [which version] to deploy to [which environment]!"
			echo "Usage: ./pipeline.sh deploy  "
			exit 1
		fi
		if [ "${VERSION}" == "latest" ]; then VERSION=$TAG; fi
		echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
		echo "You are deploying version "$VERSION "to" $ENVIRONMENT
		sed -e "s/%buildversion%/${VERSION}/g" -e "s/%imageversion%/${VERSION}/g" -e "s/%env%/${ENVIRONMENT}/g" deploy-template.yaml > deploy.yaml
		if [[ $(oc -n $PROJECT get dc | grep -c ${ENVIRONMENT}) -gt 0 ]]; then
			oc replace -n $PROJECT -f deploy.yaml
		else
			oc create -n $PROJECT -f deploy.yaml
		fi
		#oc get dc/${ENVIRONMENT} -w -o jsonpath={.status.availableReplicas}
		;;
	*)
		echo 'Usage:'
		echo 'To build : ./pipeline.sh build [version]'
		echo 'To deploy: ./pipeline.sh deploy  '
		echo 'To CI/CD: ./pipeline.sh build && ./pipeline.sh deploy latest '
		exit 1		
		;;
esac		

Bamboo plan works the same way, the only difference is that the parameters are from Bamboo plan variables. Just is a simple plan with 3 tasks.

Screen Shot 2018-03-08 at 11.47.57 AM.png

First step, checking out the source code from repository.

Second step, ensure the oc command is installed.

#!/bin/bash
tar xvzf lib/oc.tar.gz -C ~/
export PATH=$PATH:~
oc login ${bamboo.os_url} --token=${bamboo.os_password}

The last step is the pipeline script:

#!/bin/bash
export PATH=$PATH:~
cd openshift
# Project name
PROJECT=${bamboo.project}

# User inputs
# Build or deploy
ACTION=$1
VERSION=$2 
ENVIRONMENT=$3
TAG=$(oc -n $PROJECT get is/${PROJECT} -o jsonpath={.status.tags[1].tag})

case $ACTION in
	build)
		# Verson number
		# Assume tags[0] is latest
		if [ -z "${VERSION}" ]; then
			echo Previous version is $TAG
			if [ -z "$TAG" ]; then 
				PREVERSION=v0.1
			else
				PREVERSION=$TAG
			fi
			MAJVERSION=$(echo $PREVERSION | cut -d'.' -f1)
			let MINVERSION=$(echo $PREVERSION | cut -d'.' -f2)+1
			VERSION=${MAJVERSION}.${MINVERSION}
		fi
		echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
		echo "You are buliding version" $VERSION
		sed -e "s/%buildversion%/${VERSION}/g" build-template.yaml > build.yaml
		if [[ $(oc -n $PROJECT get bc | grep -c ${PROJECT}) -gt 0 ]]; then
			oc replace -n $PROJECT -f build.yaml
		else
			oc create -n $PROJECT -f build.yaml
		fi
		BUILDNUBER=$(oc -n $PROJECT start-build ${PROJECT} | cut -d'"' -f2)
		echo "The build job is" $BUILDNUBER
		until [ "$BUILDSTATUS" == "Failed" ] || [ "$BUILDSTATUS" == "Complete" ] ; do
			BUILDSTATUS=$(oc -n $PROJECT get build/$BUILDNUBER -o jsonpath={.status.phase})
			echo $BUILDNUBER status is $BUILDSTATUS
			sleep 5
		done
		if [ "$BUILDSTATUS" == "Failed" ]; then echo "Oops, build failed!"; exit 1; fi
		if [ "$BUILDSTATUS" == "Complete" ]; then 
			echo "Congrats! build completed!"
			echo ${VERSION} > VERSION
			oc -n $PROJECT tag ${PROJECT}:${VERSION} $PROJECT:latest
			exit 0;
			 fi
		;;
	deploy)
		if [ -z ${VERSION} ] || [ -z ${ENVIRONMENT} ]; then
			echo "You need to specify [which version] to deploy to [which environment]!"
			echo "Usage: ./pipeline.sh deploy  "
			exit 1
		fi
		if [ "${VERSION}" == "latest" ]; then VERSION=$TAG; fi
		echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
		echo "You are deploying version "$VERSION "to" $ENVIRONMENT
		sed -e "s/%buildversion%/${VERSION}/g" -e "s/%imageversion%/${VERSION}/g" -e "s/%env%/${ENVIRONMENT}/g" deploy-template.yaml > deploy.yaml
		if [[ $(oc -n $PROJECT get dc | grep -c ${ENVIRONMENT}) -gt 0 ]]; then
			oc replace -n $PROJECT -f deploy.yaml
		else
			oc create -n $PROJECT -f deploy.yaml
		fi
		#oc get dc/${ENVIRONMENT} -w -o jsonpath={.status.availableReplicas}
		;;
	*)
		echo 'Usage:'
		echo 'To build : ./pipeline.sh build [version]'
		echo 'To deploy: ./pipeline.sh deploy  '
		echo 'To CI/CD: ./pipeline.sh build && ./pipeline.sh deploy latest '
		exit 1		
		;;
esac

Add a trigger to the plan to allow automated build when changes are committed.

Screen Shot 2018-03-08 at 11.54.48 AM.png

Also create a associated deployment with two environments: UAT and PROD. We want UAT environment to always use the latest build automatically, but PROD needs a manual deployment only after users are happy with the UAT test.

Screen Shot 2018-03-08 at 11.59.28 AM.png

And add a trigger for the UAT.

Screen Shot 2018-03-08 at 11.59.59 AM.png

For PROD, I can use whichever release that I am happy with to deploy into production,

Screen Shot 2018-03-08 at 12.01.22 PM.png

In summary, the rule of thumb is that you only build image once for each release. This ensures the same binary/ docker image that runs in different environments (dev, uat … prod). And follow the environment promotion path to deploy the binary/ docker image from dev all the way to production.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s