Migrating from Heroku
Introduction
This guide describes how to migrate your application running on Heroku to AWS using Stacktape. Using Stacktape, you can deploy your web services and databases similarly to deploying them on Heroku. Main reason for using AWS instead of Heroku are:
- Save on the bill - AWS can be a lot cheaper compared to Heroku
- your own VPC (private network) out of the box,
- broader support of resources (containers, lambda functions, batch jobs, dynamo...).
It is possible to continue using other Heroku add-ons while your app is running on AWS by copying over the appropriate
environment variables — e.g., if you are using Heroku’s Sendgrid add-on, set SENDGRID_USERNAME
and SENDGRID_PASSWORD
in your service environment variables.
Prerequisites
- You should have a Stacktape account. If you do not have a Stacktape account, create one here.
- You should have an AWS account connected to your Stacktape organization. Refer to this tutorial to see how to connect your AWS account.
Concepts mapping
The following table explains how some Heroku concepts map to the Stacktape concepts.
Heroku | Stacktape |
---|---|
Web Process (within a Heroku app) | Web service |
Worker Process (within a Heroku app) | Worker service |
Dyno | An instance of your service |
Heroku Postgres | Relational database (also possibility of serverless database) |
Heroku Redis | Redis cluster (also possibility of serverless redis) |
Heroku Scheduler | Lambda function with schedule event |
1 - Writing stacktape.yml
Stacktape config file stacktape.yml
is an infrastructure as a code (IaC) that specifies your services - how to package
them and what resources they have available, along with your databases and all other infrastructure resources.
Additionally, it can specify automated actions to execute as a part of the deployment process, such as testing or
database migrations.
1.1 - Create stacktape.yml
Create config file stacktape.yml in your application's project directory.
For easier writing of the config, you can try to use our interactive config editor or use our VSCode editor extension.
1.2 - Adding web-service
Since you are coming from Heroku, you will probably want to use Web Service resource for your application. Web service is a simple container-based resource that runs your code with public URL and port exposed for HTTPS communication(automatic SSL out of the box), similar to Heroku's web dyno.
Your web service definition contains everything Stacktape needs to know including how to build and package your app. You can use Heroku's buildpacks builder(same way Heroku builds and packages apps), which automatically detects the language and the framework of your application and applies the correct buildpacks for building your application. Optionally, you can specify buildpacks yourself.
However, you can also choose to package app by:
- providing a Dockerfile
- using our built-in, zero-config Stacktape Image Buildpack.
- To see all packaging options refer to Web Service packaging docs.
For convenience, Stacktape automatically injects environment variable PORT
into the web service.
All the traffic is routed to this port, and you should bind your application to this port. Refer to docs to see example.
Copy
resources:appService:type: web-serviceproperties:packaging:type: external-buildpackproperties:sourceDirectoryPath: ./builder: heroku/builder:22# buildpacks:# - heroku/nodejsresources:cpu: 1memory: 1024
Content of stacktape.yml file in your project directory.
Alternatively, you can run your application using worker-service(similar to Heroku's worker process dyno) or any other suitable Stacktape compute resource.
1.3 - Adding database
To replace your relational database (Heroku Postgres), you can use relational database resource. Add it to the config alongside web service. Choose the engine version and instance size according to your needs.
Here is a short overview of Heroku Postgres instances mapping to AWS RDS instances. To see the complete list of all AWS instances, refer to AWS docs.
Heroku Plan | AWS Instance |
---|---|
Essential-0: 1 GB, 20 connections | db.t3.micro: 2 vCPUs, 1 GB RAM |
Essential-1: 10 GB, 20 connections | db.t3.small: 2 vCPUs, 2 GB RAM |
Essential-2: 32 GB, 40 connections | db.t3.medium: 2 vCPUs, 4 GB RAM |
Standard-0: 4 GB, 64 GB storage, 120 connections | db.t3.medium: 2 vCPUs, 4 GB RAM |
Standard-2: 8 GB, 256 GB storage, 400 connections | db.m5.large: 2 vCPUs, 8 GB RAM |
Standard-3: 15 GB, 512 GB storage, 500 connections | db.m5.xlarge: 4 vCPUs, 16 GB RAM |
Standard-4: 30 GB, 768 GB storage, 500 connections | db.m5.2xlarge: 8 vCPUs, 32 GB RAM |
Standard-5: 61 GB, 1 TB storage, 500 connections | db.r5.2xlarge: 8 vCPUs, 64 GB RAM |
Standard-6: 122 GB, 1.5 TB storage, 500 connections | db.r5.4xlarge: 16 vCPUs, 128 GB RAM |
Standard-7: 244 GB, 2 TB storage, 500 connections | db.r5.8xlarge: 32 vCPUs, 256 GB RAM |
Standard-8: 488 GB, 3 TB storage, 500 connections | db.r5.12xlarge: 48 vCPUs, 384 GB RAM |
Standard-9: 768 GB, 4 TB storage, 500 connections | db.r5.24xlarge: 96 vCPUs, 768 GB RAM |
Standard-10: 1 TB, 8 TB storage, 500 connections | db.x1e.32xlarge: 128 vCPUs, 3904 GB RAM |
Copy
resources:appService:type: web-serviceproperties:packaging:type: external-buildpackproperties:sourceDirectoryPath: ./builder: heroku/builder:22resources:cpu: 1memory: 1024database:type: relational-databaseproperties:credentials:masterUserPassword: my-supper-passwordengine:type: postgresproperties:version: "16.3"primaryInstance:instanceSize: db.t3.micro
Content of stacktape.yml file after adding database.
For storing password and other sensitive data we recommend to use secrets.
1.4 - Environment and Secrets
You can easily inject environment variables to access them in a service by specifying them in environment
list. You
can use $ResourceParam directive to inject
information about other resources (such as database URL / connection string) into your service. For sensitive and secret
values, you should create secrets first and then reference them in the config
using $Secret directive. Stacktape resolved these
directives during deployment.
Copy
resources:appService:type: web-serviceproperties:packaging:type: external-buildpackproperties:sourceDirectoryPath: ./builder: heroku/builder:22resources:cpu: 1memory: 1024environment:- name: DATABASE_URLvalue: $ResourceParam('database', 'connectionString')# - name: DATABASE_PASSWORD# value: $Secret('my-database-password')database:type: relational-databaseproperties:credentials:masterUserPassword: $Secret('my-database-password')engine:type: postgresproperties:version: "16.3"primaryInstance:instanceSize: db.t3.micro
2 - Deploy your app
After you have Stacktape config in your repository, you are ready to deploy your app.
Stacktape offers multiple ways of deploying your application:
- Using Stacktape CLI - similar to using Heroku CLI. requires Docker to be installed on the system.
- GitOps (push-to-deploy) - setup integration with Github or Gitlab to deploy your app when there is a push to a specified repository branch.
- Deploy from Git interactively - interactively deploy from your Github or Gitlab repository using Stacktape.
- Deploy from any CI/CD - deploy using any CI/CD system.
3 - Migrating your data from PostgreSQL
If you have created a Render PostgreSQL database, you may want to copy the data from your Heroku Postgres database to Render.
Put your Heroku app into maintenance mode so that no new data is written to the database during the copy.
<HEROKU APP NAME>
is the Heroku app that owns the Heroku Postgres add-on.
This data migration process requires some downtime.
Copy
heroku maintenance:on --app <HEROKU APP NAME>
Create a backup of the data in your Heroku Postgres database.
Copy
heroku pg:backups:capture --app <HEROKU APP NAME>
Download the backup. This will download a file named latest.dump
to your local computer.
Copy
heroku pg:backups:download --app <HEROKU APP NAME>
Import latest.dump
into your Stacktape Postgres relational database. The value for <CONNECTION STRING>
can be found
in Stackape console:
- In the console, go to "Projects",
- select your project and stage,
- On the project stage overview page, click on your database resource which should show you the details of the resource
(including
connectionString
)
Copy
pg_restore --verbose --no-acl --no-owner -d <CONNECTION STRING> latest.dump
If your database is larger than 20GB or under heavy load, use instructions in
Heroku docs to
create a backup of your data. After that has completed, you can use the same pg_restore
command above to import the
data to your Stacktape Postgres database.
Consider using the --jobs
flag available to the pg_restore
command to reduce the time required for restore.
4 - Migrating a domain
If your Heroku app uses a custom domain, you have two options:
Manage domains using your old DNS system - you can keep using your DNS system while using Stacktape with AWS. However, you will need to create/import a custom TLS certificate in AWS ACM and reference it using
customCertificateArn
in your web service domain configuration. After that, you can manually point your DNS record to your app URL. See our docs on using 3rd party DNS provider.Manage domains using Route53 DNS and Stacktape - you can use Stacktape to assign your custom domain name to your app during deployment. See our docs on managing domains with Stacktape. This takes the burden of manually managing DNS records off you. Additionally, it gives you broad options for managing domains: i.e. to automatically assign custom subdomains to your development and testing environments etc.
FAQ
How does auto scaling work?
Web Service auto scale based on CPU/Memory usage thresholds. For more info, refer to the web service docs on auto scaling.
Can I monitor health of my app?
Yes. Health is actually monitored out of the box. If your web service task(container) is deemed unhealthy(i.e your app crashes due to some bug), the task is automatically replaced with healthy one.
Moreover, you can easily set up your own internal health-checks. If a task fails this health-check, it is deemed unhealthy and replaced.
Is my app available during updates?
Yes. When you decide to deploy new version of your app(update to a new version), Stacktape uses rolling update strategy. This means that any old web service task(container) is only removed when a new healthy task replaced it.
Besides rolling update strategy, you can also choose from multiple types of BLUE/GREEN deployment strategies.
Can I use CDN in front of my app?
Yes. Many applications can benefit from CDN. CDN can offload your services by caching responses, which results in less requests coming to the app which leads to less compute power consumed and paid for. With Stacktape you can enable CDN with single line of config
Can I manage Atlas MongoDB clusters using Stacktape?
Yes. You can seamlessly manage Atlas MongoDB clusters using Stacktape.
Do you support other resources?
Yes. We support many resource types(container based, lambdas, batch jobs...) fitting all of your needs. See our docs.
Is Stacktape extensible?
Yes. Except for plethora of AWS and 3rd party resource types Stacktape integrates by default, you can also extend your infrastructure using AWS CDK or AWS Cloudformation.