Laura
Posted on November 12, 2023
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
- Azure DevOps agents (I used
ubuntu-latest
pools) - An AWS account with EB (Elastic Beanstalk) access
- Setup AWS Toolkit for Microsoft Azure DevOps
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
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
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:
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'
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.
Posted on November 12, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.