Hosting and CI - Teknikio/pxt-teknikio GitHub Wiki

This project contains Teknikio MakeCode project that is deployed to ECS via CircleCI using Docker containers.

Requirements

Environment Variables

  AWS_ACCOUNT_ID .       = ''
  AWS_ACCESS_KEY_ID      = ''
  AWS_SECRET_ACCESS_KEY  = ''
  AWS_RESOURCE_PREFIX    = "pxt-teknikio"

AWS Setup

  • Install AWS CLI

    pip3 install awscli --upgrade --user
    
  • Configure AWS, run the following and follow the steps

    aws configure 
    
  • APPLICATION_ID, APPLICATION_SECRET are generated when an access key is created. Take care of these, and never commit or post.

Creating a Dockerfile

This Docker image must load all environment dependencies, compile the project and specify a launch command for services.

  • Install Docker

  • All docker files must start with FROM, importing Base image.

  • The unzip commands are Play! specific, copying project plugins definitions to root location

    FROM node:10-stretch
    
    # ~~~ Environment vars
    ENV NODE_ENV production
    ENV PORT 3232
    # ~~~
    
    # ~~~ Bundle app source
    WORKDIR /usr/src/app/tmp
    COPY . ./
    # ~~~
    
    # ~~~ Install app dependencies & create static build package & clean up
    RUN npm install -g pxt \
      && npm install -g http-server \
      && npm install \
      && pxt staticpkg \
      && mv built/packaged/* /usr/src/app \
      && rm -rf /usr/src/app/tmp
    # ~~~
    
  • Most critical part is specifying the proper entry point to run the application. We do not want to use pxt serve for remote environments, and simple want to host static output

    # ~~~ Expose the port from this container
    EXPOSE ${PORT}
    # ~~~
    
    # ~~~ Load static package running web server
    WORKDIR /usr/src/app
    ENTRYPOINT ["http-server", "-c-1", "."]
    # ~~~
    

Building, running and deploying Docker images to ECR

  • Create an example ECR repository to hold (for the purposes of the next couple of steps)

    aws ecr create-repository --repository-name pxt-teknikio-scala
    
  • Build local Docker image an example ECR repository to hold

    docker build -t pxt-teknikio .
    
  • Run the docker file

    docker run -p 3232:3232 pxt-teknikio:latest
    
  • Tag the local Docker image

    docker tag pxt-teknikio:latest ${REPOSITORY_URL}/pxt-teknikio:latest
    
  • Push this Docker image to ECR

    $(aws ecr get-login --no-include-email --region us-east-2)
    docker push ${REPOSITORY_URL}/pxt-teknikio:latest
    

CircleCI

  • Project configuration

    Environment Variables
    
    AWS_ACCESS_KEY_ID	        xxxxIQZQ	
    AWS_ACCOUNT_ID	        xxxx6476	
    AWS_DEFAULT_REGION	xxxxst-2	
    AWS_ECR_ACCOUNT_URL	xxxx.com	
    AWS_RESOURCE_NAME_PREFIX	xxxxikio	 
    AWS_SECRET_ACCESS_KEY	xxxxORGh
    
  • Using Orbs - Simplify configs by leveraging circleci built in and community orbs, with discretion

    version: 2.1
    machine:
    timezone: UTC
    java:
        version: oraclejdk11
    orbs:
       aws-ecr: circleci/[email protected]
       aws-ecs: circleci/[email protected]
    

Workflow

  2. Build and push docker image
  3. Update AWS Service
  • Build and push docker image Attaching to workspace is key to pick up our output from previous step, we do not want a fresh checkout

    - aws-ecr/build_and_push_image:
        account-url: AWS_ECR_ACCOUNT_URL
        aws-access-key-id: AWS_ACCESS_KEY_ID
        aws-secret-access-key: AWS_SECRET_ACCESS_KEY
        repo: "${AWS_RESOURCE_NAME_PREFIX}-${AWS_RESOURCE_NAME_SUFFIX}"
        region: AWS_DEFAULT_REGION
        tag: "${CIRCLE_SHA1}"
        attach-workspace: true
        workspace-root: ~/project
        checkout: false
    
  • Update ECS service

    - aws-ecs/deploy-service-update:
        family: "${AWS_RESOURCE_NAME_PREFIX}-service-${AWS_RESOURCE_NAME_SUFFIX}"
        cluster-name: "${AWS_RESOURCE_NAME_PREFIX}-cluster-${AWS_RESOURCE_NAME_SUFFIX}"
        container-image-name-updates: "container=${AWS_RESOURCE_NAME_PREFIX}-service-${AWS_RESOURCE_NAME_SUFFIX},image-and- tag=${AWS_ECR_ACCOUNT_URL}/${AWS_RESOURCE_NAME_PREFIX}-${AWS_RESOURCE_NAME_SUFFIX}:${CIRCLE_SHA1}"
      verify-revision-is-deployed: true
    
  • Reference CircleCI config

AWS Stack & CloudFormations

CloudFormations

  • In this example Cloudformation stacks consist of two Clusters, one that is running EC2 capabilities, and one that is running on FARGATE capabilities

  • FARGATE clusters are reserved for Production and Staging environments whereas EC2 clusters are used for integration and sandbox environments where instance access can serve useful.

  • Templates

Terraform

  • Install Terraform and add to PATH

  • variables.tf

    variable "aws_access_key" {}
    variable "aws_secret_key" {}
    variable "aws_account_id" {}
    variable "aws_region" {
      description = "AWS region e.g. us-east-1 (Please specify a region supported by the Fargate launch type)"
    }
    variable "aws_resource_prefix" {
      description = "Prefix to be used in the naming of some of the created AWS resources e.g. demo-webapp"
    }
    
  • To build stack

    terraform init
    terraform plan
    terraform apply
    
  • Reference terraform CircleCI config

Troubleshooting

Further Reading