Deploying a Django webapp: ECS with AWS Copilot vs. EC2 with Kamal/Terraform

TL;DR Link to heading

Coming from Kubernetes, my expectations were high for ECS + Fargate to be an “easy way” to deploy stuff. I found ECS to be surprisingly complex, disappointingly slow to deploy to, and ultimately not worth the price/performance tradeoff for getting a more ‘managed’ service.

The alternative of spinning up an ARM-based t4g.small EC2 instance and deploying to it with Kamal was approximately half the price, came with better performance, and was significantly faster to deploy to. (And without any cloud vendor lock-in!)

Given this experience, in the future I’d go for plain VMs and Kamal wherever possible - and where more managed alternatives or a higher number of VMs are needed, I would directly go to Kubernetes.

Context Link to heading

In a recent project I’ve been worked on a Django-based webapp and was faced with the decision on how to get it ’live’ on cloud infrastructure. Having worked with Kubernetes a fair bit, that approach would undoubtedly have worked here, though it does introduce a lot of moving part and adds complexity to the overall application landscape.

I had heard good things about ECS as the “easy alternative to kubernetes” and wanted to give that a try. I had also had come across the very popular article from 37signals on why they left the cloud and their internally-developed-now-open-source tool kamal (previously called MRSK), which I also was interested in testing out.

Some basic requirements for this deployment include:

  • Django-based webapp, where the deployment needs:
    • Main container to run the app
    • Worker containers running the same image but with a different startup command
    • Redis as cache and job queue
    • Postgres as database
  • All infra must be on AWS
  • All infra must either as-code or controlled by a tool like AWS copilot
  • Ability to deploy from local machine to target infra with a single command
  • Logs must be collected in CloudWatch

Metrics that matter:

  • Deployment speed: The time taken to push a change from local environment to live infra
  • Ability to easily stop and bring up the costly parts of created resources
  • Overall running cost

ECS and AWS Copilot Link to heading

AWS Copilot is an open source CLI that makes deploying containerised apps on AWS ECS and AWS App Runner very straightforward, similar to what you may expect from modern infra/CD companies like Railway and Render.

After some initialisation work, copilot deploy is all you need to do to get your container up on ECS.

EC2 (Terraform IAC), deployments with Kamal Link to heading

While this alternative does mean creating Terraform scripts to create infrastructure, using community modules like this one for EC2 make things a lot easier.

Once the VM itself is up and running, Kamal works pretty much the same as Copilot - kamal deploy and your app is live after some time.

Comparison Link to heading

The below table summarises my experiences in brief though note that this definitely isn’t a scientific comparison. More ⭐ stars ⭐ the better.

AreaECS & CopilotEC2 & Terraform + Kamal
Infra: understanding required
Chances are you will need to go beyond Copilot’s small scope of supported pre-configured services. The moment you need an add-on, you need to understand most of what Copilot is doing at the back, negating the benefits in real-world use.

No escape, all infra is on you. Use community modules to manage less code yourself.
Infra: code you need to manage⭐⭐
Only ‘add-ons’ like RDS that Copilot doesn’t support natively, and they must be CloudFormation. The app itself and supporting services (e.g. Redis) don’t need any additional infra code.

You manage everything in a language of your choice. Terraform community modules make this quite easy.
Infra: effort to integrate CloudWatch logging⭐⭐⭐
Out of the box
⭐⭐
Add IAM role to the EC2 instance and ~3 lines of config.
Deployment speed:
(single ~600mb container)

5-10 minutes, large variance
⭐⭐⭐
~60-80 seconds
User experience: App performance
(feeling, initial page load)

Slow
⭐⭐⭐
Fast
Cost: Approx monthly resource cost⭐⭐
~36 USD per month (1 vCPU, 2gb RAM)
⭐⭐⭐⭐
~15 USD per month (t4g.small)

Note on costs Link to heading

The resource costs in the table are just for main compute, the actual amounts are likely to be significantly higher with ECS Fargate. (which should not come as a surprise given it’s ‘serverless’ nature)

For example, a Celery worker container at small scale can easily sit in the same VM as the webserver, and so can Redis. With Kamal I can deploy all three to the same VM; with ECS Fargate I would pay for 2 more containers, tripling the overall cost.