Continuous Deployment With Git

Introduction

While deploying with FTP or from the browser gets you started quickly it is not efficient for ongoing maintenance. For continuous deployment you need easily scripted integration into your build process. Both Azure and AWS support this while integrating with Git version control.

For my first continuous deployment comparison I am continuing with Java. As Azure and AWS both require a compiled and bundled package for Java deployment this is a little more complicated than deploying a folder of, for example, PHP script files.

The build process will require two Git repositories: one for source code and one for deployed artifacts. The automated build process will build the latest code from the source repository, commit the resultant WAR file to to the deployment repository, then deploy from there to the hosting environment. Only the last step is described here as the rest is standard practice and doesn't vary between Azure and AWS.

Azure

Once again I am doing the deployment using the preview of the new Azure management portal. To set up continuous deployment on an application start by selecting BROWSE ALL -> All Resources, select your web application, then scroll down the bottom right pane to the Deployment section.

Click on "Set up continuous deployment" -> CHOOSE SOURCE on the right -> Local Git Repository, then OK.

If deployment credentials have not been previously created then there will be a link to set them. Once that is done click on the Deployment section back at your web application panel to get the Git repository URL.

You now go to your build machine and use git clone to create your deployment repository from the Azure Git repository. Your repository folder now contains the contents of wwwroot from the Azure web application. Any WAR files that you have already deployed to Azure are in the webapps folder.

To deploy changes to your web application your build process should update the appropriate WAR file in the deployment repository, stage and commit the changes in Git, then push them to the Azure repository that you cloned from. In the output from the push command you will see something like this.

Counting objects: 7, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 2.45 KiB | 0 bytes/s, done.
Total 4 (delta 1), reused 0 (delta 0)
remote: Updating branch 'master'.
remote: Updating submodules.
remote: Preparing deployment for commit id '7eacf8cec6'.
remote: Generating deployment script.
remote: Running deployment command...
remote: Handling Basic Web Site deployment.
remote: Finished successfully.
remote: Deployment successful.
To https://atillo@atillohelloworld.scm.azurewebsites.net:443/atillohelloworld.git
   8e0c974..7eacf8c  master -> master

As well as accepting the updated files the remote repository is deploying them to Tomcat. Your updated WAR file is now deployed and running with your changes active. The Deployment section in the portal is updated to show deployment details.

AWS

In AWS the first step is to create the credentials to be used for deployment. Start in the console by selecting Administration & Security -> IAM -> Users, then Create New Users.

Enter a user name to be used for deployment to the application. Ensure "Generate an access key for each user" is checked and click Create.

A screen will be displayed allowing viewing and downloading of the Access Key ID and Secret Access Key for your new user. Copy this information somewhere secure but accessible to you. The Secret Access Key cannot be recovered from AWS later. Once the information is secured click on Close to return to the user list.

Select the user that you just created, scroll down to Permissions, then select Attach Policy under Managed Policies.

Check AWSElasticBeanstalkFullAccess, then select Attach Policy.

You will be returned to the user details page. Note that you have just granted very wide access to your new user, probably suitable only for a small project where everyone with access to the build machine genuinely should have access to almost everything attached to your AWS account. For larger projects with more stringent security requirements a more specific policy should be crafted.

Command line deployment to AWS Elastic Beanstalk requires that the Elastic Beanstalk Command Line Interface (EB CLI) is installed on your build machine. You will need to install Python 3.4, then install the EB CLI using pip install awsebcli. You can verify that the EB CLI has installed correctly using eb --version. This should print the version of EB CLI installed (3.4.6 at the time of this article) and the version of Python it is running on.

Create your deployment repository using git init, then run eb init in the repository folder. This script will ask you to select the AWS region where you created your web application, enter the Access Key ID and Secret Access Key that you generated earlier, then select the web application to manage from those you currently have deployed.

eb init will have created a folder called .elasticbeanstalk in your repository and file called config.yml in the folder. As this is a Java web application we are deploying from a WAR file and not the folder contents so edit config.yml to add these lines:

deploy:
  artifact: yourwarfilename.war

To deploy changes to your web application your build process should update the WAR file in the deployment repository, stage and commit the changes in Git, then execute eb deploy in the deployment folder. In the output from eb deploy you will see something like this.

Uploading HelloWorld/7211.war to S3. This may take a while.
Upload Complete.
INFO: Environment update is starting.
INFO: Deploying new version to instance(s).
INFO: New application version was deployed to running EC2 instances.
INFO: Environment update completed successfully.

The EB CLI is sending the updated files to AWS then deploying them to Tomcat. Your updated WAR file is now deployed and running with your changes active. The Event log for the web application shows the deployment.

Comparison

Both platforms provide a command line method to execute a script that copies deployment artefacts to the hosting platform, then deploys them to the Tomcat server. The major difference between the platforms is where that script is run. On Azure the build machine uses only standard git commands and the deployment script is run automatically by hooks on the Azure platform. On AWS the script must be deployed and run on the build machine and communicates with the AWS platform using the API.

In my opinion the Azure system is a little better. A development team can deploy to Azure from any machine with Git installed, without ever needing any further control of the environment. For AWS the team must be able to install the EB CLI to the build machine, admittedly just once, and ensure that the deployment process has access to Python and the EB CLI instead of just Git.

Where AWS comes out ahead again is in security. The AWS deployment credentials are created via a standard AWS user allowing all of the granular control that comes with AWS access management. That user can be granted exactly as much and as little access as they require to carry out necessary tasks. The Azure deployment credentials are their own thing that can't be attached to any other purpose and can't be restricted from deployment access to every application in the account. This provides less flexibility in how the account is managed.