P5-4836 deploy api to production (new hostname)
This commit is contained in:
@@ -3,3 +3,4 @@
|
|||||||
venv/
|
venv/
|
||||||
*.sublime-*
|
*.sublime-*
|
||||||
ideas.py
|
ideas.py
|
||||||
|
.fab_tasks~
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
FROM tiangolo/uwsgi-nginx-flask:python3.6
|
||||||
|
|
||||||
|
COPY ./requirements.txt /app
|
||||||
|
RUN pip install -r requirements.txt
|
||||||
|
|
||||||
|
COPY . /app/
|
||||||
|
COPY ./wsgi.py /app/main.py
|
||||||
|
RUN rm /app/wsgi.py
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
publish-to-staging:
|
||||||
|
@current_branch=$$(git rev-parse --abbrev-ref HEAD); \
|
||||||
|
git branch -D staging 2>/dev/null; \
|
||||||
|
git checkout -b staging; \
|
||||||
|
git merge $$current_branch && \
|
||||||
|
git push -f origin staging && \
|
||||||
|
git checkout $$current_branch; \
|
||||||
|
echo Pushed $$current_branch to staging
|
||||||
|
|
||||||
|
sync-master-to-staging:
|
||||||
|
@current_branch=$$(git rev-parse --abbrev-ref HEAD); \
|
||||||
|
git branch -D staging 2>/dev/null; \
|
||||||
|
git checkout master && \
|
||||||
|
git pull origin master && \
|
||||||
|
git checkout -b staging && \
|
||||||
|
git push -f origin staging && \
|
||||||
|
git checkout $$current_branch && \
|
||||||
|
echo Pushed master to staging
|
||||||
@@ -5,7 +5,7 @@ mod = Blueprint("server", __name__)
|
|||||||
|
|
||||||
@mod.route("/", methods=["GET"])
|
@mod.route("/", methods=["GET"])
|
||||||
def status():
|
def status():
|
||||||
data = {"version": "0.0.1"}
|
data = {"version": "0.0.2"}
|
||||||
return jsonify(data)
|
return jsonify(data)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
##
|
||||||
|
# Example:
|
||||||
|
# make create-stack GITHUB_TOKEN=xxxxx ENVIRONMENT_NAME=staging STACK_NAME=api
|
||||||
|
# make create-stack GITHUB_TOKEN=xxxxx ENVIRONMENT_NAME=production STACK_NAME=api
|
||||||
|
#
|
||||||
|
# # make update-stack ENVIRONMENT_NAME=staging STACK_NAME=api
|
||||||
|
##
|
||||||
|
|
||||||
|
GITHUB_REPO := api2
|
||||||
|
GITHUB_USER := Photowall
|
||||||
|
# HOSTED_ZONE=photowall.com default in the template
|
||||||
|
# Cert ARN for the hosted zone
|
||||||
|
CERTIFICATE_ARN='arn:aws:acm:eu-west-1:954747537408:certificate/1278df32-006d-48a4-abd6-2bfccabb11fd'
|
||||||
|
DB_SECURITY_GROUP_ID_PRODUCTION=sg-0b5bafc1e0a97e848
|
||||||
|
DB_SECURITY_GROUP_ID_STAGING=sg-001b3667edf19e1ce
|
||||||
|
|
||||||
|
AWS_REGION=$(shell aws configure get region)
|
||||||
|
AWS_ACCOUNT_ID=$(shell aws sts get-caller-identity --query Account --output text)
|
||||||
|
|
||||||
|
checkdef = $(if $(value $(1)),,$(error $(1) not set))
|
||||||
|
|
||||||
|
DOCKER_IMAGE=$(AWS_ACCOUNT_ID).dkr.ecr.$(AWS_REGION).amazonaws.com/$(STACK_NAME)-$(ENVIRONMENT_NAME)
|
||||||
|
|
||||||
|
ifeq ($(ENVIRONMENT_NAME),production)
|
||||||
|
SUBDOMAIN=$(STACK_NAME)
|
||||||
|
GITHUB_BRANCH=master
|
||||||
|
DB_SECURITY_GROUP_ID=$(DB_SECURITY_GROUP_ID_PRODUCTION)
|
||||||
|
CPU_SIZE=1024
|
||||||
|
MEMORY_SIZE=4GB
|
||||||
|
else
|
||||||
|
SUBDOMAIN=$(STACK_NAME)-$(ENVIRONMENT_NAME)
|
||||||
|
GITHUB_BRANCH=$(ENVIRONMENT_NAME)
|
||||||
|
DB_SECURITY_GROUP_ID=$(DB_SECURITY_GROUP_ID_STAGING)
|
||||||
|
CPU_SIZE=512
|
||||||
|
MEMORY_SIZE=2GB
|
||||||
|
endif
|
||||||
|
|
||||||
|
check-create-initial-ecr-image:
|
||||||
|
@echo Checking for inital image $(DOCKER_IMAGE)
|
||||||
|
@aws ecr list-images --repository-name $(STACK_NAME)-$(ENVIRONMENT_NAME) 2>/dev/null | grep imageTag | grep -q latest; \
|
||||||
|
status=$$?; \
|
||||||
|
if [ $$status != 0 ]; \
|
||||||
|
then \
|
||||||
|
echo ""; \
|
||||||
|
echo "ECR Repo for initial image does not exist, creating"; \
|
||||||
|
echo ""; \
|
||||||
|
aws ecr create-repository --repository $(STACK_NAME)-$(ENVIRONMENT_NAME); \
|
||||||
|
$$(aws ecr get-login --no-include-email --region eu-west-1); \
|
||||||
|
docker pull nginx; \
|
||||||
|
docker tag nginx $(AWS_ACCOUNT_ID).dkr.ecr.$(AWS_REGION).amazonaws.com/$(STACK_NAME)-$(ENVIRONMENT_NAME):latest; \
|
||||||
|
docker push $(AWS_ACCOUNT_ID).dkr.ecr.$(AWS_REGION).amazonaws.com/$(STACK_NAME)-$(ENVIRONMENT_NAME):latest; \
|
||||||
|
echo ""; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
check-create-variables-set:
|
||||||
|
$(call checkdef,STACK_NAME)
|
||||||
|
$(call checkdef,ENVIRONMENT_NAME)
|
||||||
|
$(call checkdef,GITHUB_TOKEN)
|
||||||
|
$(call checkdef,GITHUB_USER)
|
||||||
|
$(call checkdef,GITHUB_REPO)
|
||||||
|
|
||||||
|
create-stack: check-create-variables-set check-create-initial-ecr-image
|
||||||
|
aws cloudformation create-stack --stack-name $(STACK_NAME)-$(ENVIRONMENT_NAME) --template-body file://ecs-service.yaml \
|
||||||
|
--capabilities CAPABILITY_NAMED_IAM \
|
||||||
|
--parameters ParameterKey="EnvironmentName",ParameterValue="$(ENVIRONMENT_NAME)" \
|
||||||
|
ParameterKey="Image",ParameterValue="$(DOCKER_IMAGE)" \
|
||||||
|
ParameterKey="Subdomain",ParameterValue="$(SUBDOMAIN)" \
|
||||||
|
ParameterKey="Certificate",ParameterValue="$(CERTIFICATE_ARN)" \
|
||||||
|
ParameterKey="DatabaseSecurityGroup",ParameterValue="$(DB_SECURITY_GROUP_ID)" \
|
||||||
|
ParameterKey="GitHubRepo",ParameterValue="$(GITHUB_REPO)" \
|
||||||
|
ParameterKey="GitHubUser",ParameterValue="$(GITHUB_USER)" \
|
||||||
|
ParameterKey="GitHubBranch",ParameterValue="$(GITHUB_BRANCH)" \
|
||||||
|
ParameterKey="GitHubToken",ParameterValue="$(GITHUB_TOKEN)" \
|
||||||
|
ParameterKey="CpuSize",ParameterValue="$(CPU_SIZE)" \
|
||||||
|
ParameterKey="MemorySize",ParameterValue="$(MEMORY_SIZE)"
|
||||||
|
|
||||||
|
update-stack:
|
||||||
|
$(call checkdef,STACK_NAME)
|
||||||
|
$(call checkdef,ENVIRONMENT_NAME)
|
||||||
|
aws cloudformation update-stack --stack-name $(STACK_NAME)-$(ENVIRONMENT_NAME) --template-body file://ecs-service.yaml \
|
||||||
|
--capabilities CAPABILITY_NAMED_IAM \
|
||||||
|
--parameters ParameterKey="EnvironmentName",UsePreviousValue=true \
|
||||||
|
ParameterKey="Image",UsePreviousValue=true \
|
||||||
|
ParameterKey="Subdomain",UsePreviousValue=true \
|
||||||
|
ParameterKey="Certificate",UsePreviousValue=true \
|
||||||
|
ParameterKey="DatabaseSecurityGroup",,UsePreviousValue=true \
|
||||||
|
ParameterKey="GitHubRepo",UsePreviousValue=true \
|
||||||
|
ParameterKey="GitHubUser",UsePreviousValue=true \
|
||||||
|
ParameterKey="GitHubBranch",UsePreviousValue=true \
|
||||||
|
ParameterKey="GitHubToken",UsePreviousValue=true \
|
||||||
|
ParameterKey="CpuSize",ParameterValue="$(CPU_SIZE)" \
|
||||||
|
ParameterKey="MemorySize",ParameterValue="$(MEMORY_SIZE)"
|
||||||
@@ -0,0 +1,503 @@
|
|||||||
|
AWSTemplateFormatVersion: 2010-09-09
|
||||||
|
Description: CloudFormation template for a full E2E ECS service with CI/CD on Fargate.
|
||||||
|
Parameters:
|
||||||
|
VPC:
|
||||||
|
Type: AWS::EC2::VPC::Id
|
||||||
|
Default: vpc-6f596904
|
||||||
|
Description: The id of the VPC
|
||||||
|
SubnetA:
|
||||||
|
Type: AWS::EC2::Subnet::Id
|
||||||
|
Default: subnet-6e596905
|
||||||
|
Description: The id of the first subnet
|
||||||
|
SubnetB:
|
||||||
|
Type: AWS::EC2::Subnet::Id
|
||||||
|
Default: subnet-6d596906
|
||||||
|
Description: The id of the second subnet
|
||||||
|
|
||||||
|
DatabaseSecurityGroup:
|
||||||
|
Type: String
|
||||||
|
Description: Security group id to access the database
|
||||||
|
|
||||||
|
Image:
|
||||||
|
Type: String
|
||||||
|
# Docker image for this service. It must have a latest tag
|
||||||
|
# Example 260851616142.dkr.ecr.eu-west-1.amazonaws.com/nginx
|
||||||
|
EnvironmentName:
|
||||||
|
Type: String
|
||||||
|
Description: Name of env such as staging or production
|
||||||
|
|
||||||
|
# CPU
|
||||||
|
# 256 (.25 vCPU) - Available memory values: 0.5GB, 1GB, 2GB
|
||||||
|
# 512 (.5 vCPU) - Available memory values: 1GB, 2GB, 3GB, 4GB
|
||||||
|
# 1024 (1 vCPU) - Available memory values: 2GB, 3GB, 4GB, 5GB, 6GB, 7GB, 8GB
|
||||||
|
# 2048 (2 vCPU) - Available memory values: Between 4GB and 16GB in 1GB increments
|
||||||
|
# 4096 (4 vCPU) - Available memory values: Between 8GB and 30GB in 1GB increments
|
||||||
|
CpuSize:
|
||||||
|
Type: Number
|
||||||
|
|
||||||
|
# Memory
|
||||||
|
# 0.5GB, 1GB, 2GB - Available cpu values: 256 (.25 vCPU)
|
||||||
|
# 1GB, 2GB, 3GB, 4GB - Available cpu values: 512 (.5 vCPU)
|
||||||
|
# 2GB, 3GB, 4GB, 5GB, 6GB, 7GB, 8GB - Available cpu values: 1024 (1 vCPU)
|
||||||
|
# Between 4GB and 16GB in 1GB increments - Available cpu values: 2048 (2 vCPU)
|
||||||
|
# Between 8GB and 30GB in 1GB increments - Available cpu values: 4096 (4 vCPU)
|
||||||
|
MemorySize:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
ContainerPort:
|
||||||
|
Type: Number
|
||||||
|
Default: 80
|
||||||
|
LoadBalancerPort:
|
||||||
|
Type: Number
|
||||||
|
Default: 443
|
||||||
|
HealthCheckPath:
|
||||||
|
Type: String
|
||||||
|
Default: /
|
||||||
|
|
||||||
|
Certificate:
|
||||||
|
Type: String
|
||||||
|
# Update with the certificate ARN from Certificate Manager, which must exist in the same region.
|
||||||
|
HostedZoneName:
|
||||||
|
Type: String
|
||||||
|
Default: photowall.com
|
||||||
|
Subdomain:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
# for autoscaling
|
||||||
|
MinContainers:
|
||||||
|
Type: Number
|
||||||
|
Default: 1
|
||||||
|
# for autoscaling
|
||||||
|
MaxContainers:
|
||||||
|
Type: Number
|
||||||
|
Default: 4
|
||||||
|
# target CPU utilization (%)
|
||||||
|
AutoScalingTargetValue:
|
||||||
|
Type: Number
|
||||||
|
Default: 50
|
||||||
|
|
||||||
|
# Github info for code pipeline
|
||||||
|
GitHubRepo:
|
||||||
|
Type: String
|
||||||
|
GitHubBranch:
|
||||||
|
Type: String
|
||||||
|
GitHubToken:
|
||||||
|
Type: String
|
||||||
|
NoEcho: true
|
||||||
|
GitHubUser:
|
||||||
|
Type: String
|
||||||
|
|
||||||
|
Resources:
|
||||||
|
Cluster:
|
||||||
|
Type: AWS::ECS::Cluster
|
||||||
|
Properties:
|
||||||
|
ClusterName: !Join ['', [!Ref 'AWS::StackName', Cluster]]
|
||||||
|
|
||||||
|
TaskDefinition:
|
||||||
|
Type: AWS::ECS::TaskDefinition
|
||||||
|
# Makes sure the log group is created before it is used.
|
||||||
|
DependsOn: LogGroup
|
||||||
|
Properties:
|
||||||
|
# Name of the task definition. Subsequent versions of the task definition are grouped together under this name.
|
||||||
|
Family: !Join ['', [!Ref 'AWS::StackName', TaskDefinition]]
|
||||||
|
# awsvpc is required for Fargate
|
||||||
|
NetworkMode: awsvpc
|
||||||
|
RequiresCompatibilities:
|
||||||
|
- FARGATE
|
||||||
|
Cpu: !Ref CpuSize
|
||||||
|
Memory: !Ref MemorySize
|
||||||
|
# A role needed by ECS.
|
||||||
|
# "The ARN of the task execution role that containers in this task can assume. All containers in this task are granted the permissions that are specified in this role."
|
||||||
|
# "There is an optional task execution IAM role that you can specify with Fargate to allow your Fargate tasks to make API calls to Amazon ECR."
|
||||||
|
ExecutionRoleArn: !Ref ExecutionRole
|
||||||
|
# "The Amazon Resource Name (ARN) of an AWS Identity and Access Management (IAM) role that grants containers in the task permission to call AWS APIs on your behalf."
|
||||||
|
TaskRoleArn: !Ref TaskRole
|
||||||
|
ContainerDefinitions:
|
||||||
|
- Name: !Ref AWS::StackName
|
||||||
|
Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${AWS::StackName}:latest
|
||||||
|
Environment:
|
||||||
|
- Name: DEBUG
|
||||||
|
Value: True
|
||||||
|
PortMappings:
|
||||||
|
- ContainerPort: !Ref ContainerPort
|
||||||
|
# Define which parameters should be fetched
|
||||||
|
Secrets:
|
||||||
|
- { Name: "SQLALCHEMY_DATABASE_URI", ValueFrom: !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${EnvironmentName}/SQLALCHEMY_DATABASE_URI" }
|
||||||
|
- { Name: "API_KEYS", ValueFrom: !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${EnvironmentName}/API2_API_KEYS" }
|
||||||
|
- { Name: "BERNARD_QUEUE_URL", ValueFrom: !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${EnvironmentName}/BERNARD_QUEUE_URL" }
|
||||||
|
# Send logs to CloudWatch Logs
|
||||||
|
LogConfiguration:
|
||||||
|
LogDriver: awslogs
|
||||||
|
Options:
|
||||||
|
awslogs-region: !Ref AWS::Region
|
||||||
|
awslogs-group: !Ref LogGroup
|
||||||
|
awslogs-stream-prefix: ecs
|
||||||
|
|
||||||
|
# A role needed by ECS
|
||||||
|
ExecutionRole:
|
||||||
|
Type: AWS::IAM::Role
|
||||||
|
Properties:
|
||||||
|
RoleName: !Join ['', [!Ref 'AWS::StackName', ExecutionRole]]
|
||||||
|
AssumeRolePolicyDocument:
|
||||||
|
Statement:
|
||||||
|
- Effect: Allow
|
||||||
|
Principal:
|
||||||
|
Service: ecs-tasks.amazonaws.com
|
||||||
|
Action: 'sts:AssumeRole'
|
||||||
|
ManagedPolicyArns:
|
||||||
|
- 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'
|
||||||
|
- arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess
|
||||||
|
# A role for the containers
|
||||||
|
TaskRole:
|
||||||
|
Type: AWS::IAM::Role
|
||||||
|
Properties:
|
||||||
|
RoleName: !Join ['', [!Ref 'AWS::StackName', TaskRole]]
|
||||||
|
AssumeRolePolicyDocument:
|
||||||
|
Statement:
|
||||||
|
- Effect: Allow
|
||||||
|
Principal:
|
||||||
|
Service: ecs-tasks.amazonaws.com
|
||||||
|
Action: 'sts:AssumeRole'
|
||||||
|
|
||||||
|
# A role needed for auto scaling
|
||||||
|
AutoScalingRole:
|
||||||
|
Type: AWS::IAM::Role
|
||||||
|
Properties:
|
||||||
|
RoleName: !Join ['', [!Ref 'AWS::StackName', AutoScalingRole]]
|
||||||
|
AssumeRolePolicyDocument:
|
||||||
|
Statement:
|
||||||
|
- Effect: Allow
|
||||||
|
Principal:
|
||||||
|
Service: ecs-tasks.amazonaws.com
|
||||||
|
Action: 'sts:AssumeRole'
|
||||||
|
ManagedPolicyArns:
|
||||||
|
- 'arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceAutoscaleRole'
|
||||||
|
|
||||||
|
ContainerSecurityGroup:
|
||||||
|
Type: AWS::EC2::SecurityGroup
|
||||||
|
Properties:
|
||||||
|
GroupDescription: !Join ['', [!Ref 'AWS::StackName', ContainerSecurityGroup]]
|
||||||
|
VpcId: !Ref VPC
|
||||||
|
SecurityGroupIngress:
|
||||||
|
- IpProtocol: tcp
|
||||||
|
FromPort: !Ref ContainerPort
|
||||||
|
ToPort: !Ref ContainerPort
|
||||||
|
SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup
|
||||||
|
|
||||||
|
LoadBalancerSecurityGroup:
|
||||||
|
Type: AWS::EC2::SecurityGroup
|
||||||
|
Properties:
|
||||||
|
GroupDescription: !Join ['', [!Ref 'AWS::StackName', LoadBalancerSecurityGroup]]
|
||||||
|
VpcId: !Ref VPC
|
||||||
|
SecurityGroupIngress:
|
||||||
|
- IpProtocol: tcp
|
||||||
|
FromPort: !Ref LoadBalancerPort
|
||||||
|
ToPort: !Ref LoadBalancerPort
|
||||||
|
CidrIp: 0.0.0.0/0
|
||||||
|
|
||||||
|
Service:
|
||||||
|
Type: AWS::ECS::Service
|
||||||
|
# This dependency is needed so that the load balancer is setup correctly in time
|
||||||
|
DependsOn:
|
||||||
|
- ListenerHTTPS
|
||||||
|
Properties:
|
||||||
|
ServiceName: !Ref AWS::StackName
|
||||||
|
Cluster: !Ref Cluster
|
||||||
|
TaskDefinition: !Ref TaskDefinition
|
||||||
|
DeploymentConfiguration:
|
||||||
|
MinimumHealthyPercent: 100
|
||||||
|
MaximumPercent: 200
|
||||||
|
DesiredCount: 1
|
||||||
|
# This may need to be adjusted if the container takes a while to start up
|
||||||
|
HealthCheckGracePeriodSeconds: 30
|
||||||
|
LaunchType: FARGATE
|
||||||
|
NetworkConfiguration:
|
||||||
|
AwsvpcConfiguration:
|
||||||
|
# change to DISABLED if you're using private subnets that have access to a NAT gateway
|
||||||
|
AssignPublicIp: ENABLED
|
||||||
|
Subnets:
|
||||||
|
- !Ref SubnetA
|
||||||
|
- !Ref SubnetB
|
||||||
|
SecurityGroups:
|
||||||
|
- !Ref ContainerSecurityGroup
|
||||||
|
- !Ref DatabaseSecurityGroup
|
||||||
|
LoadBalancers:
|
||||||
|
- ContainerName: !Ref AWS::StackName
|
||||||
|
ContainerPort: !Ref ContainerPort
|
||||||
|
TargetGroupArn: !Ref TargetGroup
|
||||||
|
|
||||||
|
TargetGroup:
|
||||||
|
Type: AWS::ElasticLoadBalancingV2::TargetGroup
|
||||||
|
Properties:
|
||||||
|
HealthCheckIntervalSeconds: 10
|
||||||
|
# will look for a 200 status code by default unless specified otherwise
|
||||||
|
HealthCheckPath: !Ref HealthCheckPath
|
||||||
|
HealthCheckTimeoutSeconds: 5
|
||||||
|
UnhealthyThresholdCount: 2
|
||||||
|
HealthyThresholdCount: 2
|
||||||
|
Name: !Join ['', [!Ref 'AWS::StackName', TargetGroup]]
|
||||||
|
Port: !Ref ContainerPort
|
||||||
|
Protocol: HTTP
|
||||||
|
TargetGroupAttributes:
|
||||||
|
- Key: deregistration_delay.timeout_seconds
|
||||||
|
Value: 60 # default is 300
|
||||||
|
TargetType: ip
|
||||||
|
VpcId: !Ref VPC
|
||||||
|
|
||||||
|
ListenerHTTPS:
|
||||||
|
Type: AWS::ElasticLoadBalancingV2::Listener
|
||||||
|
Properties:
|
||||||
|
DefaultActions:
|
||||||
|
- TargetGroupArn: !Ref TargetGroup
|
||||||
|
Type: forward
|
||||||
|
LoadBalancerArn: !Ref LoadBalancer
|
||||||
|
Port: !Ref LoadBalancerPort
|
||||||
|
Protocol: HTTPS
|
||||||
|
Certificates:
|
||||||
|
- CertificateArn: !Ref Certificate
|
||||||
|
|
||||||
|
LoadBalancer:
|
||||||
|
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
|
||||||
|
Properties:
|
||||||
|
LoadBalancerAttributes:
|
||||||
|
# this is the default, but is specified here in case it needs to be changed
|
||||||
|
- Key: idle_timeout.timeout_seconds
|
||||||
|
Value: 60
|
||||||
|
Name: !Join ['', [!Ref 'AWS::StackName', LoadBalancer]]
|
||||||
|
# "internal" is also an option
|
||||||
|
Scheme: internet-facing
|
||||||
|
SecurityGroups:
|
||||||
|
- !Ref LoadBalancerSecurityGroup
|
||||||
|
Subnets:
|
||||||
|
- !Ref SubnetA
|
||||||
|
- !Ref SubnetB
|
||||||
|
|
||||||
|
DNSRecord:
|
||||||
|
Type: AWS::Route53::RecordSet
|
||||||
|
Properties:
|
||||||
|
HostedZoneName: !Join ['', [!Ref HostedZoneName, .]]
|
||||||
|
Name: !Join ['', [!Ref Subdomain, ., !Ref HostedZoneName, .]]
|
||||||
|
Type: A
|
||||||
|
AliasTarget:
|
||||||
|
DNSName: !GetAtt LoadBalancer.DNSName
|
||||||
|
HostedZoneId: !GetAtt LoadBalancer.CanonicalHostedZoneID
|
||||||
|
|
||||||
|
LogGroup:
|
||||||
|
Type: AWS::Logs::LogGroup
|
||||||
|
Properties:
|
||||||
|
LogGroupName: !Join ['', [/ecs/, !Ref 'AWS::StackName', TaskDefinition]]
|
||||||
|
|
||||||
|
AutoScalingTarget:
|
||||||
|
Type: AWS::ApplicationAutoScaling::ScalableTarget
|
||||||
|
Properties:
|
||||||
|
MinCapacity: !Ref MinContainers
|
||||||
|
MaxCapacity: !Ref MaxContainers
|
||||||
|
ResourceId: !Join ['/', [service, !Ref Cluster, !GetAtt Service.Name]]
|
||||||
|
ScalableDimension: ecs:service:DesiredCount
|
||||||
|
ServiceNamespace: ecs
|
||||||
|
# "The Amazon Resource Name (ARN) of an AWS Identity and Access Management (IAM) role that allows Application Auto Scaling to modify your scalable target."
|
||||||
|
RoleARN: !GetAtt AutoScalingRole.Arn
|
||||||
|
AutoScalingPolicy:
|
||||||
|
Type: AWS::ApplicationAutoScaling::ScalingPolicy
|
||||||
|
Properties:
|
||||||
|
PolicyName: !Join ['', [!Ref 'AWS::StackName', AutoScalingPolicy]]
|
||||||
|
PolicyType: TargetTrackingScaling
|
||||||
|
ScalingTargetId: !Ref AutoScalingTarget
|
||||||
|
TargetTrackingScalingPolicyConfiguration:
|
||||||
|
PredefinedMetricSpecification:
|
||||||
|
PredefinedMetricType: ECSServiceAverageCPUUtilization
|
||||||
|
ScaleInCooldown: 10
|
||||||
|
ScaleOutCooldown: 10
|
||||||
|
# Keep things at or lower than 50% CPU utilization, for example
|
||||||
|
TargetValue: !Ref AutoScalingTargetValue
|
||||||
|
|
||||||
|
## Deployment pipeline below
|
||||||
|
CodeBuildServiceRole:
|
||||||
|
Type: AWS::IAM::Role
|
||||||
|
Properties:
|
||||||
|
Path: /
|
||||||
|
AssumeRolePolicyDocument:
|
||||||
|
Version: 2012-10-17
|
||||||
|
Statement:
|
||||||
|
- Effect: Allow
|
||||||
|
Principal:
|
||||||
|
Service: codebuild.amazonaws.com
|
||||||
|
Action: sts:AssumeRole
|
||||||
|
Policies:
|
||||||
|
- PolicyName: root
|
||||||
|
PolicyDocument:
|
||||||
|
Version: 2012-10-17
|
||||||
|
Statement:
|
||||||
|
- Resource: "*"
|
||||||
|
Effect: Allow
|
||||||
|
Action:
|
||||||
|
- logs:CreateLogGroup
|
||||||
|
- logs:CreateLogStream
|
||||||
|
- logs:PutLogEvents
|
||||||
|
- ecr:GetAuthorizationToken
|
||||||
|
- Resource: !Sub arn:aws:s3:::${ArtifactBucket}/*
|
||||||
|
Effect: Allow
|
||||||
|
Action:
|
||||||
|
- s3:GetObject
|
||||||
|
- s3:PutObject
|
||||||
|
- s3:GetObjectVersion
|
||||||
|
- Resource: !Sub arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/${AWS::StackName}
|
||||||
|
Effect: Allow
|
||||||
|
Action:
|
||||||
|
- ecr:GetDownloadUrlForLayer
|
||||||
|
- ecr:BatchGetImage
|
||||||
|
- ecr:BatchCheckLayerAvailability
|
||||||
|
- ecr:PutImage
|
||||||
|
- ecr:InitiateLayerUpload
|
||||||
|
- ecr:UploadLayerPart
|
||||||
|
- ecr:CompleteLayerUpload
|
||||||
|
|
||||||
|
CodePipelineServiceRole:
|
||||||
|
Type: AWS::IAM::Role
|
||||||
|
Properties:
|
||||||
|
Path: /
|
||||||
|
AssumeRolePolicyDocument:
|
||||||
|
Version: 2012-10-17
|
||||||
|
Statement:
|
||||||
|
- Effect: Allow
|
||||||
|
Principal:
|
||||||
|
Service: codepipeline.amazonaws.com
|
||||||
|
Action: sts:AssumeRole
|
||||||
|
Policies:
|
||||||
|
- PolicyName: root
|
||||||
|
PolicyDocument:
|
||||||
|
Version: 2012-10-17
|
||||||
|
Statement:
|
||||||
|
- Resource:
|
||||||
|
- !Sub arn:aws:s3:::${ArtifactBucket}/*
|
||||||
|
Effect: Allow
|
||||||
|
Action:
|
||||||
|
- s3:PutObject
|
||||||
|
- s3:GetObject
|
||||||
|
- s3:GetObjectVersion
|
||||||
|
- s3:GetBucketVersioning
|
||||||
|
- Resource: "*"
|
||||||
|
Effect: Allow
|
||||||
|
Action:
|
||||||
|
- ecs:List*
|
||||||
|
- ecs:Describe*
|
||||||
|
- ecs:RegisterTaskDefinition
|
||||||
|
- ecs:UpdateService
|
||||||
|
- codebuild:StartBuild
|
||||||
|
- codebuild:BatchGetBuilds
|
||||||
|
- iam:PassRole
|
||||||
|
|
||||||
|
ArtifactBucket:
|
||||||
|
Type: AWS::S3::Bucket
|
||||||
|
DeletionPolicy: Retain
|
||||||
|
|
||||||
|
CodeBuildProject:
|
||||||
|
Type: AWS::CodeBuild::Project
|
||||||
|
Properties:
|
||||||
|
Artifacts:
|
||||||
|
Type: CODEPIPELINE
|
||||||
|
Source:
|
||||||
|
Type: CODEPIPELINE
|
||||||
|
BuildSpec: |
|
||||||
|
version: 0.2
|
||||||
|
phases:
|
||||||
|
pre_build:
|
||||||
|
commands:
|
||||||
|
- $(aws ecr get-login --no-include-email)
|
||||||
|
- TAG="$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | head -c 8)"
|
||||||
|
- IMAGE_URI="${REPOSITORY_URI}:${TAG}"
|
||||||
|
- IMAGE_LATEST_URI="${REPOSITORY_URI}:latest"
|
||||||
|
build:
|
||||||
|
commands:
|
||||||
|
- docker build --tag "$IMAGE_URI" .
|
||||||
|
- docker tag "$IMAGE_URI" "$IMAGE_LATEST_URI"
|
||||||
|
post_build:
|
||||||
|
commands:
|
||||||
|
- docker push "$IMAGE_URI"
|
||||||
|
- docker push "$IMAGE_LATEST_URI"
|
||||||
|
- printf '[{"name":"%s","imageUri":"%s"}]' "$IMAGE_NAME" "$IMAGE_LATEST_URI" > images.json
|
||||||
|
artifacts:
|
||||||
|
files: images.json
|
||||||
|
Environment:
|
||||||
|
ComputeType: BUILD_GENERAL1_SMALL
|
||||||
|
Image: aws/codebuild/docker:17.09.0
|
||||||
|
Type: LINUX_CONTAINER
|
||||||
|
EnvironmentVariables:
|
||||||
|
- Name: AWS_DEFAULT_REGION
|
||||||
|
Value: !Ref AWS::Region
|
||||||
|
- Name: REPOSITORY_URI
|
||||||
|
Value: !Ref Image
|
||||||
|
- Name: IMAGE_NAME
|
||||||
|
Value: !Ref AWS::StackName
|
||||||
|
Name: !Ref AWS::StackName
|
||||||
|
ServiceRole: !Ref CodeBuildServiceRole
|
||||||
|
|
||||||
|
Pipeline:
|
||||||
|
Type: AWS::CodePipeline::Pipeline
|
||||||
|
Properties:
|
||||||
|
RoleArn: !GetAtt CodePipelineServiceRole.Arn
|
||||||
|
Name: !Join ['', [!Ref 'AWS::StackName', Pipeline]]
|
||||||
|
ArtifactStore:
|
||||||
|
Type: S3
|
||||||
|
Location: !Ref ArtifactBucket
|
||||||
|
Stages:
|
||||||
|
- Name: Source
|
||||||
|
Actions:
|
||||||
|
- Name: App
|
||||||
|
ActionTypeId:
|
||||||
|
Category: Source
|
||||||
|
Owner: ThirdParty
|
||||||
|
Version: 1
|
||||||
|
Provider: GitHub
|
||||||
|
Configuration:
|
||||||
|
Owner: !Ref GitHubUser
|
||||||
|
Repo: !Ref GitHubRepo
|
||||||
|
Branch: !Ref GitHubBranch
|
||||||
|
OAuthToken: !Ref GitHubToken
|
||||||
|
OutputArtifacts:
|
||||||
|
- Name: App
|
||||||
|
RunOrder: 1
|
||||||
|
- Name: Build
|
||||||
|
Actions:
|
||||||
|
- Name: Build
|
||||||
|
ActionTypeId:
|
||||||
|
Category: Build
|
||||||
|
Owner: AWS
|
||||||
|
Version: 1
|
||||||
|
Provider: CodeBuild
|
||||||
|
Configuration:
|
||||||
|
ProjectName: !Ref CodeBuildProject
|
||||||
|
InputArtifacts:
|
||||||
|
- Name: App
|
||||||
|
OutputArtifacts:
|
||||||
|
- Name: BuildOutput
|
||||||
|
RunOrder: 1
|
||||||
|
- Name: Deploy
|
||||||
|
Actions:
|
||||||
|
- Name: Deploy
|
||||||
|
ActionTypeId:
|
||||||
|
Category: Deploy
|
||||||
|
Owner: AWS
|
||||||
|
Version: 1
|
||||||
|
Provider: ECS
|
||||||
|
Configuration:
|
||||||
|
ClusterName: !Ref Cluster
|
||||||
|
ServiceName: !Ref Service
|
||||||
|
FileName: images.json
|
||||||
|
InputArtifacts:
|
||||||
|
- Name: BuildOutput
|
||||||
|
RunOrder: 1
|
||||||
|
|
||||||
|
# What outputs to expose
|
||||||
|
Outputs:
|
||||||
|
Endpoint:
|
||||||
|
Description: Endpoint
|
||||||
|
Value: !Join ['', ['https://', !Ref DNSRecord]]
|
||||||
|
Service:
|
||||||
|
Value: Service
|
||||||
|
PipelineUrl:
|
||||||
|
Value: !Sub https://console.aws.amazon.com/codepipeline/home?region=${AWS::Region}#/view/${Pipeline}
|
||||||
|
ContainerSecurityGroup:
|
||||||
|
Value: !Ref ContainerSecurityGroup
|
||||||
|
TaskDefinition:
|
||||||
|
Value: !Ref TaskDefinition
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
version: '3.2'
|
||||||
|
|
||||||
|
services:
|
||||||
|
api22:
|
||||||
|
build:
|
||||||
|
context: ./
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: api2.uwsgi.web
|
||||||
|
hostname: api2-uwsgi.local
|
||||||
|
ports:
|
||||||
|
- "1881:80"
|
||||||
|
environment:
|
||||||
|
- SQLALCHEMY_DATABASE_URI=postgresql://fondberg:@docker.for.mac.localhost/photowall
|
||||||
|
- API_KEYS=[]
|
||||||
|
- DEBUG=True
|
||||||
|
# - SQLALCHEMY_TRACK_MODIFICATIONS=True # change in prestart.sh
|
||||||
|
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
external:
|
||||||
|
name: photowall-docker-network
|
||||||
Vendored
+18
-19
@@ -1,24 +1,23 @@
|
|||||||
from fabric.api import *
|
from fabric.api import env, lcd, local, abort
|
||||||
|
|
||||||
env.user = 'ubuntu'
|
def basic_environment_settings():
|
||||||
env.key_filename = '~/.ssh/ukad.pem'
|
env.stack_name = 'api'
|
||||||
|
|
||||||
env.hosts = (
|
def staging():
|
||||||
'ec2-52-50-174-196.eu-west-1.compute.amazonaws.com', #api2-dev
|
basic_environment_settings()
|
||||||
)
|
env.environment = 'staging'
|
||||||
|
|
||||||
|
def production():
|
||||||
|
basic_environment_settings()
|
||||||
|
env.environment = 'production'
|
||||||
|
|
||||||
|
def cloudformation_update():
|
||||||
|
if env.environment != 'staging':
|
||||||
|
abort('Only staging is deployed soo far')
|
||||||
|
with lcd('./cloudformation/'):
|
||||||
|
local('make update-stack ENVIRONMENT_NAME={0} STACK_NAME={1}'.format(env.environment, env.stack_name))
|
||||||
|
|
||||||
def deploy():
|
def deploy():
|
||||||
branch = local('git rev-parse --abbrev-ref HEAD', capture=True)
|
if env.environment != 'staging':
|
||||||
local('git archive --format tar.gz -o /tmp/api.tar.gz {0}'.format(branch), capture=False)
|
abort('Local deploy to staging only. Production deploy is automatic when merging to master.')
|
||||||
put('/tmp/api.tar.gz', '/tmp/api.tar.gz')
|
local('make publish-to-staging')
|
||||||
with warn_only():
|
|
||||||
sudo('service nginx stop')
|
|
||||||
sudo('service api-uwsgi stop')
|
|
||||||
with cd('/srv/api'):
|
|
||||||
run('tar xzf /tmp/api.tar.gz')
|
|
||||||
run('rm /tmp/api.tar.gz')
|
|
||||||
with warn_only():
|
|
||||||
sudo('service api-uwsgi start')
|
|
||||||
sudo('service nginx start')
|
|
||||||
local('rm /tmp/api.tar.gz')
|
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
echo "SQLALCHEMY_DATABASE_URI = '$SQLALCHEMY_DATABASE_URI'" > /app/config.py
|
||||||
|
echo "SQLALCHEMY_TRACK_MODIFICATIONS = True" >> /app/config.py
|
||||||
|
echo "API_KEYS = $API_KEYS" >> /app/config.py
|
||||||
|
echo "BERNARD_QUEUE_URL = '$BERNARD_QUEUE_URL'" >> /app/config.py
|
||||||
|
|
||||||
|
if [ -z "$DEBUG" ]
|
||||||
|
then
|
||||||
|
echo "DEBUG = False" >> /app/config.py
|
||||||
|
else
|
||||||
|
echo "DEBUG = True" >> /app/config.py
|
||||||
|
echo "SQLALCHEMY_ENGINE_OPTIONS = {" >> /app/config.py
|
||||||
|
echo ' "pool_pre_ping": True,' >> /app/config.py
|
||||||
|
echo ' "pool_recycle": 300,' >> /app/config.py
|
||||||
|
echo '} ' >> /app/config.py
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user