From 3a9dd3c6e7c4ae1d5fc49b34804d31209997bb8b Mon Sep 17 00:00:00 2001 From: Marc Burgess Date: Fri, 20 Mar 2020 11:35:18 +1300 Subject: [PATCH] Ci cd/deploy to aws (#112) * Added dockerfile and AWS ECS deployment workflow * Added a simple release workflow * Fixed yaml for create-release * Updated dockerfile node image to try fix uid/gid issue * Fixed release workflow to stop it triggering on all master pushes * Changed AWS region to ap-southeast-2 * Fixed task def path * Changed task def to run nginx * Fixed command (missing quotes) * Added full CherryPy server to dockerfile * Updated ECS task definition command and image --- .dockerignore | 1 + .github/workflows/aws-ecr-deployment.yml | 80 ++++++++++++++++ .github/workflows/create-release.yml | 29 ++++++ .github/workflows/taskDef.json | 112 +++++++++++++++++++++++ Dockerfile | 20 ++++ 5 files changed, 242 insertions(+) create mode 100644 .dockerignore create mode 100644 .github/workflows/aws-ecr-deployment.yml create mode 100644 .github/workflows/create-release.yml create mode 100644 .github/workflows/taskDef.json create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..600e365 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +**/node_modules \ No newline at end of file diff --git a/.github/workflows/aws-ecr-deployment.yml b/.github/workflows/aws-ecr-deployment.yml new file mode 100644 index 0000000..c8c9cb3 --- /dev/null +++ b/.github/workflows/aws-ecr-deployment.yml @@ -0,0 +1,80 @@ +# 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 a release is created +# +# 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 `ECR_REPOSITORY` in the workflow below with your repository's name. +# Replace the value of `aws-region` 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 values for `service` and `cluster` in the workflow below with your service and cluster names. +# +# 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 `task-definition` in the workflow below with your JSON file's name. +# Replace the value of `container-name` 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. + +on: + release: + types: [created] + +name: Deploy to Amazon ECS + +jobs: + deploy: + name: Deploy + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - 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: ap-southeast-2 + + - 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 }} + ECR_REPOSITORY: se701-g1-a1 + 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: ./.github/workflows/taskDef.json + container-name: split + 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: split-app-service + cluster: default + wait-for-service-stability: true diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml new file mode 100644 index 0000000..4ff4690 --- /dev/null +++ b/.github/workflows/create-release.yml @@ -0,0 +1,29 @@ +on: + push: + tags: + - "v*" # Push events to matching v*, i.e. v1.0, v20.15.10 + +name: Create Release + +jobs: + build: + if: github.event.base_ref == 'refs/heads/master' + name: Create Release + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@master + - name: Create Release + id: create_release + uses: actions/create-release@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + body: | + Changes in this Release + - First Change + - Second Change + draft: false + prerelease: false diff --git a/.github/workflows/taskDef.json b/.github/workflows/taskDef.json new file mode 100644 index 0000000..14d168b --- /dev/null +++ b/.github/workflows/taskDef.json @@ -0,0 +1,112 @@ +{ + "ipcMode": null, + "executionRoleArn": "arn:aws:iam::902753724065:role/ecsTaskExecutionRole", + "containerDefinitions": [ + { + "dnsSearchDomains": null, + "logConfiguration": { + "logDriver": "awslogs", + "secretOptions": null, + "options": { + "awslogs-group": "/ecs/first-run-task-definition", + "awslogs-region": "ap-southeast-2", + "awslogs-stream-prefix": "ecs" + } + }, + "entryPoint": ["sh", "-c"], + "portMappings": [ + { + "hostPort": 80, + "protocol": "tcp", + "containerPort": 80 + } + ], + "command": ["python3 /app/main.py"], + "linuxParameters": null, + "cpu": 256, + "environment": [], + "resourceRequirements": null, + "ulimits": null, + "dnsServers": null, + "mountPoints": [], + "workingDirectory": null, + "secrets": null, + "dockerSecurityOptions": null, + "memory": null, + "memoryReservation": 512, + "volumesFrom": [], + "stopTimeout": null, + "image": "python:3.9.0a4-buster", + "startTimeout": null, + "firelensConfiguration": null, + "dependsOn": null, + "disableNetworking": null, + "interactive": null, + "healthCheck": null, + "essential": true, + "links": [], + "hostname": null, + "extraHosts": null, + "pseudoTerminal": null, + "user": null, + "readonlyRootFilesystem": null, + "dockerLabels": null, + "systemControls": null, + "privileged": null, + "name": "split" + } + ], + "placementConstraints": [], + "memory": "512", + "taskRoleArn": null, + "compatibilities": ["EC2", "FARGATE"], + "taskDefinitionArn": "arn:aws:ecs:ap-southeast-2:902753724065:task-definition/first-run-task-definition:1", + "family": "first-run-task-definition", + "requiresAttributes": [ + { + "targetId": null, + "targetType": null, + "value": null, + "name": "com.amazonaws.ecs.capability.logging-driver.awslogs" + }, + { + "targetId": null, + "targetType": null, + "value": null, + "name": "ecs.capability.execution-role-awslogs" + }, + { + "targetId": null, + "targetType": null, + "value": null, + "name": "com.amazonaws.ecs.capability.docker-remote-api.1.19" + }, + { + "targetId": null, + "targetType": null, + "value": null, + "name": "com.amazonaws.ecs.capability.docker-remote-api.1.21" + }, + { + "targetId": null, + "targetType": null, + "value": null, + "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18" + }, + { + "targetId": null, + "targetType": null, + "value": null, + "name": "ecs.capability.task-eni" + } + ], + "pidMode": null, + "requiresCompatibilities": ["FARGATE"], + "networkMode": "awsvpc", + "cpu": "256", + "revision": 1, + "status": "ACTIVE", + "inferenceAccelerators": null, + "proxyConfiguration": null, + "volumes": [] +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c886ebc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +# build environment +FROM node:12.16.1-alpine as build +WORKDIR /app +ENV PATH /app/node_modules/.bin:$PATH +COPY ./split-webapp/split/package.json /app/package.json +RUN npm install +RUN npm install react-scripts@3.0.1 -g +COPY ./split-webapp/split /app +RUN npm run build + +# production environment +FROM python:3.9.0a4-buster +WORKDIR /app +ENV SITE_ROOT ./static +ENV SITE_PORT 80 +RUN pip install cherrypy +COPY ./server/src /app +COPY --from=build /app/build /app/static +EXPOSE 80 +CMD ["python3", "/app/main.py"] \ No newline at end of file