Microservice Deployment
A continuous delivery (CD) pipeline is an automated system that streamlines software moving from version control to end users and customers. A Jenkins Pipeline is defined in a text file known as a Jenkinsfile, which can be committed to a project’s source control repository. This practice, known as “Pipeline-as-Code,” integrates the CD pipeline into the application itself, allowing it to be versioned and reviewed just like any other code.
Jenkins Pipeline
The below is pipeline for our Microservice to deploy service to ECS with Load Balancer
The below pipeline will (1)checkout the changes from the repository, (2)build the image and (3)pushes the image to Docker hub, the next step is to (4)deploy the changes to ECS.
pipeline {
agent any
environment {
IMAGE_REPO = "jonesjalapatgithub"
NAME = "hireapro-admin-service"
VERSION = "${env.BUILD_ID}-${env.GIT_COMMIT}"
registryCredential = 'dockerhub_id'
}
stages {
stage('Build') {
steps {
echo "Running ${VERSION} on ${env.JENKINS_URL}"
sh 'mvn -B -DskipTests clean package'
}
}
stage('Test') {
steps {
sh "chmod +x -R ${env.WORKSPACE}"
sh 'mvn test'
}
post {
always {
junit 'target/surefire-reports/*.xml'
}
}
}
stage('Docker Push') {
steps {
echo " Branch ${env.BRANCH_NAME}"
sh "docker login -u=${DOCKER_USERNAME} -p=${DOCKER_PASSWORD}"
sh "docker build -t ${NAME} ."
sh "docker tag ${NAME}:latest ${IMAGE_REPO}/${NAME}:latest"
sh "docker push ${IMAGE_REPO}/${NAME}:latest"
}
}
stage('Deploy') {
steps {
sh "delete-stack --stack-name hireapro-admin"
sh "aws cloudformation create-stack --capabilities CAPABILITY_NAMED_IAM --stack-name hireapro-admin --template-body file://./ecs.yml"
}
}
}
}
ECS deployment using CloudFormation
CloudFormation is AWS’s service for automating the deployment of AWS resources.
- The cloudFormation script does the following things
- Creates VPC
- Create two public Subnet
- Create two private Subnet
- Create Internet Gateway
- Create Nat Gateway
- Create Route Table
- Create Public Loadbalancer
- Create ECS Cluster
AWSTemplateFormatVersion: '2010-09-09'
Description: AWS core resources to create an ECS cluster spanning public and private subnets. Supports
public facing load balancers.
Mappings:
SubnetConfig:
VPC:
CIDR: '10.0.0.0/16'
PublicOne:
CIDR: '10.0.0.0/24'
PublicTwo:
CIDR: '10.0.1.0/24'
PrivateOne:
CIDR: '10.0.2.0/24'
PrivateTwo:
CIDR: '10.0.3.0/24'
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
EnableDnsSupport: true
EnableDnsHostnames: true
CidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR']
PublicSubnetOne:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 0
- Fn::GetAZs: !Ref 'AWS::Region'
VpcId: !Ref 'VPC'
CidrBlock: !FindInMap ['SubnetConfig', 'PublicOne', 'CIDR']
MapPublicIpOnLaunch: true
PublicSubnetTwo:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 1
- Fn::GetAZs: !Ref 'AWS::Region'
VpcId: !Ref 'VPC'
CidrBlock: !FindInMap ['SubnetConfig', 'PublicTwo', 'CIDR']
MapPublicIpOnLaunch: true
PrivateSubnetOne:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 0
- Fn::GetAZs: !Ref 'AWS::Region'
VpcId: !Ref 'VPC'
CidrBlock: !FindInMap ['SubnetConfig', 'PrivateOne', 'CIDR']
PrivateSubnetTwo:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 1
- Fn::GetAZs: !Ref 'AWS::Region'
VpcId: !Ref 'VPC'
CidrBlock: !FindInMap ['SubnetConfig', 'PrivateTwo', 'CIDR']
InternetGateway:
Type: AWS::EC2::InternetGateway
GatewayAttachement:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref 'VPC'
InternetGatewayId: !Ref 'InternetGateway'
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref 'VPC'
PublicRoute:
Type: AWS::EC2::Route
DependsOn: GatewayAttachement
Properties:
RouteTableId: !Ref 'PublicRouteTable'
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !Ref 'InternetGateway'
PublicSubnetOneRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetOne
RouteTableId: !Ref PublicRouteTable
PublicSubnetTwoRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetTwo
RouteTableId: !Ref PublicRouteTable
NatGatewayOneAttachment:
Type: AWS::EC2::EIP
DependsOn: GatewayAttachement
Properties:
Domain: vpc
NatGatewayTwoAttachment:
Type: AWS::EC2::EIP
DependsOn: GatewayAttachement
Properties:
Domain: vpc
NatGatewayOne:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGatewayOneAttachment.AllocationId
SubnetId: !Ref PublicSubnetOne
NatGatewayTwo:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGatewayTwoAttachment.AllocationId
SubnetId: !Ref PublicSubnetTwo
PrivateRouteTableOne:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref 'VPC'
PrivateRouteOne:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTableOne
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGatewayOne
PrivateRouteTableOneAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTableOne
SubnetId: !Ref PrivateSubnetOne
PrivateRouteTableTwo:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref 'VPC'
PrivateRouteTwo:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTableTwo
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGatewayTwo
PrivateRouteTableTwoAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTableTwo
SubnetId: !Ref PrivateSubnetTwo
####
# ALB related resources
####
PublicLoadBalancerSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Access to the public facing load balancer
VpcId: !Ref 'VPC'
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
IpProtocol: -1
PublicLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Scheme: internet-facing
LoadBalancerAttributes:
- Key: idle_timeout.timeout_seconds
Value: '30'
Subnets:
- !Ref 'PublicSubnetOne'
- !Ref 'PublicSubnetTwo'
SecurityGroups: [!Ref 'PublicLoadBalancerSG']
TargetGroupPublic:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckIntervalSeconds: 6
HealthCheckPath: /hello
HealthCheckProtocol: HTTP
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 2
Port: 80
Protocol: HTTP
TargetType: ip
UnhealthyThresholdCount: 2
VpcId: !Ref 'VPC'
PublicLoadBalancerListener:
Type: AWS::ElasticLoadBalancingV2::Listener
DependsOn:
- PublicLoadBalancer
Properties:
DefaultActions:
- TargetGroupArn: !Ref 'TargetGroupPublic'
Type: 'forward'
LoadBalancerArn: !Ref 'PublicLoadBalancer'
Port: 80
Protocol: HTTP
####
# ECS related resources
####
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: 'hireapro-admin-service'
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: hireapro-admin-service-log-group
ExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: hireapro-admin-service-role
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
ContainerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: ContainerSecurityGroup
GroupDescription: Security group for NGINX container
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 8080
ToPort: 8080
CidrIp: 0.0.0.0/0
VpcId: !Ref 'VPC'
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: hireapro-admin-service-task
Cpu: 256
Memory: 512
NetworkMode: awsvpc
ExecutionRoleArn: !Ref ExecutionRole
ContainerDefinitions:
- Name: hireapro-admin-service-container
Image: jonesjalapatgithub/hireapro-admin-service:latest
PortMappings:
- ContainerPort: 8080
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-region: !Ref AWS::Region
awslogs-group: !Ref LogGroup
awslogs-stream-prefix: ecs
RequiresCompatibilities:
- EC2
- FARGATE
Service:
Type: AWS::ECS::Service
DependsOn: PublicLoadBalancerListener
Properties:
ServiceName: hireapro-admin-service
Cluster: !Ref ECSCluster
TaskDefinition: !Ref TaskDefinition
DesiredCount: 1
LaunchType: FARGATE
LoadBalancers:
- ContainerName: hireapro-admin-service-container
ContainerPort: 8080
TargetGroupArn: !Ref TargetGroupPublic
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
Subnets:
- !Ref 'PrivateSubnetOne'
- !Ref 'PrivateSubnetTwo'
SecurityGroups:
- !GetAtt ContainerSecurityGroup.GroupId
API Gateway deployment
Jenkins File
This pipeline will checkout the code, Delete the previous stack, create a new stack.
pipeline {
agent any
stages {
stage('Delete Previous-Stack') {
steps {
sh "aws cloudformation delete-stack --stack-name hireaproapigateway5"
}
}
stage('Release new-Stack') {
steps {
sh "aws cloudformation create-stack --capabilities CAPABILITY_IAM CAPABILITY_AUTO_EXPAND --stack-name hireaproapigateway --template-body file://./apigateway.yml"
}
}
}
}
Cloudformation
- Creates API Gateway
- Create Method and add API Configuration
- Create a Stage and deploy
Transform: AWS::Serverless-2016-10-31
Resources:
ApiGatewayRestApi0010nid2q3na00BIR7p:
UpdateReplacePolicy: Delete
Type: AWS::ApiGateway::RestApi
DeletionPolicy: Delete
Properties:
ApiKeySourceType: HEADER
EndpointConfiguration:
Types:
- REGIONAL
DisableExecuteApiEndpoint: false
Name: hireapro1
ResourcePath:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !GetAtt ApiGatewayRestApi0010nid2q3na00BIR7p.RootResourceId
RestApiId: !Ref ApiGatewayRestApi0010nid2q3na00BIR7p
PathPart: admin
Resource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !GetAtt ResourcePath.ResourceId
RestApiId: !Ref ApiGatewayRestApi0010nid2q3na00BIR7p
PathPart: '{proxy+}'
ApiGatewayMethod:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref ApiGatewayRestApi0010nid2q3na00BIR7p
ResourceId: !Ref Resource
HttpMethod: GET
AuthorizationType: NONE
RequestParameters:
method.request.path.proxy: true
Integration:
CacheKeyParameters:
- method.request.path.proxy
RequestParameters:
integration.request.path.proxy: method.request.path.proxy
IntegrationHttpMethod: ANY
Type: HTTP_PROXY
Uri: http://hireap-publi-zqxhkhoasadr-1284408898.us-east-2.elb.amazonaws.com/{proxy}
PassthroughBehavior: WHEN_NO_MATCH
IntegrationResponses:
- StatusCode: 200
ApiGatewayStage00prod00Dbe25:
UpdateReplacePolicy: Delete
Type: AWS::ApiGateway::Stage
DeletionPolicy: Delete
Properties:
RestApiId: !Ref ApiGatewayRestApi0010nid2q3na00BIR7p
DeploymentId: !GetAtt ApiGatewayDeployment00pga0oi00ACNil.DeploymentId
StageName: prod
CacheClusterSize: '0.5'
TracingEnabled: false
CacheClusterEnabled: false
ApiGatewayDeployment00pga0oi00ACNil:
UpdateReplacePolicy: Delete
DependsOn:
- ApiGatewayMethod
Type: AWS::ApiGateway::Deployment
DeletionPolicy: Delete
Properties:
RestApiId: !Ref ApiGatewayRestApi0010nid2q3na00BIR7p
Testing
Get the API gateway URL and hit the url on the browser
Github
- https://github.com/jonesjalapatgithub/hireapro-admin-service
- https://github.com/jonesjalapatgithub/hireaprogateway/