Sample Jenkins Pipeline for a Flask Python Application
Application will show how we can use Jenkins to deploy/test a flask application running on openshift, the Application being used is testFlask
Environment variables used in Commands have samples in the sample_env file.
So this example assumes a pipeline scenario where there is a running production application represented by our Production Project 'NAMESPACE_PROD' and at build time we deploy the same exact infrastructure in our devlopment project 'NAMESPACE_DEV' and test, when all satisfied we promote our dev image to production which is automatically deployed based on a trigger on the imagestream.
- OCP Version >= 4.11
-
Source Environment Variables
eval "$(curl https://raw.githubusercontent.com/MoOyeg/testFlask/master/sample_env)"
-
Create a Jenkins namespace
oc new-project $JENKINS_NAMESPACE
-
Create Jenkins either with storage or without
-
With Storage
oc process -f ./jenkinsdeploytemplates/jenkins-persistent-deployment.yaml | oc apply -f - -n $JENKINS_NAMESPACE
-
Without Storage
oc process -f ./jenkinsdeploytemplates/jenkins-ephemeral-deployment.yaml | oc apply -f - -n $JENKINS_NAMESPACE
-
-
We used Openshift Oauth, so confirm you can login to Jenkins with the credentials you used to log into openshift
-
To get the route for the Jenkins login url
oc get route jenkins -n $JENKINS_NAMESPACE -o jsonpath='{ .spec.host }'
-
Open the URL in a browser and login
-
Create prod and test projects for your pipeline and add permissions for the jenkins Service Account to be able to build on thos projects
-
Create Projects
oc new-project $NAMESPACE_DEV
oc new-project $NAMESPACE_PROD
-
Add Permissions for Jenkins service account to Projects
oc policy add-role-to-user edit system:serviceaccount:$JENKINS_NAMESPACE:jenkins -n $NAMESPACE_DEV oc policy add-role-to-user edit system:serviceaccount:$JENKINS_NAMESPACE:jenkins -n $NAMESPACE_PROD
-
Add Permissions for Default service account in jenkins namespace to Projects
oc policy add-role-to-user edit system:serviceaccount:$JENKINS_NAMESPACE:default -n $NAMESPACE_DEV oc policy add-role-to-user edit system:serviceaccount:$JENKINS_NAMESPACE:default -n $NAMESPACE_PROD
-
Run Installation Steps for Application - You can skip this step, pipeline will still run but wont show how to replace promoted application.
-
Create Jenkins Slave for Python
The Jenkins slave will be used to run the jenkins pipeline, while not necessary to always create your own slave as Openshift comes out of the box with some, I am using this example to show you can build yours and if you have dependencies to test or build your application you can add them into your image.I am using the Dockerfile above to build my image, because the image uses an image in registry.redhat.io remember to create a service account, create a service account secret and link that secret to your builder service account in Jenkins, please see https://access.redhat.com/documentation/en-us/openshift_container_platform/3.11/html/configuring_clusters/install-config-configuring-red-hat-registry
Also you might not be able to build this image if your cluster is not entitled, please do this at cloud.redhat.com. If you have redhat subscriptions but have not entitled your cluster you can use this process to pass your entitlement into the BuildConfig, see https://docs.openshift.com/container-platform/4.4/builds/running-entitled-builds.html
To build a jenkins image without a subscription please read https://github.com/openshift/jenkins.-
Pass DockerFile Value into Variable(Openshift Subscription Required)
If you have access to RedHat catalog
export BASE_IMAGE=registry.redhat.io/openshift4/ose-jenkins-agent-base:v4.10.0
If you do not have access you can try this option
export BASE_IMAGE=image-registry.openshift-image-registry.svc:5000/openshift/jenkins-agent-base:latest
export PYTHON_DOCKERFILE=$(curl https://raw.githubusercontent.com/MoOyeg/testFlask-Jenkins/master/Dockerfile | envsubst )
-
Build Slave Image in Jenkins Project
oc new-build --strategy=docker -D="$PYTHON_DOCKERFILE" --name=python-jenkins -n $JENKINS_NAMESPACE
-
-
Create Our BuildConfig with our buildstrategy as Pipeline
- We can create our BuildConfig below
echo """ apiVersion: build.openshift.io/v1 kind: BuildConfig metadata: name: "$APP_NAME-pipeline" namespace: $JENKINS_NAMESPACE spec: source: git: ref: master uri: 'https://github.com/MoOyeg/testFlask-Jenkins.git' type: Git strategy: type: "JenkinsPipeline" jenkinsPipelineStrategy: jenkinsfilePath: Jenkinsfile """ | oc create -f -
-
Pass our variables to our pipeline, they will show up as parameters in jenkins**
-
Set environment variables on BuildConfig
oc set env bc/$APP_NAME-pipeline \ --env=JENKINS_NAMESPACE=$JENKINS_NAMESPACE \ --env=REPO="https://github.com/MoOyeg/testFlask.git" \ --env=DEV_PROJECT=$NAMESPACE_DEV --env=APP_NAME=$APP_NAME \ --env=MYSQL_USER=$MYSQL_USER --env=MYSQL_PASSWORD=$MYSQL_PASSWORD \ --env=APP_CONFIG=$APP_CONFIG --env=APP_MODULE=$APP_MODULE \ --env=MYSQL_HOST=$MYSQL_HOST --env=MYSQL_DATABASE=$MYSQL_DATABASE --env=PROD_PROJECT=$NAMESPACE_PROD -n $JENKINS_NAMESPACE
-
-
Start build in Jenkins
-
We can start build using
oc start-build $APP_NAME-pipeline -n $JENKINS_NAMESPACE
-
-
Log into Jenkins to follow the build, you can use the route provided earlier
-
Build has approval stage to simulate approval, we need to accept that to move forward
-
We can confirm that prod version got updated with new application image
-
This pipeline can also be triggered with a a code change via a webhook
-
We can add a webhook by
oc set triggers bc/$APP_NAME-pipeline --from-github -n $JENKINS_NAMESPACE
-
PodTemplatesprovide a way to define the Pod Instance to run that will run the build process.Example here requires the use of a Storage Class that supports dynamic provisioning.
This pipeline shows an example of how to provision a dynamic volume and share it between the workspace and a pod within the pipline steps. This Pipeline requires that you provide elevated privileged to the Jenkins serviceaccount to allow dynamic provisioning of the pvc.
For this Example RWX is required for storage class -
Export your StorageClass Values, see example below:
export SC_NAME=sc-efs export PV_SIZE=300Mi export ACCESS_MODE=ReadWriteMany
-
Create PodTemplates to use your above storage values
envsubst '$SC_NAME $PV_SIZE $ACCESS_MODE' < ./podtemplates/podtemplate-dynamic-volume-rwx.yaml | oc create -n $JENKINS_NAMESPACE -f -
envsubst '$SC_NAME $PV_SIZE $ACCESS_MODE' < ./podtemplates/podtemplate-python-inherit-dynamic-volume.yaml | oc create -n $JENKINS_NAMESPACE -f -
-
This example shares workspace volume with application builds, Since the PVC can only exist in one namespace we will build in JENKINS_NAMESPACE. Let's add our application secret
oc create secret generic my-secret --from-literal=MYSQL_USER=$MYSQL_USER --from-literal=MYSQL_PASSWORD=$MYSQL_PASSWORD -n $JENKINS_NAMESPACE
-
Depending on how your cluster is configured you might need to apply RBAC permissions to allow Jenkins Agent use volumes.
oc apply -k ./rbac
-
You can manually create the pipeline object in Jenkins. Use the Jenkinsfile-with-volume(preferred) OR you can also use a Buildconfig.
echo """ apiVersion: build.openshift.io/v1 kind: BuildConfig metadata: name: "$APP_NAME-pipeline-volume" namespace: $JENKINS_NAMESPACE spec: source: git: ref: master uri: 'https://github.com/MoOyeg/testFlask-Jenkins.git' type: Git strategy: type: "JenkinsPipeline" jenkinsPipelineStrategy: jenkinsfilePath: Jenkinsfile-with-volume """ | oc create -f -
oc set env bc/$APP_NAME-pipeline-volume \ --env=JENKINS_NAMESPACE=$JENKINS_NAMESPACE \ --env=REPO="https://github.com/MoOyeg/testFlask.git" \ --env=DEV_PROJECT=$NAMESPACE_DEV --env=APP_NAME=$APP_NAME \ --env=APP_CONFIG=$APP_CONFIG --env=APP_MODULE=$APP_MODULE \ --env=MYSQL_USER=$MYSQL_USER --env=MYSQL_PASSWORD=$MYSQL_PASSWORD \ --env=MYSQL_HOST=$MYSQL_HOST --env=MYSQL_DATABASE=$MYSQL_DATABASE --env=PROD_PROJECT=$NAMESPACE_PROD -n $JENKINS_NAMESPACE