├── LICENSE ├── README.md ├── appspec.yml ├── buildspec.yml ├── requirements.txt ├── scripts ├── mkdir.sh ├── start_flask.sh ├── stop_flask.py ├── stop_flask.sh └── stop_flask1.sh ├── templates ├── layout.html └── test.html ├── test_app.py └── web.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 AWS Devops 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS-Jenkins-Pipeline 2 | 3 | ## Setting up a CI/CD pipeline by integrating Jenkins with AWS CodeBuild and AWS CodeDeploy 4 | 5 | 6 | 7 | Jenkins open-source automation server is used to deploy AWS CodeBuild artifacts with AWS CodeDeploy, creating a functioning CI/CD pipeline. 8 | When properly implemented, the CI/CD pipeline is triggered by code changes pushed to your GitHub repo, automatically fed into CodeBuild, then the output is deployed on CodeDeploy. 9 | 10 | 11 | The functioning pipeline creates a fully managed build service that compiles your source code. It then produces code artifacts that can be used by CodeDeploy to deploy to your production environment automatically. 12 | 13 | 14 |  15 | 16 | 17 | 18 | ### Walkthrough 19 | 20 | Creating resources to build the infrastructure, including the Jenkins server, CodeBuild project, and CodeDeploy application. 21 | 22 | Accessing and unlocking the Jenkins server. 23 | 24 | Creating a project and configuring the CodeDeploy Jenkins plugin. 25 | 26 | Testing the whole CI/CD pipeline. 27 | 28 | ### Create the resources 29 | how to launch an AWS CloudFormation template, a tool that creates the following resources: 30 | 31 | Amazon S3 bucket—Stores the GitHub repository files and the CodeBuild artifact application file that CodeDeploy uses. 32 | IAM S3 bucket policy—Allows the Jenkins server access to the S3 bucket. 33 | JenkinsRole—An IAM role and instance profile for the Amazon EC2 instance for use as a Jenkins server. This role allows Jenkins on the EC2 instance to access the S3 bucket to write files and access to create CodeDeploy deployments. 34 | CodeDeploy application and CodeDeploy deployment group. 35 | CodeDeploy service role—An IAM role to enable CodeDeploy to read the tags applied to the instances or the EC2 Auto Scaling group names associated with the instances. 36 | CodeDeployRole—An IAM role and instance profile for the EC2 instances of CodeDeploy. This role has permissions to write files to the S3 bucket created by this template and to create deployments in CodeDeploy. 37 | CodeBuildRole—An IAM role to be used by CodeBuild to access the S3 bucket and create the build projects. 38 | Jenkins server—An EC2 instance running Jenkins. 39 | CodeBuild project—This is configured with the S3 bucket and S3 artifact. 40 | Auto Scaling group—Contains EC2 instances running Apache and the CodeDeploy agent fronted by an Elastic Load Balancer. 41 | Auto Scaling launch configurations—For use by the Auto Scaling group. 42 | Security groups—For the Jenkins server, the load balancer, and the CodeDeploy EC2 instance 43 | 44 |  45 | 46 |  47 | 48 | 49 | ### Access and unlock your Jenkins server 50 | 51 | Copy the JenkinsServerDNSName value from the Outputs tab of the CloudFormation stack, and paste it into your browser. 52 | 53 | To unlock the Jenkins server, SSH to the server using the IP address and key pair, following the instructions from Unlocking Jenkins. 54 | 55 | Use the root user to Cat the log file (/var/log/jenkins/jenkins.log) and copy the automatically generated alphanumeric password (between the two sets of asterisks). Then, use the password to unlock your Jenkins server, as shown in the following screenshots. 56 | 57 |  58 | 59 |  60 | 61 |  62 | 63 |  64 | 65 | 66 | 67 | ### Create a project and configure the CodeDeploy Jenkins plugin 68 | 69 |  70 |  71 |  72 |  73 |  74 |  75 |  76 |  77 |  78 |  79 |  80 |  81 |  82 |  83 |  84 |  85 |  86 | 87 | 88 | ### Testing the whole CI/CD pipeline 89 | 90 | To test the whole solution, put an application on your GitHub repository. 91 | 92 | The following screenshot shows an application tree containing the application source files, including text and binary files, executables, and packages: 93 | 94 |  95 | 96 | In this example, the application files are the templates directory, test_app.py file, and web.py file. 97 | 98 | The appspec.yml file is the main application specification file telling CodeDeploy how to deploy your application. Jenkins uses the AppSpec file to manage each deployment as a series of lifecycle event “hooks”, as defined in the file. For information about how to create a well-formed AppSpec file, see AWS CodeDeploy AppSpec File Reference. 99 | 100 | The buildspec.yml file is a collection of build commands and related settings, in YAML format, that CodeBuild uses to run a build. You can include a build spec as part of the source code, or you can define a build spec when you create a build project. For more information, see How AWS CodeBuild Works. 101 | 102 | The scripts folder contains the scripts that you would like to run during the CodeDeploy LifecycleHooks execution with respect to your application requirements. For more information, see Plan a Revision for AWS CodeDeploy. 103 | 104 | To test this solution, perform the following steps: 105 | 106 | Unzip the application files and send them to your GitHub repository, run the following git commands from the path where you placed your sample application: 107 | 108 | $ git add -A 109 | 110 | $ git commit -m 'Your first application' 111 | 112 | $ git push 113 | On the Jenkins server dashboard, wait for two minutes until the previously set project trigger starts working. After the trigger starts working, you should see a new build taking place. 114 | 115 |  116 | 117 | In the Jenkins server Console Output page, check the build events and review the steps performed by each Jenkins plugin. You can also review the CodeDeploy deployment in detail, as shown in the following screenshot: 118 | 119 |  120 | 121 | On completion, Jenkins should report that you have successfully deployed a web application. You can also use your ELBDNSName value to confirm that the deployed application is running successfully. 122 | 123 |  124 | -------------------------------------------------------------------------------- /appspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.0 2 | 3 | os: linux 4 | files: 5 | - source: / 6 | destination: /web/ 7 | hooks: 8 | AfterInstall: 9 | - location: scripts/mkdir.sh 10 | timeout: 300 11 | runas: root 12 | ApplicationStart: 13 | - location: scripts/start_flask.sh 14 | timeout: 300 15 | runas: root 16 | ApplicationStop: 17 | - location: scripts/stop_flask1.sh 18 | timeout: 300 19 | runas: root 20 | -------------------------------------------------------------------------------- /buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | phases: 3 | install: 4 | commands: 5 | - python -m pip install Flask 6 | build: 7 | commands: 8 | - echo Build started on `date` 9 | - echo Compiling the Python code... 10 | - python test_app.py 11 | post_build: 12 | commands: 13 | - echo Build completed on `date` 14 | artifacts: 15 | files: 16 | - web.py 17 | - appspec.yml 18 | - templates/layout.html 19 | - templates/test.html 20 | - scripts/mkdir.sh 21 | - scripts/start_flask.sh 22 | - scripts/stop_flask1.sh 23 | - scripts/stop_flask.py 24 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask 2 | -------------------------------------------------------------------------------- /scripts/mkdir.sh: -------------------------------------------------------------------------------- 1 | mkdir -p /web 2 | curl -O https://bootstrap.pypa.io/get-pip.py 3 | python get-pip.py --user 4 | python -m pip install Flask 5 | #sdssdsds 6 | 7 | -------------------------------------------------------------------------------- /scripts/start_flask.sh: -------------------------------------------------------------------------------- 1 | python /web/web.py > /dev/null 2>&1 & 2 | -------------------------------------------------------------------------------- /scripts/stop_flask.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | requests.post("http://127.0.0.1/shutdown") -------------------------------------------------------------------------------- /scripts/stop_flask.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import requests 3 | 4 | requests.post("http://127.0.0.1/shutdown") 5 | 6 | 7 | -------------------------------------------------------------------------------- /scripts/stop_flask1.sh: -------------------------------------------------------------------------------- 1 | python /web/scripts/stop_flask.py -------------------------------------------------------------------------------- /templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |{% endblock %}
-------------------------------------------------------------------------------- /test_app.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | 4 | from web import myapp 5 | import unittest 6 | 7 | # python -m unittest test_app 8 | 9 | 10 | class TestMyApp(unittest.TestCase): 11 | 12 | def setUp(self): 13 | self.app = myapp.test_client() 14 | 15 | def test_main(self): 16 | rv = self.app.get('/') 17 | assert rv.status == '200 OK' 18 | assert b'Congratulations' in rv.data 19 | #assert False 20 | 21 | def test_404(self): 22 | rv = self.app.get('/other') 23 | self.assertEqual(rv.status, '404 NOT FOUND') 24 | 25 | 26 | if __name__ == '__main__': 27 | unittest.main() 28 | -------------------------------------------------------------------------------- /web.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | from flask import Flask, flash, redirect, render_template, request, session, abort 4 | from random import randint 5 | 6 | 7 | def shutdown_server(): 8 | func = request.environ.get('werkzeug.server.shutdown') 9 | if func is None: 10 | raise RuntimeError('Not running with the Werkzeug Server') 11 | func() 12 | 13 | 14 | myapp = Flask(__name__) 15 | 16 | 17 | @myapp.route('/shutdown', methods=['POST']) 18 | def shutdown(): 19 | shutdown_server() 20 | return 'Server shutting down...' 21 | 22 | 23 | @myapp.route("/") 24 | def hello(): 25 | # return name 26 | return render_template( 27 | 'test.html', **locals()) 28 | 29 | 30 | if __name__ == "__main__": 31 | myapp.run(host='0.0.0.0', port=80) 32 | --------------------------------------------------------------------------------