Deploying a Swift API on AWS Elastic Container Service with CodePipeline
Tags: swift, swiftonserver, aws
Published: 2021-12-14 00:00:00

---
cover_image: 'https://zentered.co/images/articles/2021-12/built-on-aws.jpg'
date: '2021-12-14T00:00:00.000Z'
created_at: '2021-12-14T00:00:00.000Z'
edited_at: '2021-12-27T00:00:00.000Z'
crossposted_at: '2021-12-27T12:15:15.870Z'
---

## Motivation

After [getting started with Swift on Server](https://zentered.co/articles/getting-started-with-swift-server/) and [deploying a Swift on Server API on Google Cloud Run with Google Cloud Build](https://zentered.co/articles/deploying-swift-api-on-google-cloud/), we wanted to see how to get the Swift API running on Amazon Web Services (AWS). AWS offers a lot more products and flexibility, which comes at the cost of simplicity, so we created a new [Terraform](https://www.terraform.io) project to consistently re-create the environment. Here's an overview of the puzzle pieces roughly in order:

- **CodeCommit** as a mirror of the GitHub repo
- **CodeBuild** to build the Docker image and push it to the registry
- **CodeDeploy** to orchestrate the deployment and traffic allocation to ECS
- **CodePipeline** to glue Commit, Build and Deploy together in a nice deployment pipeline
- **Elastic Container Registry (ECR)** to store the Docker images
- **Elastic Container Service (ECS)** to run Docker containers
- **Elastic Application Load Balancer (ABN)** to manage the traffic between instances and allow "Blue/Green Deployment"
- and a few more 3-letter acronyms and other AWS products like KMS, IAM, S3, CloudWatch...

![diagram showing the above mentioned AWS products](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zh6nsx5fvozoiasm5uzd.png)
 

Please mind the `/api` folder. For prototyping we've decided to work in a single repo, while the server bits are stored in the `/api` subfolder (which makes things again a little more difficult, as this needs to be specified in various places).

## TLDR; Mistakes made, 🤦 and lessons learned

You can find our [Terraform project on GitHub](https://github.com/zentered/terraform-ecs-blue-green-pipeline)

- for ECS Blue/Green builds, the "image definition" is not "imagedefinitions.json" but `imageDetail.json`: `- printf '{"ImageURI":"%s"}' ${REPOSITORY_URI}:latest} > imageDetail.json`
- to deploy from CodePipeline to ECS, the "blue/green" strategy is required
- CodePipeline uses S3 to pass build artifacts from one step to the next
- a `taskdef.json` and `appspec.yaml` are necessary build artifacts from the build to the deploy step
- it's `appspec.yaml` (y**a**ml with the 'a') not `appspec.yml`
- Docker container port (ie `8080`) is used everywhere except for the Load Balancer _Listener_
- `Fargate` requires network mode `awsvpc` and public IPs, or private IPs and a lot more configuration with firewalls, networks etc.
- IAM permissions are a mess
- `snake_case` should be used for all Terraform names

## Getting down to the nitty gritty

Setting up this project was all but smooth. There are a lot of little details and a single wrong number can cost you hours of debugging. The AWS error messages are misleading, the user/developer experience a mess, each of the products uses different UIs, all in all very chaotic. At least with Terraform we're able to write "Infrastructure as Code" and provide a working Terraform project that you can use as a starting point. Some product specific information first:

### AWS CodeCommit

`CodeBuild` uses GitHub OAuth, which gives Amazon access to all public and private repos. We're a little paranoid, so that's not something we wanted to do. Instead, we created a CodeCommit repo and push the changes there, until AWS switches to the new GitHub App experience, which lets you choose individual repos.

In order to push to CodeBuild, you need to add your ssh public key to your IAM user and add CodeCommit origin to your `git config`:

- CodeCommit setup: https://docs.aws.amazon.com/codecommit/latest/userguide/setting-up-ssh-unixes.html?icmpid=docs_acc_console_connect_np
- IAM console "security credentials": https://console.aws.amazon.com/iam/home#/users/?section=security_credentials

You can probably skip this with the [AWS Connector for GitHub](https://docs.aws.amazon.com/codepipeline/latest/userguide/connections-github.html) where you can connect a GitHub Repo as Source in the Pipeline. We're still working that out with Terraform.

### AWS CodeBuild

CodeBuild was one of the easier tools to use. Just add your `buildspec.yml`. Important are the build artifacts that are exported to S3 and used by the deploy step.

### Elastic Container Registry & Elastic Container Service (ECS)

To get a head start for your builds, you can push your `latest` image to ECR:

```
aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <account_id>.dkr.ecr.<region>.amazonaws.com
docker push <account_id>.dkr.ecr.<region>.amazonaws.com/<image>:latest
```

ECS was the worst part to get up and running, since there are a lot of different components playing together. There are containers, tasks, services, task definitions, image definitions and more. If you encounter any issues, it's worth looking into the service, then tasks, to see if the container boots up correctly.

## Let's Deploy

We've published the entire Terraform project here: [Terraform ECS Blue/Green Deployments with CodePipeline](https://github.com/zentered/terraform-ecs-blue-green-pipeline). You need to [download the Terraform CLI](https://www.terraform.io/downloads.html). If you're new to AWS and you don't have the AWS CLI installed, you can find [instructions here](https://aws.amazon.com/cli/).

```
terraform init
terraform validate
terraform plan
terraform apply
```

Terraform outputs the url of the load balancer, you should be able to navigate to that URL and get the 'hello world' response.

### Clean up:

```
terraform destroy
```

Feel free to fork/clone the repo and adjust it to your needs.

## Summary

AWS comes with a lot of benefits and great features, but the UI across the products is inconsistent and there are dozens of configuration options, permissions and other things to take care of and its easy to miss an important detail. Setting up the project in Terraform makes things a little easier, but it still takes time to write down all the configs. There are some pre-built Terraform modules for AWS which we didn't use, as we wanted to learn how things worked under the hood. In comparison, [deployment to GCP](https://zentered.co/articles/deploying-swift-api-on-google-cloud/) was definitely a lot easier and faster to set things up. On GCP there are a lot of "beta" products though and things can change, or sometimes don't work as expected.

## Special thanks and further reading ...

Special thanks to "vinycoolguy2015", "snow-dev" and "capital one" for their articles and resources on the topic. Here's a list of links to articles and repos that helped put together this project:

- https://github.com/vinycoolguy2015/awslambda/tree/master/terraform_ecs_bluegreen
- https://github.com/aws-samples/amazon-ecs-fullstack-app-terraform
- https://snow-dev.com/posts/ecs-cd-with-codepipeline-in-terraform.html
- https://github.com/snowiow/green-blue-ecs-example/blob/master/buildspec.yml
- https://docs.aws.amazon.com/codepipeline/latest/userguide/ecs-cd-pipeline.html
- https://medium.com/capital-one-tech/seamless-blue-green-deployment-using-aws-codedeploy-4c36c0bbeef4
- https://github.com/flexelem/aws-samples/tree/master/nodejs-codepipeline

Thanks for reading! You can [check out all the code on GitHub](https://github.com/zentered/terraform-ecs-blue-green-pipeline) and read more about our "Swift on Server" series:

- [Deploying a Swift API on Google Cloud Run with Google Cloud Build](https://zentered.co/articles/deploying-swift-api-on-google-cloud/)
- [Getting Started with Swift on Server](https://zentered.co/articles/getting-started-with-swift-server/)

If you have any questions or comments, please [reach out on Twitter](https://twitter.com/zenteredco) or [start a discussion on GitHub](https://github.com/zentered/zentered/discussions/new?category=ideas-feedback).