This deployment was designed and implemented to demonstrate the use of infrastructure automation to streamline the deployment of a CI/CD pipeline facilitating the deployment of a banking application.
AWS cloud infrastructure is deployed using Terraform, setting up a Jenkins CI/CD server and a Web application server running Gunicorn and Python code.
The following files are needed to run this deployment:
app.pyThe main python application filedatabase.pyPython file to create application databaseload_data.pyPython file to load data into into the databasetest_app.pyTest functions used to test application functionalityrequirements.txtRequired packages for python applicationmain.tfTerraform file to deploy AWS infrastructurejenkins_deploy.shBash script to install and run Jenkinspkill.shBash script to terminate Gunicorn processsetup.shBash script to setup and run Gunicorn and the Python applicationsetup2.shBash script to setup and run Gunicorn and the Python applicationJenkinsfilev1Configuration file version 1 used by Jenkins to run a pipelineJenkinsfilev2Configuration file version 2 used by Jenkins to run a pipelineREADME.mdREADME documentationstatic/Folder housing CSS filestemplates/Folder housing HTML templatesimages/Folder housing deployment artifacts
-
Development of the infrastructure using Terraform. The main.tf file houses the code to deploy the AWS infrastructure. The infrastructure includes a VPC, route table, two subnets (public) in two availability zones, two route table/subnet associations, security group, and two EC2 instances (jenkins & application servers). Run this command the deploy the infrastructure:
Terraform initTerraform planTerraform apply -
The Jenkins server needs to be set up with some additional configuration. First, verify that the Jenkins application is accessible at the public IP address outputted after applying the terraform configuration.
http://<jenkins-server-public-ip>Retrieve initial Jenkins password
sudo cat /var/lib/jenkins/secrets/initialAdminPasswordNow, connect to the Jenkins server and run the following commands:
sudo add-apt-repository -y ppa:deadsnakes/ppasudo apt install -y software-properties-common python3.7 python3.7-venvDD_API_KEY=*******************************************DD_SITE="us5.datadoghq.com" > DD_APM_INSTRUMENTATION_ENABLED=hostbash -c "$(curl -L https://s3.amazonaws.com/dd-agent/scripts/install_script_agent7.sh)"We need to set up an ssh connection to the application server to allow Jenkins Deploy phase of the pipeline to deploy the application code. The ssh connection needs to be configured under the jenkins user account. Start by configuring the jenkins account login:
sudo passwd jenkinssudo su - jenkins -s /bin/bashNext, setup the ssh connection using the ssh-keygen utility:
ssh-keygen>cat .ssh/id_rsa.pubCopy the contents of the public key to the .ssh/authorized_keys file on the application server. Test ssh connection to verify configuration. Upon successful testing, exit the jenkins user account using the
exitcommand. -
The application server needs to be configured with additional packages. Login into the application server and run the following commands:
sudo add-apt-repository -y ppa:deadsnakes/ppasudo apt install -y software-properties-common python3.7 python3.7-venvDD_API_KEY=*******************************************DD_SITE="us5.datadoghq.com" > DD_APM_INSTRUMENTATION_ENABLED=hostbash -c "$(curl -L https://s3.amazonaws.com/dd-agent/scripts/install_script_agent7.sh)" -
Setup Jenkins CI/CD pipeline in the Jenkins application.
- Login: username | password
- From Dashboard, select a
new item>Create Name>Mulit-branch Pipelineoption - Set Branch sources:
Credentials: How to setup Github Access Token
Repository HTTPS URL:
<Github Repo URL>Build Configuration > Mode > Script Path: Jenkinsfilev1 - Apply and Save
-
In Github, configure the Jenkinsfilev1 to have the Jenkins server connect to the application server. The deploy stage is configured with the following commands using git locally:
git branch jenkins_v1_configgit checkout jenkins_v1_configAdd to Jenkinsfile: ssh ubuntu@10.0.2.217 "curl -O https://raw.githubusercontent.com/kaedmond24/python_banking_app_deployment_5/main/setup.sh && chmod 744 setup.sh && ./setup.sh"git add Jenkinsfilev1git commit -m “commit message”git checkout maingit merge jenkins_v1_configgit push -u origin main -
In Jenkins, run pipeline build to deploy the application. If pipeline run completes successfully, the python application will be available at
http://<application_server_public_ip>:8000. -
In Github, configure the Jenkinsfilev2 to run the Jenkins pipeline with some additional commands. Configure the file with the following commands using git locally:
git branch jenkins_v2_configgit checkout jenkins_v2_configAdd to Jenkinsfile: ssh ubuntu@10.0.2.217 "curl -O https://raw.githubusercontent.com/kaedmond24/python_banking_app_deployment_5/main/pkill.sh && chmod 744 pkill.sh && ./pkill.sh"Add to Jenkinsfile: ssh ubuntu@10.0.2.217 "curl -O https://raw.githubusercontent.com/kaedmond24/python_banking_app_deployment_5/main/setup2.sh && chmod 744 setup2.sh && ./setup2.sh"git add Jenkinsfilev2git commit -m “commit message”git checkout maingit merge jenkins_v2_config -
In Jenkins, rerun the pipeline build to redeploy the application. If pipeline run completes successfully, the python application will be available at
http://<application_server_public_ip>:8000.
CI/CD Pipeline Architecture Link
During my first iterations of running the deployment I noticed that the jenkins_deploy.sh script file, configured in the Terraform main.tf file under aws_instance user data resource, was not being applied to the jenkins server launch configuration. After reading through the AWS documentation, I discovered that the commands executed in the user data field are run as the root user. As a result, the use of sudo is unnecessary in the script which I was using in the jenkins_deploy.sh file. Once removed, the commands within the script were able to be properly applied.
-
How did you decide to run Jenkinsfilev2?
- In order to run Jenkinsfilev2 I reconfigured the pipeline build configuration’s script path to use the specified filename. A pipeline build was run once the change was made to apply the new instructions.
- In order to run Jenkinsfilev2 I reconfigured the pipeline build configuration’s script path to use the specified filename. A pipeline build was run once the change was made to apply the new instructions.
-
Should you place both instances in the public subnet? Or should you place them in a private subnet? Explain why?
- Ideally, the web application should be in the public subnet since it is running an internet facing service. If the web service and application were decoupled and running on different servers, then the application server could be moved to the private subnet. The Jenkins server could be placed in the private subnet. With Jenkins being the host that controls configuration and deployment placement in the private subnet would add an additional layer of security. This would also prompt for specific configuration to be put in place for access to the Jenkins server.
- Ideally, the web application should be in the public subnet since it is running an internet facing service. If the web service and application were decoupled and running on different servers, then the application server could be moved to the private subnet. The Jenkins server could be placed in the private subnet. With Jenkins being the host that controls configuration and deployment placement in the private subnet would add an additional layer of security. This would also prompt for specific configuration to be put in place for access to the Jenkins server.