URL Shortener with Rust, Svelte, & AWS (6/): Deploying to AWS
Tags: rust, svelte, aws, docker
Published: 2021-10-08 15:31:31

In the last post, we created a static front-end application with [Svelte](https://svelte.dev/) + [Bulma](https://bulma.io/), and then integrated it into our Rust code + Dockerfile. In this final post, we will cover the process of actually deploying the app to [AWS Elastic Beanstalk](https://aws.amazon.com/elasticbeanstalk/).

### What is Elastic Beanstalk?

Elastic Beanstalk is a service provided by AWS which enables developers to focus purely on application code, without worrying about the infrastructure the code is being run on. Although we won't be exploring the full power of EB, it is capable of capacity provisioning, load balancing, scaling, and application health monitoring. 

### Manual Deployment

The first step in manually deploying your application is to create a zipped archive of your code to upload to EB. As an effort to stay cross-platform, we will do this using `git archive` (this has the added benefit of automatically ignoring anything in the gitignore).

```sh
git archive --format=zip HEAD -o ./target/repo.zip
```
This will place a zip of our repo into the `target` folder.

Now we have the zip file, you should following the following steps:
1. Login to [AWS Console](console.aws.amazon.com/)
2. Use the search bar to go to the "Elastic Beanstalk" page, and make sure you are in the "Elastic Beanstalk > Environments page"
3. Select your desired region using the dropdown menu in the top right
4. Click the "Create application" button (alternatively, click "Create Environment, and then select "Web server environment")
5. Give your application a suitable name
![AWS console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j53b4wr1bah9x7nkidn5.png)
6. Give the application environment (the collection of services that will run your application) the name "production"
![AWS console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iwhwnllbbxmh6kewvjgs.png)
7. Select the following platform options: 
 ![AWS console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uqv9phv0fqjigtl439ji.png)
8. Upload your zip file, and then click "Create environment"
 ![AWS console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jf3e10lf095kv1t7hqdj.png)

If you go back the environments page, you will see that an environment with the name "production" has been created. It should have the status "Pending" - you will now have to wait around ten minutes for your application to build and startup (EB uses the `docker-compose.yml` file to build the images from scratch on the underlying EC2 instance).

Once the environment health transitions to "Ready", you should be able to go to the provided URL (HTTP *only*, as setting up HTTPS is beyond the scope of this series).

### Creating a Deployment Pipeline

Manually updating your application like this can be time-consuming, so I will now show you how to automatically deploy your code with GitHub Actions.

First, you will need to use the "IAM" service to create a user (so that the workflow can access your AWS account). The user should be called "url-shortener-deploy" and the credential type should be "Programmatic access".

We will be using the [Beanstalk Deploy](https://github.com/marketplace/actions/beanstalk-deploy), which requires the `AWSElasticBeanstalkWebTier` and `AWSElasticBeanstalkManagedUpdatesCustomerRolePolicy` permissions. Make sure to attach these to the IAM role, and then create the user.

Once you have clicked `Create user`, you will be shown a table with the access credentials. You will only be shown these once - don't close the window just yet. In a new tab, open your repo on GitHub and add the following secrets (Settings > Secrets > New repository secret):
 - AWS_ACCESS_KEY_ID
 - AWS_SECRET_ACCESS_KEY
You should set these to the corresponding credentials of your `url-shortener-deploy` user, and then close the credential view on the AWS console.

Next, create a new workflow called `deploy.yml` (this should be in the same directory as `test.yml`). This action will use the secrets we set in the last step to deploy our code to AWS whenever code is pushed to production.

```yml
name: Deploy to AWS
on:
  push:
    branches:
      - production
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Latest Repo
        uses: actions/checkout@master
        with:
          ref: "production"

      - name: Generate Deployment Package
        run: mkdir target && git archive --format=zip HEAD -o ./target/repo.zip

      - name: Get timestamp
        uses: gerred/actions/current-time@master
        id: current-time

      - name: Run string replace
        uses: frabert/replace-string-action@master
        id: format-time
        with:
          pattern: '[:\.]+'
          string: "${{ steps.current-time.outputs.time }}"
          replace-with: "-"
          flags: "g"

      - name: Deploy to EB
        uses: einaregilsson/beanstalk-deploy@v18
        with:
          aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          application_name: url-shortener
          environment_name: production
          version_label: "url-shortener-${{ steps.format-time.outputs.replaced }}"
          region: eu-west-2
          deployment_package: target/repo.zip
```


> Note: The string replacement step simply sets the code version to the current time.

### Testing Auto-Deployment

Now that we have created the workflow, we need to push to the `production` branch. Normally we can do this via a PR on the GitHub web interface, but that only works after we have created and pushed the branch. To do this, use the following git commands:
```sh
git branch production
git push origin production
```
If all goes correctly, your workflow should take about 15 minutes to deploy your code to AWS.

### Now it's your turn!

Now that you have the barebones structure up and running, perhaps you could try adding the following features:
 - persistance with an AWS-provided database (like Aurora or DynamoDB)
 - expiring links, so that a given memory / storage limit isn't exceeded
 - a fully fleshed-out frontend with common pages (such as an FAQ, contact us)
 - a custom domain name + https support for EB

That's all for this series! If you have any issues, make sure to check out the [part-6 tag](https://github.com/mileswatson/url-shortener/tree/part-6) of my repo.

#### Footnote

If you enjoyed reading this, then consider dropping a like or following me:
 - [DEV](https://dev.to/mileswatson)
 - [LinkedIn](https://www.linkedin.com/in/watsonmiles)
 - [Twitter](https://twitter.com/miles__watson)
 - [Github](https://github.com/mileswatson)

I'm just starting out, so the support is greatly appreciated!

*Disclaimer - I'm a (mostly) self-taught programmer, and I use my blog to share things that I've learnt on my journey to becoming a better developer. Because of this, I apologize in advance for any inaccuracies I might have made - criticism and corrections are welcome!*