Project 6: Deployment¶
Learning Goals¶
- Learn how to package an application for deployment to the cloud.
- Learn how to deploy a frontend and backend application to Amazon Web Services (AWS)
- Learn how to automate deployment using GitHub continuous deployment.
Project Context¶
In P1, you defined requirements and user stories. In P2, you expanded some of those stories into detailed development specifications. In P3, you implemented two user stories for the front end of your application. In P4, you implemented two dev specs for the back end of your application. In P5, you wrote unit tests for two core frontend and two core backend files/classes. In P6, you will deploy the frontend and backend of your application to AWS.
By the end of this sprint, you will set up a publicly visible deployment of your application. You will then automate deployment so that every time you commit code to your repository, GitHub will run the test cases and if successful, will deploy the updated application to AWS.
Remember to use the LLMs as much as possible to generate your deliverables. You may not modify any generated code directly, only by prompting the LLM. You should use formalized LLM prompts, such as those we introduced in class. These will make the LLM output more reliable.
Deliverables¶
You will begin by setting up your AWS account. You will need AWS access for all steps of this project.
None of the steps in P6 should cost you any money, however the AWS account setup will likely require a credit card to be charged in case you incur any costs. Be assured that whenever we've done this before, we've spent at most 20-30 cents total. If you find that AWS has billed you anywhere near USD $1, immediately turn off any applications you have already deployed and reach out to the instructors for help.
Next, you will set up your application to run with AWS Lambda. AWS Lambda lets you run server code without having to deal with actual server machines. It's a "serverless" computing service. You will modify your backend to run on AWS Lambda.
Your backend should publish its public interfaces via REST API. You will use AWS API Gateway to expose your public endpoints for web users (or applications) to interact with.
Next, you will use AWS Amplify to host your frontend application. Amplify will store and serve static web assets, like HTML, CSS, and JS files, that comprise your application frontend.
Note
If you are building a VS Code Extension, you will deploy your frontend to the VS Code Extension Marketplace.
Now is the time to implement integration tests. These are tests that exercise the frontend to backend (and vice versa) code paths in your app. You will learn to run these integration tests on localhost and in the cloud and run them on every checkin.
At the end, you will set up GitHub actions to deploy your frontend code to Amplify and your backend code to Lambda after each pull request has been approved.
1. Create an AWS account¶
Go to the AWS Console and create an account. If one person on your team already has an AWS account, you can use that one. Log into the AWS Console with your new account.
2. Use AWS Lambda to run your backend code¶
To use Lambda, you will
- Write (slightly stylized) code that executes functions on certain events (e.g., the invocation of a given REST endpoint)
- Package up your code (i.e., put it all in a ZIP file)
- Upload the packaged code to AWS
Ask your LLM to modify your backend code so that it executes as a lambda function. Eventually, that lambda function will execute when your REST API's public interface endpoints receive post requests. To start with, though, you should become familiar with Lambda, then package up your Lambda code, deploy it, and make sure you can invoke it using the AWS command-line interface (CLI).
1. Use the AWS console to experiment with Lambda¶
Ask your LLM for detailed instructions on how to use AWS Lambda to set up a dummy application that you can invoke. This will help you get familiar with AWS Lambda when you have to set up your own application. If ChatGPT proves unhelpful, read the official AWS documentation.
2. Package and invoke your Lambda code using the AWS CLI¶
Ask your LLM to teach you how to package your Javascript code for deployment on AWS and upload it with the AWS CLI. If ChatGPT is unhelpful, you can read the official AWS documentation. There is some additional documentation in the Lambda section of the official AWS API Gateway tutorial.
3. Integrate your Lambda code with the REST API¶
Ask your LLM to teach you how to modify the Lambda code so that it is invoked by requests to your API's public interface functions. If ChatGPT is not helpful, read the Lambda section of the official AWS API Gateway tutorial.
3. Use API Gateway to create a REST API¶
AWS API Gateway makes it simple to spin up an API. A web API exposes endpoints that users (or applications) can interact with. You are going to create a REST API for the backend of your app that exposes all of your public interfaces functions.
Ask your LLM to teach you how to create your REST API with AWS API Gateway. If ChatGPT is unhelpful, read through this tutorial.
After setting up AWS API Gateway, locate the API call logic in your frontend code (where it currently calls localhost). Replace the localhost URL with the API Gateway endpoint URL. Note, edit the code carefully to preserve a version of the app that runs locally for easier testing.
4. Host your frontend code¶
AWS Amplify makes it easy to e.g., deploy app frontends and integrate with version control. In this assignment, you will use Amplify to manage deployment of the frontend of your calculator application.
Your task is to set up Amplify to host the application frontend.
To complete this part of the assignment, refer to the AWS Amplify tutorial for deploying a web application by connecting Amplify to your GitHub repository.
If you are building a VS Code Extension, do not follow the AWS Amplify directions. Instead, you will deploy the frontend of your extension to the VS Code Extension Marketplace. To complete this deployment, you will follow these instructions. First, install the vsce command line tool, create an Azure DevOps personal access token, define your team as a publisher, and publish your extension. Make sure to say that the cost of your extension is USD $0.
Be sure to have your LLM do all this work for you!
Note
When this course is over, please remember to unpublish your extension from the VS Code Extension Marketplace.
5. Integration testing¶
Ask your LLM to write an English-language test specification for the code pathways that require the execution of frontend and backend code together. Each specification should contain a list of all functionality that needs to be tested, followed by a table of tests. Each row of the table should describe the purpose of the test, the test inputs to the function, and the test output that is expected if the test passes. You must write at least one integration test for every code pathway that spans frontend and backend functionality.
Generate integration tests for each row of your test specification using your LLM.
Test out your full app on your local machine first. Run your npm scripts to setup and start the frontend and backend of your application on localhost, then execute the integration tests with your testing framework.
Note
Some integrations tests will fail when run on localhost, but work fine when deployed on the Internet. Please take a note of these and condition their execution to run only when deployed in the desired environment.
Finally, create a new test configuration that uses the URLs of the deployed frontend and backend hosted by the AWS Cloud. Rerun your integration tests on your deployed app and fix any bugs that pop up until the entire app is working as desired.
6. Automate your integration tests¶
Ask your LLM to create a new GitHub Action that runs your integration tests on every commit. Store the YAML workflow file in the .github/workflows directory. Name it run-integration-tests.yml. It should check out your code, set up the application environment for frontend and backend (e.g., install Node.js if needed), install dependencies, and then execute your tests.
- For CI instructions to run tests with Jest, check out Dennis O'Keefe's blog.
- For CI instructions with VS Code extensions, check out these instructions.
Check in your YAML file to the GitHub repository.
Ask your LLM to test out your CI code by making a change to one of the source code files in the frontend and one backend source code file. Commit the change to Git, push to the remote repository, create a pull request on GitHub, and accept the pull request. Finally, go to the GitHub repository on the web and click on the Actions tab on the navigation bar. You'll see all the workflows on the left and workflow runs on the right. If you have a green checkmark next to a workflow run, that means it worked! If there is a red cross, then it did not. Click on the workflow run to see exactly what got executed in GitHub's "terminal window" and find out what went wrong. Fix the problem and try again until each of your two GitHub actions run successfully.
7. Adopt good GitHub hygiene¶
Git is a very powerful and flexible version control system. One best practice you will follow is to create a new feature branch whenever you start working on a new coding task. Never work directly on the main branch. When your feature is done and your CI GitHub Actions (unit tests and integration tests) have passed their tests, create a pull request on GitHub to push the changes from the feature branch to main.
As configured by default, anyone with access to your repo can push whatever garbage they want to the main branch. That's not good! It's important to make sure code that actually gets deployed has been thoroughly tested and reviewed (to catch everything from mistakes to intentional back doors!). In this assignment, you must block merges to main until your code is reviewed and passes CI.
To protect your main branch, navigate to the Settings tab in your GitHub repo and click on Branches (on the lefthand side). You'll see two options: (1) Add branch ruleset and (2) Add classic branch protection rule. Add a classic branch protection rule that protects main from direct, unreviewed commits: first check the box to require a pull request before merging and second check the box to require status checks to pass before merging. Select your CI testing workflows here as the relevant status checks. Finally,
8. Use Github actions to automatically deploy on each push to main¶
After getting hands on experience with each service, you will use a Github action to deploy updates automatically on each push to your main branch.
The CD pipeline will perform the following tasks:
- Deploy the packaged backend Lambda code.
- Redeploy the frontend (to Amplify or the VS Code Extension Marketplace).
In order to do this, you will need to allow Github to authenticate to AWS. Follow the Github documentation to safely use your AWS secrets in CD. This AWS blog post describes some (basic) best practices for generating and handling AWS authentication secrets in CI; navigate to the "Configuring AWS credentials in GitHub" section of the tutorial.
Deploying backend code¶
Your LLM should create a Github workflow named deploy-aws-lambda.yml that takes the follow steps:
- Checks out the code, sets up Node, and installs dependencies.
- Packages the code for lambda deployment.
- Uses the AWS CLI to update the lambda code (giving the CLI access to your authentication secret and AWS region through the environment).
Deploying frontend code¶
Your LLM should create a Github workflow named deploy-aws-amplify.yml that takes the following steps:
- Checks out the code, sets up Node, and builds the code.
- Triggers AWS Amplify to redeploy the latest frontend version from your repository. See the AWS documentation for more.
If you are publishing a VS Code Extension, your workflow will be named deploy-extension.yml. It should simply package up your extension and publish it to the marketplace.
9. Wrap it up¶
Edit the README.md file for your project.
- Provide instructions for web users of your app to run your application.
- Provide all the instructions needed for a random person on the Internet who forks your codebase to set up AWS to deploy your application.
10. Reflection¶
Without your LLM, write a 500-word (i.e., one-page) reflection on:
- How effective was the LLM in helping you understand how to deploy your app? What did you like about it? What was wrong with it? How many times did you have to change your prompt to get it to explain the information in a way you could understand?
- How difficult was it to change habits and stop committing directly to main? Did you have to ask your team to change their practices to ensure minimal delays for accepting your pull requests? How do you feel about this feature branch practice? What are the pros and cons?
Turn-in Instructions¶
Please turn in a single document that contains these parts:
- Deploy your app. Keep it deployed until the instructors let you know that they've checked this part out.
- Provide a link to your Amplify frontend deployment or VS Code Extension Marketplace extension URL.
- Provide a link to your Lambda backend REST function.
- The integration test specification.
- Provide a Git repository link to the test code files that implement your integration test specs.
- Copy-paste in the test output from running your integration tests on localhost.
- Copy-paste in the test output from running your integration tests in the cloud.
- Provide a Git repository link to your run-integration-tests.yml file.
- Provide a Git repository link to your deploy-aws-amplify.yml file (or deploy-extension.yml as appropriate).
- Provide a Git repository link to your deploy-aws-lambda.yml file.
- Provide a link to your project's README in GitHub.
- A 1-page reflection as in the Reflection section.
- Copy-paste logs of all LLM interactions you used during this sprint. Identify the name and version of the LLM used.