Working with Microservices-16: Preparing and Running The Production Jenkins File and Pipeline, Examining the output of the Jenkins Pipeline Using Rancher and our Browser

We continue our Production Pipeline. In this section, we will prepare a Jenkinsfile for the production pipeline. We will use the scripts that we prepared, in Jenkinsfile. Then, we will run the Jenkinsfile in a Jenkins pipeline so that our application will be deployed in the production environment (Amazon EKS cluster). Finally, we will examine the app’s output via Rancher and check whether our application works properly in the browser.

Cumhur Akkaya
12 min readSep 11, 2023

1. Preparing Production Jenkinsfile for Pipeline

Prepare a Jenkinsfile for the microservices app production pipeline with the values below and save it as “jenkinsfile-microservice-app-production” under “jenkins” folder, as shown in Figure-1.

pipeline {
agent any
environment {
PATH=sh(script:"echo $PATH:/usr/local/bin", returnStdout:true).trim()
APP_NAME="petclinic"
APP_REPO_NAME="cmakkaya/microservices-application-production"
AWS_ACCOUNT_ID=sh(script:'export PATH="$PATH:/usr/local/bin" && aws sts get-caller-identity --query Account --output text', returnStdout:true).trim()
AWS_REGION="us-east-1"
ECR_REGISTRY="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
}
stages {
stage('Package Application') {
steps {
echo 'Packaging the app into jars with maven'
sh ". ./jenkins/package-with-maven-container.sh"
}
}
stage('Prepare Tags for Production Docker Images') {
steps {
echo 'Preparing Tags for Production Docker Images'
script {
MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-admin-server/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
env.IMAGE_TAG_ADMIN_SERVER="${ECR_REGISTRY}/${APP_REPO_NAME}:admin-server-v${MVN_VERSION}-b${BUILD_NUMBER}"
MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-api-gateway/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
env.IMAGE_TAG_API_GATEWAY="${ECR_REGISTRY}/${APP_REPO_NAME}:api-gateway-v${MVN_VERSION}-b${BUILD_NUMBER}"
MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-config-server/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
env.IMAGE_TAG_CONFIG_SERVER="${ECR_REGISTRY}/${APP_REPO_NAME}:config-server-v${MVN_VERSION}-b${BUILD_NUMBER}"
MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-customers-service/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
env.IMAGE_TAG_CUSTOMERS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:customers-service-v${MVN_VERSION}-b${BUILD_NUMBER}"
MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-discovery-server/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
env.IMAGE_TAG_DISCOVERY_SERVER="${ECR_REGISTRY}/${APP_REPO_NAME}:discovery-server-v${MVN_VERSION}-b${BUILD_NUMBER}"
MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-hystrix-dashboard/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
env.IMAGE_TAG_HYSTRIX_DASHBOARD="${ECR_REGISTRY}/${APP_REPO_NAME}:hystrix-dashboard-v${MVN_VERSION}-b${BUILD_NUMBER}"
MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-vets-service/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
env.IMAGE_TAG_VETS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:vets-service-v${MVN_VERSION}-b${BUILD_NUMBER}"
MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-visits-service/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
env.IMAGE_TAG_VISITS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:visits-service-v${MVN_VERSION}-b${BUILD_NUMBER}"
env.IMAGE_TAG_GRAFANA_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:grafana-service"
env.IMAGE_TAG_PROMETHEUS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:prometheus-service"
}
}
}
stage('Build App Production Docker Images') {
steps {
echo 'Building App Production Images'
sh ". ./jenkins/build-prod-docker-images-for-ecr.sh"
sh 'docker image ls'
}
}
stage('Push Images to ECR Repo') {
steps {
echo "Pushing ${APP_NAME} App Images to ECR Repo"
sh ". ./jenkins/push-prod-docker-images-to-ecr.sh"
}
}
stage('Deploy App on Petclinic Kubernetes Cluster'){
steps {
echo 'Deploying App on K8s Cluster'
sh ". ./jenkins/deploy_app_on_prod_environment.sh"
}
}
}
post {
always {
echo 'Deleting all local images'
sh 'docker image prune -af'
}
}
}
Figure-1

In Jenkinsfile;

agent any; This value is not important to us as we do not create any Agent node. If we created an Agent node, we would have chosen the Agent node that Jenkinsfile will use from here. (1)

environment; Here we define the environments we will use in Jenkinsfile, the environments that need to be changed are explained below.

The following Jenkinsfile consists of six stages.

Stage 1; Packages “the microservice app” with Maven by using package-with-maven-container.shscript.

Stage 2; Tags production stage’s Docker Images.

Stage 3; Builds production stage’s Docker Image by using build-prod-docker-images-for-ecr.sh script.

Stage 4; Sends the created images to the Amazon ECR repository by using push-prod-docker-images-to-ecr.sh script.

Stage 5; Deploys the microservice app on Amazon EKS Kubernetes cluster with the “deploy_app_on_prod_environment.sh” script by using kubectl and Helm after login Rancher server.

Finally, “Post” deletes all local images so that the server does not run out of capacity in a short time.

Note: For more detailed information about script files and stages, I will write my notes in a separate article at the end of this series; “Working with Microservices-23: Detailed Explanation of The Scripts We Use in Jenkins Files and Pipelines

Attention: Follow the steps below for the values that need to change while preparing the Jenkinsfile;

“APP_REPO_NAME=cmakkaya/microservices-application-production”. You can check your repository name in the Amazon ECR window, as shown in Figure-2.

Figure-2

(Optional) “AWS_REGION= us-east-1”. You must enter the region that you use here.

2. Pushing created files to the remote repo and merging the main branch (GitHub)

When we started the production pipeline, we created the “production” branch and pushed our work in this branch.

Now, commit the change, then push created files (scripts, yaml files, etc) to the remote repo (GitHub). Run the commands below, as shown in Figure 3.

git add .
git commit -m 'added jenkinsfile "jenkinsfile-microservice-app-production" for Production stage'
git push --set-upstream origin production

Figure 3

Merge the “production” branch to the “main” branch to build and deploy the app on “Production environment” with the pipeline.

git checkout main
git merge production
git push origin main

Note: In the Jenkins pipeline, we will use this branch(“main”) that we push. Github-webhook triggers the pipeline every “commits” on the “main” branch.

Figure 4

The best practice is to create a different branch and continue from the new branch in the next stage (2).

3. Creating a GitHub Webhook to auto-trigger the production pipeline

Configure a “github-webhook” to trigger the pipeline for every “commit” on the “main” branch.

Go to the “microservices-with-RDS-MySQL-DB” project page in the GitHub repository and click on “Settings”, as shown in Figure 5. (3)

Figure 5

Then Click on the “Webhooks” on the left-hand menu, and then click on “Add Webhook”, as shown in Figure 6.

Figure 6

If GitHub wants an authentication, you enter your GitHub password and confirm it, as shown in Figure 7.

Figure 7

Copy the Jenkins Server URL from the AWS Management Console > EC2 Dashboard > Instances, paste it into the “Payload URL” field, add “/github-webhook/” at the end of the URL, and click on “Add webhook” button, as shown in Figure 8.

Figure 8

Webhook is ready now, as shown in Figure 9. We will use it in Production Pipeline.

Figure 9

You can also check this article: “Creating a CI/CD Jenkins Pipeline with GitHub Webhook that runs the Production Stage via Amazon ECS- Fargate, and Amazon ECR automatically.

4. Preparing Production Jenkins Pipeline

Create a “Jenkins Production Pipeline” on Jenkins with name of “microservice-app-production” by using the below values, as shown in Figures 10–13. (4)

- job name: microservice-app-production
- job type: pipeline
- Description: The production pipeline deploys the Java-based Springboot web application consisting of 10 microservices to the Amazon EKS cluster with Helm. In the production Stage, Whenever the developers push their codes to the GitHub repository, the Jenkins pipeline will run automatically thanks to the GitHub webhook and automatically update our Java-based application running on the web.
- Discard old builds: Days to keep builds=2, Max of builds to keep=2.
- GitHub project: Project url= https://github.com/cmakkaya/microservices-with-RDS-MySQL-DB
- Source Code Management: Git
Repository URL: https://github.com/[your-github-account]/microservices-with-RDS-MySQL-DB.git
- Branches to build:
Branch Specifier (blank for 'any'): */main
- Build triggers: GitHub hook trigger for GITScm polling
- Pipeline:
Script Path: jenkins/jenkinsfile-microservice-app-production

For preparing a Jenkins pipeline, go to the Jenkins dashboard and click on “New Item” to create a pipeline, then enter an item name, select “Pipeline”, click on the “OK” button, as shown in Figure 10.

Figure 10

Write a description of the pipeline, and make the following setting to delete automatically the builds of the pipeline so that the Jenkins server does not reach its capacity in a short time, as shown in Figure 11.

Figure 11

We paste the address of our GitHub repo here, as shown in Figure 12. So that our GitHub repo link will appear on the Dashboard, as shown in Figure 13.

Figure 12
Figure 13

In the Pipeline section, enter the values below, as shown in Figure 14. As Source Code Management (SCM), we will use our Git repository and “main” branche.

Figure 14

Attention: We check the Jenkinsfile path (“Script Path”) from GitHub, as shown in Figure 15.

Figure 15

When we click on the “Save” button, the following window will open, as shown in Figure 16.

Figure 16

Note-1: “Petclinic production pipeline” should be deployed on permanent production-environment on “petclinic-cluster” Kubernetes cluster under “petclinic-prod-ns” namespace. It was created by using deploy_app_on_prod_environment.sh script in the Jenkinsfile.

Note-2: In the “Credential” section, in order to use a credential (example: GitHub private repo) check the article: “Using a private GitHub repository with a “GitHub Personal Access Token” in the Jenkins pipeline that runs automatically the development stage via Amazon ECR and Docker container.

5. Running Production Jenkins Pipeline

Click on the “Build Now” button, as shown in Figure 17.

Figure 17

Jenkins Pipeline starts working, as shown in Figure 18.

Figure 18

Jenkins Pipeline completed its working, as shown in Figure 19.

Figure 19

By looking at the logs, we can see Jenkins Pipeline’s work and if there are errors, we can see the reasons, as shown in Figures 20–21.

Figure 20
Figure 21

Also, by clicking on the “Console Output”, we can see Jenkins Pipeline’s work, as shown in Figures 22–24.

Figure 22
Figure 23
Figure 24

Files belonging to our application created by the Jenkins user when the Jenkins pipeline runs in the path var/lib/jenkins/workspace, as shown in Figure 25.

Figure 25

The final state of the “values.yaml” file after the pipeline runs and dynamically pulls the values from the system, as shown in Figure 26.

Figure 26

6. Examining the Output of the Jenkins Pipeline Using Rancher and Checking Whether Our Application Works Properly in the Browser

Go to Rancher and click on the “microservice-app-eks” in hamburger menu, as shown in Figure 27.

Figure 27

A page showing the general status of our cluster appears, as shown in Figure 28.

Figure 28

The status of Nodes are as shown in Figure 29.

Figure 29

The status of Ingress is, as shown in Figure 30.

Figure 30

The status of Pods are, as shown in Figure 31.

Figure 31

We checked that our application was running in the browser. We also saw that our certificate was received from “Let’s Encrypt” when we clicked on the “Lock” icon, as shown in Figure 32.

Figure 32

We added a user to our application to check that RDS Database is running and when we query the record, we see that it is registered to the database, as shown in Figures 33–34.

Figure 33
Figure 34

7. Testing The Auto-triggering of Our Pipeline and The Working of The Webhook

We made a change to our source code and saved it, as shown in Figures 35–36.

Figure 35
Figure 36

We sent the changes to our GitHub repository with the push command, as shown in Figure 37.

Figure 37

When we looked at the “microservice-app-production” pipeline in Jenkins, we saw that Pipeline started running automatically, as shown in Figure 38.

Figure 38

Jenkins pipeline completed its work successfully, as shown in Figure 39. We tested successfully the auto-triggering of our pipeline and the working of the webhook. Our application running in the browser has been updated according to new data.

Figure 39

Note: For clean-up, you can see this articleWorking with Microservices-22: Clean up The Production Envirovment (Amazon EKS cluster, Amazon RDS Database, Docker container images in Amazon ECR , Helm Charts in S3 Bucket, The Rancher server, The Jenkins server, The Development server)” In this article, we clean-up the resources we have created so far.

8. As a result

We successfully deployed the Java-based Springboot web application consisting of 10 microservices to the Kubernetes cluster. For this, we prepared Jenkinsfile and Jenkins production pipeline. Then, we examined the output of the Jenkins pipeline using Rancher and checked whether our application works properly in our browser. Finally, we tested the auto-triggering of our pipeline and the working of the webhook by changing our source code in GitHub repository.

We prepare a sample production CI/CD process that can be used in similar projects.

You can find the necessary files in my GitHub repo.

If you liked the article, I would be happy if you click on the Medium Following button to encourage me to write and not miss future articles.

Your clap, follow, or subscribe, they help my articles to reach the broader audience. Thank you in advance for them.

For more info and questions, please contact me on Linkedin or Medium.

9. Next post

In the next post, “Working with Microservices-17: Monitoring and Creating an Alarm with Prometheus and Grafana in the Production Stage” in Figure 40.

Figure 40- In the next post, “Working with Microservices-17: Monitoring and Creating an Alarm with Prometheus and Grafana in the Production Stage”

We will collect and store metrics as time-series data, monitor, and set an alarm for the cluster with Prometheus. We will visualize all the information received and put it in the desired shape and make it easier to follow and read them by using Grafana.

I hope you enjoyed reading this article. You can share this article with friends in your network and help them to upskill.

I frequently share articles about Cloud and DevOps tools and resources, if you follow me on my Medium or LinkedIn account you don’t miss future articles. I wish you growing success in the DevOps and the Cloud way.

Happy Clouding…

10. References

(1) https://www.jenkins.io/doc/book/pipeline/jenkinsfile/

(2) https://docs.github.com/en/get-started/using-git/pushing-commits-to-a-remote-repository

(3) https://docs.github.com/en/webhooks/using-webhooks/creating-webhooks

(4) https://www.jenkins.io/doc/book/pipeline/

--

--

Cumhur Akkaya

✦ DevOps/Cloud Engineer, ✦ Believes in learning by doing, ✦ Dedication To Lifelong Learning, ✦ Tea and Coffee Drinker. ✦ Linkedin: linkedin.com/in/cumhurakkaya