On the previous post I showed how to setup an Azure DevOps pipeline to push Docker images into ECR.
In this guide I will show how to use AWS Elastic Beanstalk to pull and run these images in a fully fledged application (with database, EC2 servers, load balancer; all handled by EB)
Pre-requisites
- AWS-CLI
- EB CLI
- An AWS account with the following permissions:
- ECR (Elastic Container Registry)
- ECS (Elastic Container Service)
- EC2 (Elastic Compute Cloud)
- RDS (Relational Database Service)
- EB (Elastic Beanstalk)
IAM role
In order to initialize an EB application, I created IAM role with the following permission policies:
AdministratorAccess-AWSElasticBeanstalk
AmazonEC2ContainerRegistryFullAccess
EC2InstanceProfileForImageBuilderECRContainerBuilds
AmazonSSMFullAccess
AmazonEC2FullAccess
AWSElasticBeanstalkMulticontainerDocker
AWSElasticBeanstalkRoleECS
Optional - push the redis cache to a private ECR repository
It was better for my project to have a locally available version of the dependencies, so I created an powershell script create-local-redis.ps1
to push a new version of the redis image
aws ecr get-login-password --region AWS_REGION | docker login --username AWS --password-stdin AWS_ACCOUNT_ID.dkr.ecr.AWS_REGION.amazonaws.com
docker pull redis:7.2.1
docker tag redis:7.2.1 AWS_ACCOUNT_ID.dkr.ecr.AWS_REGION.amazonaws.com/local-redis:7.2.1
docker push AWS_ACCOUNT_ID.dkr.ecr.AWS_REGION.amazonaws.com/local-redis:7.2.1
Configuration files for Elastic Beanstalk
I used the configuration for EB multicontainer
So I added a deployment/
folder side-by-side with MyJavaSolution
with the following:
deployment/
├── create-local-redis.ps1
├── Dockerrun.aws.json
├── .ebextensions/
│ │── db-instance-properties.config
│ │── network-load-balancer.config
│
MyJavaSolution/
├── ...
Dockerrun.aws.json
{
"AWSEBDockerrunVersion": 2,
"containerDefinitions": [
{
"name": "local-redis",
"image": "AWS_ACCOUNT_ID.dkr.ecr.AWS_REGION.amazonaws.com/local-redis:7.2.1",
"portMappings": [
{
"hostPort": 6379,
"containerPort": 6379
}
],
"essential": true,
"memory": 1024
},
{
"name": "customer_DOCKER_REPOSITORY_NAME",
"image": "AWS_ACCOUNT_ID.dkr.ecr.AWS_REGION.amazonaws.com/customer_DOCKER_REPOSITORY_NAME:Build.BuildNumber",
"portMappings": [
{
"hostPort": 9001,
"containerPort": 9001
}
],
"links": [
"local-redis"
],
"essential": true,
"memory": 1024
},
{
"name": "ADMIN_DOCKER_REPOSITORY_NAME",
"image": "AWS_ACCOUNT_ID.dkr.ecr.AWS_REGION.amazonaws.com/ADMIN_DOCKER_REPOSITORY_NAME:Build.BuildNumber",
"portMappings": [
{
"hostPort": 9002,
"containerPort": 9002
}
],
"links": [
"local-redis"
],
"essential": true,
"memory": 1024
}
]
}
db-instance-properties.config
option_settings:
# Sets a decoupled database for the connection
# It can be created from a specific snapshot using DBSnapshotIdentifier
# If you are happy with the database, you can choose to decouple it via command line later
aws:rds:dbinstance:
DBAllocatedStorage: '5'
DBDeletionPolicy: Retain
DBInstanceClass: db.t4g.micro
DBSnapshotIdentifier: 'DB_INITIAL_SNAPSHOT'
HasCoupledDatabase: 'true'
MultiAZDatabase: 'false'
DBName: DB_NAME
DBEngine: DB_ENGINE
DBEngineVersion: DB_ENGINE_VERSION
DBUser: DB_USERNAME
DBPassword: DB_PASSWORD
network-load-balancer.config
option_settings:
# Set the instance type for EC2 instances to t3.large.
aws:ec2:instances:
InstanceTypes: t3.large
# Set the instance type for Auto Scaling launch configuration to t3.large.
aws:autoscaling:launchconfiguration:
InstanceType: t3.large
# Disable the listener on port 80.
aws:elbv2:listener:default:
ListenerEnabled: false
# Configure Elastic Beanstalk to listen on port 9001.
aws:elbv2:listener:9001:
DefaultProcess: default
ListenerEnabled: 'true'
Protocol: HTTP
Rules: null
SSLCertificateArns: null
SSLPolicy: null
# Configure Elastic Beanstalk to listen on port 9002.
aws:elbv2:listener:9002:
DefaultProcess: admin
ListenerEnabled: 'true'
Protocol: HTTP
Rules: null
SSLCertificateArns: null
SSLPolicy: null
# Configure default Health endpoint to be Customer health
aws:elasticbeanstalk:environment:process:default:
DeregistrationDelay: '20'
HealthCheckInterval: '15'
HealthCheckPath: /api/customer/health
HealthCheckTimeout: '5'
HealthyThresholdCount: '3'
MatcherHTTPCode: '200'
Port: '9001'
Protocol: HTTP
StickinessEnabled: 'false'
StickinessLBCookieDuration: '86400'
StickinessType: lb_cookie
UnhealthyThresholdCount: '5'
# Configure additional Health endpoint to be Admin health
admin.aws:elasticbeanstalk:environment:process:admin:
DeregistrationDelay: '20'
HealthCheckInterval: '15'
HealthCheckPath: /api/admin/health
HealthCheckTimeout: '5'
HealthyThresholdCount: '3'
MatcherHTTPCode: '200'
Port: '9002'
Protocol: HTTP
StickinessEnabled: 'false'
StickinessLBCookieDuration: '86400'
StickinessType: lb_cookie
UnhealthyThresholdCount: '5'
Inital AWS Elastic Beanstalk setup
Provided the desired images are already in ECR, I first initialized EB after installing AWS and EB CLI with: eb init
Select a default region
1) us-east-1 : US East (N. Virginia)
2) us-west-1 : US West (N. California)
3) us-west-2 : US West (Oregon)
4) eu-west-1 : EU (Ireland)
5) eu-central-1 : EU (Frankfurt)
6) ap-south-1 : Asia Pacific (Mumbai)
7) ap-southeast-1 : Asia Pacific (Singapore)
8) ap-southeast-2 : Asia Pacific (Sydney)
9) ap-northeast-1 : Asia Pacific (Tokyo)
10) ap-northeast-2 : Asia Pacific (Seoul)
11) sa-east-1 : South America (Sao Paulo)
12) cn-north-1 : China (Beijing)
13) cn-northwest-1 : China (Ningxia)
14) us-east-2 : US East (Ohio)
15) ca-central-1 : Canada (Central)
16) eu-west-2 : EU (London)
17) eu-west-3 : EU (Paris)
18) eu-north-1 : EU (Stockholm)
19) eu-south-1 : EU (Milano)
20) ap-east-1 : Asia Pacific (Hong Kong)
21) me-south-1 : Middle East (Bahrain)
22) il-central-1 : Middle East (Israel)
23) af-south-1 : Africa (Cape Town)
24) ap-southeast-3 : Asia Pacific (Jakarta)
25) ap-northeast-3 : Asia Pacific (Osaka)
(default is 3): 19
Enter Application Name
(default is "eb_deploy"): MyJavaAPI-newEnv
Application MyJavaAPI-newEnv has been created.
It appears you are using Docker. Is this correct?
(Y/n): y
Select a platform branch.
1) Docker running on 64bit Amazon Linux 2023
2) ECS running on 64bit Amazon Linux 2023
3) Docker running on 64bit Amazon Linux 2
4) ECS running on 64bit Amazon Linux 2
(default is 1): 2
Cannot setup CodeCommit because there is no Source Control setup, continuing with initialization
Do you want to set up SSH for your instances?
(Y/n): y
Select a keypair.
1) existing_pair
2) [ Create new KeyPair ]
(default is 1): 2
Type a keypair name.
(Default is aws-eb): MyJavaSolutionAPI_pair
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in C:\Users\Username\.ssh\MyJavaSolutionAPI_pair.
Your public key has been saved in C:\Users\Username\.ssh\MyJavaSolutionAPI_pair.pub.
The key fingerprint is:
SHA256:.../te34 MyJavaSolutionAPI_pair
The key's randomart image is:
...
Enter passphrase:
WARNING: Uploaded SSH public key for "MyJavaSolutionAPI_pair" into EC2 for region ...
Create
- After the AWS Beanstalk Environment was initialized locally, run
eb create
to push the initial changes into the server
Enter Environment Name
(default is MyJavaAPI-newEnv): MyJavaAPI-newEnv
Enter DNS CNAME prefix
(default is MyJavaAPI-newEnv):
Select a load balancer type
1) classic
2) application
3) network
(default is 2): 2
Would you like to enable Spot Fleet requests for this environment? (y/N): n
Creating application version archive "app-231023_153901209577".
Uploading MyJavaAPI/app-231023_153901209577.zip to S3. This may take a while.
If the configuration is applied correctly, then it will create a new EB application and environment, with a coupled RDS database, a EC2 instance, an S3 bucket containing the files, an ECS cluster and all necessary security groups.
Manually deploying a new version on AWS Elastic Beanstalk
Deploy
If the latest build was 20231026.21:
You can change the version in Dockerrun.aws.json
and run
eb deploy --label "20231026.21" --message "20231026.21" --process
This will result in a new application version in the server.
Config save
The configuration of a current version can be saved to be reused in different environments.
eb config save --cfg my-api-v2-20231026.21 --tags Environment=newEnv
And with that we have an environment up and running with our 2 dockerized API images.
In the next post of this series I will show how to use Azure DevOps pipelines and release to Continuously Deploy this.
Top comments (0)