Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create aws.yml #11

Open
wants to merge 15 commits into
base: dev
Choose a base branch
from
92 changes: 92 additions & 0 deletions .github/workflows/aws.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# This workflow will build and push a new container image to Amazon ECR,
# and then will deploy a new task definition to Amazon ECS, when there is a push to the dev branch.
#
# To use this workflow, you will need to complete the following set-up steps:
#
# 1. Create an ECR repository to store your images.
# For example: `aws ecr create-repository --repository-name my-ecr-repo --region us-east-2`.
# Replace the value of the `ECR_REPOSITORY` environment variable in the workflow below with your repository's name.
# Replace the value of the `AWS_REGION` environment variable in the workflow below with your repository's region.
#
# 2. Create an ECS task definition, an ECS cluster, and an ECS service.
# For example, follow the Getting Started guide on the ECS console:
# https://us-east-2.console.aws.amazon.com/ecs/home?region=us-east-2#/firstRun
# Replace the value of the `ECS_SERVICE` environment variable in the workflow below with the name you set for the Amazon ECS service.
# Replace the value of the `ECS_CLUSTER` environment variable in the workflow below with the name you set for the cluster.
#
# 3. Store your ECS task definition as a JSON file in your repository.
# The format should follow the output of `aws ecs register-task-definition --generate-cli-skeleton`.
# Replace the value of the `ECS_TASK_DEFINITION` environment variable in the workflow below with the path to the JSON file.
# Replace the value of the `CONTAINER_NAME` environment variable in the workflow below with the name of the container
# in the `containerDefinitions` section of the task definition.
#
# 4. Store an IAM user access key in GitHub Actions secrets named `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
# See the documentation for each action used below for the recommended IAM policies for this IAM user,
# and best practices on handling the access key credentials.

name: Deploy to Amazon ECS

on:
push:
branches:
- dev

env:
AWS_REGION: MY_AWS_REGION # set this to your preferred AWS region, e.g. us-west-1
ECR_REPOSITORY: MY_ECR_REPOSITORY # set this to your Amazon ECR repository name
ECS_SERVICE: MY_ECS_SERVICE # set this to your Amazon ECS service name
ECS_CLUSTER: MY_ECS_CLUSTER # set this to your Amazon ECS cluster name
ECS_TASK_DEFINITION: MY_ECS_TASK_DEFINITION # set this to the path to your Amazon ECS task definition
# file, e.g. .aws/task-definition.json
CONTAINER_NAME: MY_CONTAINER_NAME # set this to the name of the container in the
# containerDefinitions section of your task definition

jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
environment: production

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}

- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1

- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
run: |
# Build a docker container and
# push it to ECR so that it can
# be deployed to ECS.
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"

- name: Fill in the new image ID in the Amazon ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: ${{ env.ECS_TASK_DEFINITION }}
container-name: ${{ env.CONTAINER_NAME }}
image: ${{ steps.build-image.outputs.image }}

- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: ${{ env.ECS_SERVICE }}
cluster: ${{ env.ECS_CLUSTER }}
wait-for-service-stability: true
94 changes: 85 additions & 9 deletions deploy-templates/aws-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ AWSTemplateFormatVersion: "2010-09-09"
Description: >
1. Make a copy of deploy-parameters.env.example and rename it to deploy-parameters.env, then populate it with the values appropriate to your environment. CloudFormation will read those values from the file if you pass it on the command line when you create or update the stack. See the parameter definitions below for full instructions.
2. Navigate to the directory that contains these files and run the following aws cli command:
aws cloudformation create-stack --stack-name qa-server \
aws cloudformation create-stack --stack-name lookup-int-deploy \
--profile qa-user \
--template-body file://./aws-deploy.yaml \
--parameters file://./deploy-parameters.env \
--role-arn arn:aws:iam::<your_account_id>:role/qa-role \
--parameters file://./deploy-int.env \
--role-arn arn:aws:iam::092831676293:role/qa-service-cloudformation-role \
--capabilities CAPABILITY_NAMED_IAM
3. You will need to validate the ACM certificate after the stack has been created, by creating the DNS record that will appear in the CloudFormation and ACM consoles.

Expand Down Expand Up @@ -42,6 +42,10 @@ Parameters:
Type: String
Default: ''
Description: EFS Access Point ID of the volume where the authority files are stored. This will map to the application's authority file volume, and it should contain at least one authority file. If no authority files are found, the application will still launch, and static portions will display, but the Authorities, Check Status, and Monitor Status pages may behave unpredictably.
LocalesAccessPointId:
Type: String
Default: ''
Description: EFS Access Point ID of the volume where the locale files are stored. This will map to the application's locales file volume, and it should contain at least one locale file. If no locale files are found, the application will still launch, and static portions will display, but the appearance may be unpredictable.
DatabaseAccessPointId:
Type: String
Default: ''
Expand All @@ -54,6 +58,26 @@ Parameters:
Description: EC2 instance type for the cluster. This is recommended to be a type with at least 2 CPUs and 8 GiB of RAM, but you can change it here if you need to.
Type: String
Default: m5.large
KeyPair:
Description: The name of an existing EC2 key pair that can be used to SSH to your cluster instances for debugging or troubleshooting. This is entirely optional and your service will function without it. Without a key pair you will not be able to log in to your cluster's EC2 instances via SSH. This key pair must already exist in your account, and you should have a copy of the public key downloaded to your local host.
Type: String
Default: ''
TagCostCenter:
Type: String
Default: L858313
Description: This tag and the ones that follow are provided as an example and may not be appropriate to your environment. Feel free to alter or remove them as necessary.
TagEnvironment:
Type: String
Default: Development
TagApplication:
Type: String
Default: LD4P
TagPanopta:
Type: String
Default: Dev
TagTechnicalContact:
Type: String
Default: gad22
Mappings:
AWSRegionToAMI:
Description: This list of ECS-optimized AMIs will change over time and will need to be maintained. You can get the most recent AMI for your current region with the command `aws ssm get-parameters --names /aws/service/ecs/optimized-ami/amazon-linux-2/recommended`. If your region is known and does not change, the others can be ignored or removed safely.
Expand Down Expand Up @@ -100,6 +124,8 @@ Resources:
MountPoints:
- SourceVolume: qa-server-authorities
ContainerPath: /app/ld4p/qa_server-webapp/config/authorities
- SourceVolume: qa-server-locales
ContainerPath: /app/ld4p/qa_server-webapp/config/locales
PortMappings:
- HostPort: 3000
Protocol: tcp
Expand All @@ -110,7 +136,7 @@ Resources:
- Type: s3
Value: !Join ["", ["arn:aws:s3:::", !Ref S3BucketName, "/", !Ref EnvFileName]]
Essential: True
Image: mariadb:latest
Image: mariadb:10.7.4
LogConfiguration:
LogDriver: awslogs
Options:
Expand All @@ -120,7 +146,7 @@ Resources:
MemoryReservation: 512
MountPoints:
- SourceVolume: db-mysql-data
ContainerPath: /var/lib/mysql/data
ContainerPath: /var/lib/mysql
PortMappings:
- HostPort: 3306
Protocol: tcp
Expand All @@ -140,13 +166,25 @@ Resources:
AccessPointId: !Ref AuthorityAccessPointId
RootDirectory: "/"
TransitEncryption: ENABLED
- Name: qa-server-locales
EFSVolumeConfiguration:
FilesystemId: !Ref VolumeId
AuthorizationConfig:
AccessPointId: !Ref LocalesAccessPointId
RootDirectory: "/"
TransitEncryption: ENABLED
- Name: db-mysql-data
EFSVolumeConfiguration:
FilesystemId: !Ref VolumeId
AuthorizationConfig:
AccessPointId: !Ref DatabaseAccessPointId
RootDirectory: "/"
TransitEncryption: ENABLED
Tags:
- Key: "Cost Center"
Value: !Ref TagCostCenter
- Key: "Application"
Value: !Ref TagApplication
CloudwatchLogGroup:
Type: AWS::Logs::LogGroup
Properties:
Expand All @@ -156,6 +194,15 @@ Resources:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Join ["", [!Ref AWS::StackName, "-cluster"]]
Tags:
- Key: "Cost Center"
Value: !Ref TagCostCenter
- Key: "Application"
Value: !Ref TagApplication
- Key: "Environment"
Value: !Ref TagEnvironment
- Key: "Technical Contact"
Value: !Ref TagTechnicalContact
Service:
Type: AWS::ECS::Service
DependsOn:
Expand All @@ -165,8 +212,8 @@ Resources:
Cluster: !Join ["", [!Ref AWS::StackName, "-cluster"]]
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
DesiredCount: 2
MinimumHealthyPercent: 0
DesiredCount: 1
EnableECSManagedTags: true
HealthCheckGracePeriodSeconds: 0
LaunchType: "EC2"
Expand Down Expand Up @@ -202,6 +249,14 @@ Resources:
- Key: Name
Value:
Ref: AWS::StackName
- Key: "Cost Center"
Value: !Ref TagCostCenter
- Key: "Application"
Value: !Ref TagApplication
- Key: "Environment"
Value: !Ref TagEnvironment
- Key: "Technical Contact"
Value: !Ref TagTechnicalContact
Type: application
SecurityGroupLB:
Type: AWS::EC2::SecurityGroup
Expand Down Expand Up @@ -327,6 +382,25 @@ Resources:
MinSize: '1'
MaxSize: '2'
DesiredCapacity: '2'
Tags:
- Key: "Name"
Value: !Ref AWS::StackName
PropagateAtLaunch: true
- Key: "Cost Center"
Value: !Ref TagCostCenter
PropagateAtLaunch: true
- Key: "Application"
Value: !Ref TagApplication
PropagateAtLaunch: true
- Key: "Environment"
Value: !Ref TagEnvironment
PropagateAtLaunch: true
- Key: "Panopta"
Value: !Ref TagPanopta
PropagateAtLaunch: true
- Key: "Technical Contact"
Value: !Ref TagTechnicalContact
PropagateAtLaunch: true
CreationPolicy:
ResourceSignal:
Timeout: PT15M
Expand All @@ -340,6 +414,7 @@ Resources:
SecurityGroups: [!Ref 'SecurityGroupCI', !Ref 'SecurityGroupLB']
InstanceType: !Ref 'InstanceType'
IamInstanceProfile: !Ref 'EC2InstanceProfile'
KeyName: !Ref 'KeyPair'
UserData:
Fn::Base64: !Sub |
#!/bin/bash -xe
Expand Down Expand Up @@ -367,8 +442,9 @@ Resources:
'ecr:BatchCheckLayerAvailability', 'ecr:GetDownloadUrlForLayer',
'ecr:BatchGetImage', 'logs:CreateLogStream', 'logs:PutLogEvents']
Resource: '*'
# If you would rather use the AWS managed policy than the above custom policy, use this:
# ManagedPolicyArns:
# - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore'
# The following managed policy is an alternative to the custom policy
# - 'arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role'
AutoscalingRole:
Type: AWS::IAM::Role
Expand Down Expand Up @@ -449,7 +525,7 @@ Outputs:
Cluster:
Value: !Ref 'EcsCluster'
LoadBalancer:
Description: Your Load Balancer's URL. Create a DNS record for {!Ref DomainName} that points to this location.
Description: Your Load Balancer's URL. Create a DNS record for your app's domain that points to this location.
Value: !Join ['', [!GetAtt [LoadBalancer, DNSName]]]
TaskDefinition:
Value: !Ref 'TaskDefinition'
Loading