DEV Community

Laura
Laura

Posted on

Migrating an Springboot Java API: Part 4 - Azure Release

On the previous post I used AWS Elastic Beanstalk to pull and run 2 dockerized Java APIs in a fully fledged application.
In this guide I will show how I used Azure DevOps release to continously deploy new versions of the APIs into AWS.

Pre-requisites

IAM role

In order to allow my Azure releases to deploy new AWS Elastic Beanstalk versions, I created IAM role with the following permission policies:

AdministratorAccess-AWSElasticBeanstalk
AmazonEC2ContainerRegistryFullAccess
EC2InstanceProfileForImageBuilderECRContainerBuilds
AmazonSSMFullAccess
AmazonEC2FullAccess
AWSElasticBeanstalkMulticontainerDocker
AWSElasticBeanstalkRoleECS
Enter fullscreen mode Exit fullscreen mode

Changing the pipelines to include the deployment information

In the previous post I created a deployment folder in my solution repository, so now I changed the existing azure-pipelines.yml to publish the deployment into a different artifact.

trigger:
  - main

resources:
  - repo: self

stages:
  - stage: ReplaceVariables
    displayName: Replace variables
    jobs:
      - job: ReplaceAzureVariables
        displayName: Replace Azure variables
        pool:
          vmImage: ubuntu-latest
        steps:
        - task: replacetokens@5
          displayName: Replace Tokens
          inputs:
            targetFiles: |
              **/application.yml
              **/application.properties
              deployment/**

            encoding: 'auto'
            tokenPattern: 'doublebraces'
            writeBOM: true
            actionOnMissing: 'warn'
            keepToken: false
            actionOnNoFiles: 'continue'
            enableTransforms: false
            enableRecursion: false
            useLegacyPattern: false
            enableTelemetry: false

        - task: CopyFiles@2
          displayName: Copy deployment files
          inputs:
            Contents: 'deployment/**'
            TargetFolder: '$(Build.ArtifactStagingDirectory)'

        - publish: $(Build.ArtifactStagingDirectory)/deployment
          displayName: Publish deployment files
          artifact: deployment

        - task: CopyFiles@2
          displayName: Copy all files 
          inputs:
            Contents: '**'
            TargetFolder: '$(Build.ArtifactStagingDirectory)'

        - publish: $(Build.ArtifactStagingDirectory)
          displayName: Publish all files
          artifact: drop

  - stage: CustomerDockerBuildPublish
    displayName: Customer API
    dependsOn: ReplaceVariables
    jobs:
      - job: Build_and_Push
        displayName: Customer - Build & Push Docker image
        pool:
          vmImage: ubuntu-latest
        steps:
          # Skip source code checkout and reuse sources
          - checkout: none
          # Download the artifact from the ReplaceVariables stage
          - task: DownloadPipelineArtifact@2
            inputs:
              buildType: 'current'
              artifact: drop
              targetPath: '$(Build.SourcesDirectory)'

          - task: Docker@2
            displayName: Customer - Build Customer API Docker image
            inputs:
              command: build
              dockerfile: './Customer.Dockerfile'
              buildContext: '$(Build.SourcesDirectory)'
              repository: $(CUSTOMER_DOCKER_REPOSITORY_NAME)
              tags: |
                $(Build.BuildNumber)

          - task: ECRPushImage@1
            displayName: Customer - Push Admin API Docker image
            inputs:
              awsCredentials: 'my-azure-service-connection'
              regionName: '$(AWS_REGION)'
              imageSource: 'imagename'
              sourceImageName: '$(CUSTOMER_DOCKER_REPOSITORY_NAME)'
              sourceImageTag: '$(Build.BuildNumber)'
              pushTag: '$(Build.BuildNumber)'
              repositoryName: '$(CUSTOMER_DOCKER_REPOSITORY_NAME)'
              logRequest: true
              logResponse: true

  - stage: AdminDockerBuildPublish
    displayName: Admin API
    dependsOn: ReplaceVariables
    jobs:
      - job: Build_and_Push
        displayName: Admin - Build & Push Docker image
        pool:
          vmImage: ubuntu-latest
        steps:
          # Skip source code checkout and reuse sources
          - checkout: none
          # Download the artifact from the ReplaceVariables stage
          - task: DownloadPipelineArtifact@2
            inputs:
              buildType: 'current'
              artifact: drop
              targetPath: '$(Build.SourcesDirectory)'

          - task: Docker@2
            displayName: Admin - Build Admin API Docker image
            inputs:
              command: build
              dockerfile: './Admin.Dockerfile'
              buildContext: '$(Build.SourcesDirectory)'
              repository: $(ADMIN_DOCKER_REPOSITORY_NAME)
              tags: |
                $(Build.BuildNumber)

          - task: ECRPushImage@1
            displayName: Admin - Push Admin API Docker image
            inputs:
              awsCredentials: 'my-azure-service-connection'
              regionName: '$(AWS_REGION)'
              imageSource: 'imagename'
              sourceImageName: '$(ADMIN_DOCKER_REPOSITORY_NAME)'
              sourceImageTag: '$(Build.BuildNumber)'
              pushTag: '$(Build.BuildNumber)'
              repositoryName: '$(ADMIN_DOCKER_REPOSITORY_NAME)'
              logRequest: true
              logResponse: true

Enter fullscreen mode Exit fullscreen mode

Change the release trigger

Then I changed the release to be triggered when new builds from main are successful.

Add Azure DevOps Release

Since we want the image size to be linked to the BuildNumber I have changed the release name configuration to be:

Release Name

steps:
- task: UsePythonVersion@0
  displayName: 'Use Python 3.7'
  inputs:
    versionSpec: 3.7

- script: 'pip install --upgrade pip'
  workingDirectory: '$(System.DefaultWorkingDirectory)/_MyJavaSolutionAPI/deployment'
  displayName: 'Command Line Script - Install pip'

- script: 'pip install awsebcli --upgrade --user'
  workingDirectory: '$(System.DefaultWorkingDirectory)/_MyJavaSolutionAPI/deployment'
  displayName: 'Command Line Script- Install awsebcli '


- task: AmazonWebServices.aws-vsts-tools.AWSShellScript.AWSShellScript@1
  displayName: 'AWS Shell Script - Elastic Beanstalk init'
  inputs:
    awsCredentials: 'my-aws-azure-service-connection'
    regionName: '$(AWS_REGION)'
    scriptType: inline
    inlineScript: 'eb init $(AWS_BEANSTALK_ENVIRONMENT_NAME) --platform "$(AWS_PLATFORM)" --tags $(AWS_TAGS) --keyname $(AWS_BEANSTALK_KEYNAME_NAME) --region $(AWS_REGION)'
    disableAutoCwd: true
    workingDirectory: '$(System.DefaultWorkingDirectory)/_MyJavaSolutionAPI/deployment'


- task: AmazonWebServices.aws-vsts-tools.AWSShellScript.AWSShellScript@1
  displayName: 'AWS Shell Script - Elastic Beanstalk deploy'
  inputs:
    awsCredentials: 'my-aws-azure-service-connection'
    regionName: '$(AWS_REGION)'
    scriptType: inline
    inlineScript: 'eb deploy $(AWS_BEANSTALK_ENVIRONMENT_NAME) --label "$(Release.ReleaseName)" --message "$(Release.ReleaseDescription)" --process --region $(AWS_REGION)'
    disableAutoCwd: true
    workingDirectory: '$(System.DefaultWorkingDirectory)/_MyJavaSolutionAPI/deployment'
Enter fullscreen mode Exit fullscreen mode

Release steps

And with that we have a completed CI/CD pipeline in Azure DevOps
This concludes my post series "Migrating an Springboot Java API".
Creating a dockerized version of a Java 1.8 Springboot solution containing 2 APIs, then creating a CI/CD pipeline in Azure DevOps and using AWS Elastic Beanstalk to host and orchestrate the running server.

Top comments (0)