Continuous Integration using AWS CodePipeline (GitHub to Elastic BeanStalk)

AWS CodePipeline can be used to continuously deploy code changes to Elastic Beanstalk in Staging Environment. Here is an example which makes use of amazon web services to deploy code changes for Grails Project.
  1. CodePipeline will get code from GitHub repository, build using CodeBuild and then deploy the war file to Elastic Beanstalk. AWS CodeBuild uses buildspec.yml to get build instructions. Add buildspec.yml at root folder of your project. Since Grails uses gradle to build the project, the content of file can be:
    version: 0.1
    
    phases:
      install:
        commands:
          - echo Install started on `date`
      pre_build:
        commands:
          - echo Pre Build started on `date`
      build:
        commands:
          - echo Build started on `date`
          - ./gradlew assemble
      post_build:
        commands:
          - echo Build completed on `date`
    artifacts:
      files:
        - build/libs/*.war
        
    
  2. The root folder should also contain gradle wrapper (gradlew). We won't have to install gradle on build server if using Gradle wrapper.
  3. Log into AWS account and create AWS CodePipeline to fetch code from github. You will need github credentials, repository and branch name.
  4. Select AWS CodeBuild as Build Provider and then select 'create a new build project'.
  5. AWS CodeBuild can use docker image. However, for this example, select 'use an image managed by AWS'. Then select ubuntu as OS and Java as Runtime.
  6. Select option 'Use buildspec.yml in the source code root directory'. In deploy section, select name of elastic bean stalk application where code needs to be deployed.
  7. And run the code pipeline using button 'Release Changes'.
AWS should show that all build steps have been executed successfully. However, you will not be able to access application using elastic beanstalk URL. This is because CodeBuild packages all output artifacts (mentioned in the files section of buildspec.yml) in a single zip file. In this example, CodeBuild packages war file (created by assemble command) inside a zip file. When this zip file is passed to tomcat by Elastic Beanstalk, tomcat fails to extract contents of files accurately (since tomcat is not getting war file, instead getting zip file which in turn contains war file).
In order to workaround this issue, one possible solution is to use Elastic Beanstalk hooks. Using elastic beanstalk hooks, we can execute bash script which can extract war file in ROOT folder of tomcat.
  1. In the root folder of source code, add folder '.ebextensions'.
  2. Add following file in '.ebextensions'
    files:
      "/opt/elasticbeanstalk/hooks/appdeploy/post/100_myscript.sh":
        mode: "000755"
        owner: root
        group: root
        content: |
          #!/usr/bin/env bash
          sudo mv /var/lib/tomcat8/webapps/ROOT/build/libs/*.war /var/lib/tomcat8/webapps/ROOT.war
          sudo rm -r /var/lib/tomcat8/webapps/ROOT
          sudo service tomcat8 restart
          
    
  3. Modify buildspec.yml file to include .ebextensions as part of output artifacts.
      files:
        - build/libs/*.war
        - .ebextensions/**/*
    
    CodeBuild will package war file and .ebextensions folder into a zip file and pass it to Elastic Beanstalk. Tomcat will unzip the file and place the war file and .ebextensions folder into ROOT folder. Elastic BeanStalk will execute the script after deployment and script will place the correct war file in webapps folder.
Run code pipeline again and it should work now.

Comments

Popular posts from this blog

Practice Questions - AWS Solutions Architect - Associate Certification

AWS Parameter Store