Η μετάβαση από το Heroku στο AWS είναι κυρίως θέμα μετάφρασης: τα dynos γίνονται containers στο ECS Fargate, η Heroku Postgres γίνεται RDS, τα config vars πάνε στο SSM και το release phase γίνεται ένα one-off task για migrations μέσα στο pipeline σας. Αυτό που θέλει πραγματικό σχεδιασμό είναι η μεταφορά της βάσης με λίγο downtime, γιατί τα κλασικά πλάνα της Heroku Postgres δεν σας αφήνουν να κάνετε replication προς τα έξω με τα συνηθισμένα εργαλεία.
Το ίδιο το Heroku έκανε το ερώτημα πιο πιεστικό. Τον Φεβρουάριο του 2026 ανακοίνωσε ότι περνά σε μοντέλο sustaining engineering, με έμφαση στη σταθερότητα, την ασφάλεια και την υποστήριξη αντί για νέα features. Τίποτα δεν κλείνει και οι υπάρχοντες πελάτες κρατούν τα πλάνα τους, όμως πολλές ομάδες θέλουν πλέον μια πλατφόρμα της οποίας το roadmap ελέγχουν οι ίδιες.
Αντιστοιχίστε κάθε έννοια του Heroku με το AWS
Ξεκινήστε με απογραφή. Τρέξτε heroku apps, heroku addons, heroku ps και heroku config για κάθε εφαρμογή και pipeline, και βρείτε για κάθε γραμμή τον στόχο της στο AWS πριν γράψετε έστω και μία γραμμή Terraform.
| Heroku | Στόχος στο AWS | Σημειώσεις |
|---|---|---|
| Web και worker dynos | ECS services σε Fargate | Ένα service ανά process type. Διαστασιολογήστε με βάση πραγματικά metrics CPU και μνήμης, όχι με βάση το όνομα του dyno. |
| Heroku router | Application Load Balancer | Health checks, τερματισμός TLS, routing ανά host. |
| Heroku Postgres | Amazon RDS for PostgreSQL ή Aurora PostgreSQL | Multi-AZ για production. Ίδια major version. |
| Heroku Key-Value Store (πρώην Heroku Redis) | Amazon ElastiCache (Valkey ή Redis OSS) | Κρατήστε το TLS ενεργό και ελέγξτε τις ρυθμίσεις του client. |
| Config vars | SSM Parameter Store / Secrets Manager | Περνούν στο container μέσω του secrets στο task definition. |
| Procfile | ECS task definitions | Κάθε process type με τη δική του εντολή. |
| Release phase | One-off ECS task πριν από το deploy | Τρέχει τα migrations και σταματά το pipeline αν αποτύχει. |
| Heroku Scheduler | EventBridge Scheduler που τρέχει ECS tasks | Τα cron expressions μεταφέρονται σχεδόν αυτούσια. |
| Review apps | Preview environments ανά pull request | Ξεχωριστό ECS service και schema ανά PR, που σβήνεται με το merge. |
| Log drains, Papertrail | CloudWatch Logs | Με τον awslogs driver, και από εκεί όπου αλλού θέλετε. |
| Buildpacks | Dockerfile ή Cloud Native Buildpacks, images στο ECR | Τα heroku/builder images δουλεύουν και εκτός Heroku. |
Τα add-ons τρίτων (Sentry, SendGrid, New Relic, Bonsai κ.λπ.) είναι συνήθως το πιο εύκολο κομμάτι: τα περισσότερα είναι αυτόνομα SaaS, στα οποία κάνετε εγγραφή απευθείας και συνεχίζετε με τον ίδιο κώδικα. Αντικαταστήστε τα με υπηρεσίες του AWS μόνο όταν υπάρχει σαφής λόγος.
Πού θα τρέξει ο κώδικας: ECS Fargate, όχι App Runner
Για μια εφαρμογή «τύπου Heroku», τρέξτε containers στο Amazon ECS με Fargate. Είναι ό,τι πιο κοντινό στα dynos: χωρίς servers για patching, χρέωση ανά δευτερόλεπτο και ένα service ανά process type.
Το App Runner ήταν παλιότερα το προφανές «Heroku του AWS», όμως το AWS το έχει κλείσει για νέους πελάτες και δεν σχεδιάζει νέα features. Στους νέους χρήστες προτείνει το Amazon ECS Express Mode: του δίνετε ένα container image και δύο IAM roles και σας στήνει Fargate service, Application Load Balancer, auto scaling και networking, χωρίς επιπλέον χρέωση πέρα από τους πόρους που χρησιμοποιούνται.
Το Express Mode είναι καλός τρόπος να σηκώσετε γρήγορα το πρώτο service. Για production συνήθως ορίζουμε τα ίδια κομμάτια σε Terraform (VPC, ALB, ECS cluster, services, task definitions), γιατί σε λίγους μήνες θα θέλετε έτσι κι αλλιώς έλεγχο στο networking, στα deployments και στο κόστος. Αν σκέφτεστε Kubernetes, η σύγκριση ECS και EKS για startups εξηγεί γιατί το ECS είναι η σωστή αφετηρία για τις περισσότερες ομάδες που φεύγουν από το Heroku.
Βήμα 1: container και pipeline
Το πρώτο παραδοτέο είναι ένα container image που τρέχει την εφαρμογή σας ακριβώς όπως το slug που φτιάχνει σήμερα το Heroku. Υπάρχουν δύο δρόμοι.
- Cloud Native Buildpacks. Το Heroku δημοσιεύει τα builder images του, οπότε το
pack build my-app --builder heroku/builder:24φτιάχνει OCI image από τον ίδιο κώδικα με παρόμοια λογική detection (heroku/cnb-builder-images). Ιδανικό για ένα γρήγορο πρώτο πέρασμα. - Dockerfile. Πιο ρητό και πιο εύκολο στο tuning (multi-stage builds, μικρότερα images, ARM64). Σε αυτό καταλήγουμε στις περισσότερες εφαρμογές production.
Μετά, το git push heroku main αντικαθίσταται από ένα pipeline. Παρακάτω είναι ένα συμπυκνωμένο job στο GitHub Actions που χτίζει το image, κάνει register νέο task definition, τρέχει τα migrations ως one-off task (το release phase σας) και μόνο τότε κάνει deploy το service. Κάνει authentication με OIDC αντί για αποθηκευμένα keys· για το κομμάτι του IAM δείτε τον οδηγό μας για GitHub Actions στο AWS με OIDC.
name: deploy
on:
push:
branches: [main]
permissions:
id-token: write
contents: read
env:
AWS_REGION: eu-central-1
CLUSTER: prod
SERVICE: web
ECR_REPO: my-app
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: aws-actions/configure-aws-credentials@v5
with:
role-to-assume: arn:aws:iam::123456789012:role/github-deploy
aws-region: ${{ env.AWS_REGION }}
- id: ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Build and push
run: |
IMAGE=${{ steps.ecr.outputs.registry }}/${{ env.ECR_REPO }}:${{ github.sha }}
docker build -t "$IMAGE" .
docker push "$IMAGE"
echo "IMAGE=$IMAGE" >> "$GITHUB_ENV"
- id: render
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: ecs/web.json
container-name: web
image: ${{ env.IMAGE }}
- name: Register task definition
run: |
ARN=$(aws ecs register-task-definition \
--cli-input-json "file://${{ steps.render.outputs.task-definition }}" \
--query 'taskDefinition.taskDefinitionArn' --output text)
echo "TASK_DEF=$ARN" >> "$GITHUB_ENV"
- name: Run migrations (release phase)
run: |
TASK=$(aws ecs run-task --cluster "$CLUSTER" --launch-type FARGATE \
--task-definition "$TASK_DEF" \
--network-configuration 'awsvpcConfiguration={subnets=[subnet-aaa,subnet-bbb],securityGroups=[sg-app],assignPublicIp=DISABLED}' \
--overrides '{"containerOverrides":[{"name":"web","command":["bin/rails","db:migrate"]}]}' \
--query 'tasks[0].taskArn' --output text)
aws ecs wait tasks-stopped --cluster "$CLUSTER" --tasks "$TASK"
EXIT=$(aws ecs describe-tasks --cluster "$CLUSTER" --tasks "$TASK" \
--query 'tasks[0].containers[0].exitCode' --output text)
test "$EXIT" = "0"
- name: Deploy
run: |
aws ecs update-service --cluster "$CLUSTER" --service "$SERVICE" --task-definition "$TASK_DEF"
aws ecs wait services-stable --cluster "$CLUSTER" --services "$SERVICE"
Δύο λεπτομέρειες που παγιδεύουν πολλούς. Το ecs/web.json πρέπει να περιέχει μόνο πεδία που δέχεται το register-task-definition (όχι την έξοδο του describe-task-definition, που έχει και read-only πεδία). Και το bin/rails db:migrate το αλλάζετε με ό,τι τρέχει η γραμμή release: στο Procfile σας.
Βήμα 2: τα config vars στο SSM και στο Secrets Manager
Βάλτε κάθε config var στο SSM Parameter Store (SecureString) ή στο Secrets Manager και αναφερθείτε σε αυτό από το task definition, ώστε να φτάνει στην εφαρμογή ως environment variable. Ο κώδικάς σας δεν αλλάζει.
"secrets": [
{ "name": "DATABASE_URL", "valueFrom": "arn:aws:ssm:eu-central-1:123456789012:parameter/my-app/prod/DATABASE_URL" },
{ "name": "STRIPE_SECRET_KEY", "valueFrom": "arn:aws:secretsmanager:eu-central-1:123456789012:secret:my-app/prod/stripe" }
]
Το task execution role χρειάζεται δικαίωμα ανάγνωσης σε αυτά τα parameters και στο KMS key που τα κρυπτογραφεί. Χρησιμοποιήστε ένα path ανά εφαρμογή και περιβάλλον (/my-app/prod/), ώστε τα IAM policies να μένουν σύντομα. Είναι επίσης η στιγμή να σβήσετε τα config vars που κανείς δεν θυμάται τι κάνουν. Σε κάθε εφαρμογή Heroku που έχουμε μεταφέρει, υπήρχαν μερικά.
Βήμα 3: Heroku Postgres σε RDS
Αν η βάση σας χωράει σε dump και restore μέσα σε ένα αποδεκτό παράθυρο συντήρησης, χρησιμοποιήστε pg_dump και pg_restore. Για μεγαλύτερες βάσεις, οι επιλογές σας εξαρτώνται από το πλάνο της Heroku Postgres που έχετε.
Ο απλός δρόμος: dump και restore
# 1. Maintenance mode, ώστε να μη γράφει τίποτα
heroku maintenance:on -a my-app
# 2. Φρέσκο backup και download
heroku pg:backups:capture -a my-app
curl -o latest.dump "$(heroku pg:backups:url -a my-app)"
# 3. Restore στο RDS (ίδια major version)
pg_restore --verbose --clean --no-acl --no-owner \
-h my-db.xxxx.eu-central-1.rds.amazonaws.com -U app -d app latest.dump
Κάντε πρώτα μια πλήρη πρόβα σε ένα staging RDS και χρονομετρήστε την. Αυτός ο χρόνος κρίνει αν ο δρόμος αυτός σας κάνει. Τρέξτε ANALYZE μετά το restore, ώστε ο planner να έχει στατιστικά, και ελέγξτε τα row counts στους μεγαλύτερους πίνακες.
Σχεδόν μηδενικό downtime: τι δουλεύει στην πράξη
Τα συνηθισμένα εργαλεία για σχεδόν μηδενικό downtime (AWS DMS με change data capture ή native logical replication προς το RDS) χρειάζονται logical replication στην πηγή. Τα κλασικά πλάνα της Heroku Postgres δεν το προσφέρουν: το Heroku δηλώνει ότι δεν υποστηρίζει logical replication προς εξωτερικές βάσεις και δεν δίνει τα roles superuser ή replication που χρειάζονται εργαλεία όπως το DMS. Το DMS μπορεί να κάνει ένα full load, αλλά αυτό θέλει το ίδιο πάγωμα εγγραφών με ένα dump.
Η εξαίρεση είναι η Heroku Postgres Advanced, που προσφέρει managed logical replication προς εξωτερική Postgres, όπως το RDS. Αν είστε σε Advanced ή μπορείτε να περάσετε εκεί, η ροή είναι: αντιγράφετε το schema με pg_dump --schema-only, φτιάχνετε publication στο Heroku και subscription στο RDS, περιμένετε το αρχικό sync και κάνετε cutover. Η τεκμηρίωση του Heroku αναφέρει τους περιορισμούς: το DDL δεν γίνεται replicate, τα sequences πρέπει να προχωρήσουν με setval() πριν από το cutover και κάθε πίνακας θέλει primary key ή unique index για να περνούν τα updates και τα deletes.
Για τα κλασικά πλάνα μένουν το trigger-based replication ή τα dual writes από την εφαρμογή. Και τα δύο προσθέτουν ρίσκο και χρόνο ανάπτυξης. Από την εμπειρία μας, ένα καλά δοκιμασμένο παράθυρο συντήρησης κάτω της μίας ώρας είναι καλύτερη επιλογή για τα περισσότερα startups.
Βήμα 4: Redis, workers, scheduler και preview environments
Όταν η εφαρμογή τρέχει ήδη στο ECS, αυτά είναι σχεδόν μηχανική δουλειά.
- Redis. Ένα ElastiCache cluster με in-transit encryption, και το
REDIS_URLδείχνει εκεί. Αν το Redis κρατά μόνο cache και ουρές jobs, αφήστε το να ξεκινήσει άδειο και αδειάστε την παλιά ουρά πριν από το cutover, αντί να μεταφέρετε keys. - Workers. Ένα δεύτερο ECS service με το ίδιο image και την εντολή του worker. Κάντε scaling με βάση το μέγεθος της ουράς, αν η ουρά σας βγάζει τέτοιο metric.
- Scheduler. Το EventBridge Scheduler τρέχει ECS tasks με cron ή rate expression και αντικαθιστά το Heroku Scheduler job προς job.
- Review apps. Ένα job στο pipeline που, όταν ανοίγει pull request, στήνει ξεχωριστό ECS service πίσω από host-based κανόνα στο ALB (
pr-123.preview.example.com) με δική του βάση ή schema, και ένα job που το σβήνει όταν κλείσει. Ξεκινήστε το μόνο αν η ομάδα σας όντως χρησιμοποιούσε review apps.
Βήμα 5: DNS και SSL cutover
Το cutover είναι το πιο σύντομο βήμα, αν το προετοιμάσετε λίγες μέρες νωρίτερα.
- Ζητήστε πιστοποιητικό ACM για τα domains σας, στο ίδιο region με τον ALB, με DNS validation.
- Κατεβάστε το TTL των DNS records της εφαρμογής στα 60 δευτερόλεπτα, τουλάχιστον μία μέρα πριν.
- Στήστε όλο το stack στο AWS και δοκιμάστε το μέσω του hostname του ALB, με
Hostheader ή προσωρινό subdomain. - Τη βραδιά του cutover: maintenance mode στο Heroku, τελευταίο αντίγραφο της βάσης, έλεγχοι, αλλαγή του DNS record προς τον ALB (alias record στο Route 53 ή CNAME αλλού) και παρακολούθηση errors και latency.
- Κρατήστε την εφαρμογή στο Heroku ανέπαφη αλλά με scale προς τα κάτω για μία εβδομάδα, ως δρόμο για rollback. Θυμηθείτε ότι rollback μετά από νέες εγγραφές στο RDS σημαίνει αντιγραφή δεδομένων προς τα πίσω.
Το checklist μετάβασης στο cloud καλύπτει όσα ισχύουν σε κάθε μετάβαση, από τα backups μέχρι την ανασκόπηση μετά το cutover.
Πώς να εκτιμήσετε το κόστος πριν μετακομίσετε
Μην εμπιστεύεστε κανένα «το AWS είναι Χ% φθηνότερο», ούτε το δικό μας. Χτίστε την εκτίμηση από τα δικά σας νούμερα.
- Τρέχον κόστος. Πάρτε τα τρία τελευταία τιμολόγια του Heroku και χωρίστε τα σε dynos, Postgres, Redis και κάθε add-on.
- Πραγματική χρήση. Δείτε στα Heroku metrics τη μνήμη και το CPU load ανά process type. Πολλές εφαρμογές τρέχουν σε υπερβολικά μεγάλα dynos, γιατί η μνήμη ήταν ο μόνος μοχλός.
- Κοστολογήστε το AWS γραμμή προς γραμμή στο AWS Pricing Calculator: ώρες vCPU και μνήμης Fargate ανά service, ALB, RDS (instance, storage, backups, και διπλό instance για Multi-AZ), ElastiCache, ingestion στα CloudWatch Logs, storage στο ECR και data transfer προς το internet.
- Προσθέστε τα κόστη δικτύου που ξεχνιούνται. Ένα NAT gateway για private subnets έχει ωριαία χρέωση συν χρέωση ανά GB, όπως εξηγούμε στο άρθρο για το κρυφό κόστος του NAT gateway.
- Προσθέστε τον χρόνο των ανθρώπων. Κάποιος πλέον έχει την ευθύνη για patching των base images, upgrades της βάσης, alarms και on-call. Στο Heroku, ένα μέρος αυτού ήταν μέσα στην τιμή.
Το compute και οι βάσεις βγαίνουν συχνά φθηνότερα στο AWS για την ίδια χωρητικότητα, και με Savings Plans και reserved instances η διαφορά μεγαλώνει. Το αν το σύνολο βγαίνει φθηνότερο κρίνεται στο βήμα 5.
Πότε να μη φύγετε από το Heroku
Μείνετε στο Heroku αν η μετάβαση κοστίζει περισσότερο από όσο αποδίδει. Είναι απολύτως θεμιτό αποτέλεσμα, όχι αποτυχία.
- Ο λογαριασμός σας στο Heroku είναι μικρός και σταθερός, και κανείς στην ομάδα δεν θέλει να αναλάβει υποδομή.
- Βασίζεστε στο Heroku Connect για συγχρονισμό με το Salesforce και δεν έχετε σχεδιάσει αντικατάσταση.
- Είστε λίγο πριν από γύρο χρηματοδότησης, launch ή rewrite, και η μετάβαση θα έτρωγε χρόνο από πράγματα πιο σημαντικά αυτό το τρίμηνο.
- Δεν έχετε κάποιον να αναλάβει το AWS μετά τη μετάβαση. Μια πλατφόρμα που δεν συντηρεί κανείς είναι χειρότερη από το Heroku.
Οι λόγοι που δικαιολογούν τη μετάβαση: κόστος που ανεβαίνει με την κλίμακα, ανάγκη για networking σε επίπεδο VPC ή private connectivity, απαιτήσεις compliance με controls που δεν μπορείτε να έχετε στο Heroku, ή απλώς η επιθυμία για μια πλατφόρμα με roadmap που ελέγχετε εσείς.
Αν σχεδιάζετε να φύγετε από το Heroku και θέλετε ένα δεύτερο ζευγάρι χέρια για το cutover της βάσης ή για τα θεμέλια σε Terraform, αυτό ακριβώς κάνει η υπηρεσία μετάβασης στο cloud: δοκιμασμένο πλάνο, σύντομο παράθυρο συντήρησης και μια ομάδα που μπορεί να τρέξει την πλατφόρμα και μετά.
Συχνές ερωτήσεις
Ποιο είναι το αντίστοιχο του Heroku στο AWS;
Το πιο κοντινό είναι το Amazon ECS σε Fargate πίσω από Application Load Balancer, με RDS για την Postgres και ElastiCache για το Redis. Το AWS App Runner ήταν η πιο απλή επιλογή, όμως έκλεισε για νέους πελάτες και το AWS προτείνει πλέον το ECS Express Mode, που στήνει Fargate, load balancer και auto scaling από ένα container image.
Μπορώ να μεταφέρω την Heroku Postgres στο RDS χωρίς downtime;
Μόνο από την Heroku Postgres Advanced, που υποστηρίζει managed logical replication προς εξωτερική Postgres όπως το RDS. Τα κλασικά πλάνα δεν επιτρέπουν logical replication ούτε δίνουν replication role, άρα το change data capture του AWS DMS δεν δουλεύει. Εκεί, η αξιόπιστη λύση είναι ένα δοκιμασμένο pg_dump και pg_restore σε σύντομο παράθυρο συντήρησης.
Πόσο διαρκεί μια μετάβαση από το Heroku στο AWS;
Για ένα τυπικό startup με μία ή δύο εφαρμογές, Postgres, Redis και λίγα add-ons, υπολογίστε μερικές εβδομάδες: θεμέλια στο AWS και pipeline, staging περιβάλλον, μία ή δύο πρόβες της βάσης και cutover σε ένα παράθυρο συντήρησης. Το μέγεθος της βάσης και ο αριθμός των add-ons επηρεάζουν το χρονοδιάγραμμα περισσότερο από τον κώδικα.
Είναι το AWS φθηνότερο από το Heroku;
Συχνά, για compute και βάσεις στην ίδια χωρητικότητα, ειδικά με Savings Plans, αλλά όχι αυτόματα. Κοστολογήστε τη δική σας χρήση στο AWS Pricing Calculator και προσθέστε load balancers, NAT gateways, logs, data transfer και τον χρόνο της ομάδας για να τρέχει την πλατφόρμα. Για μικρές, σταθερές εφαρμογές, το Heroku μπορεί να βγαίνει ακόμα φθηνότερο συνολικά.