Chapter 4: Cloud Deployment
Introduction
Your application is ready, Docker configured, CI/CD in place. It's time to go live! This chapter covers the main cloud deployment options.
🎯 Chapter Objectives
By the end of this chapter, you will know how to:
- ✅ Deploy on Railway
- ✅ Deploy on Heroku
- ✅ Understand AWS options
- ✅ Configure a managed database
- ✅ Choose the right platform
1. Platform Comparison
| Platform | Difficulty | Cost | Ideal for |
|---|---|---|---|
| Railway | ⭐ Easy | Free → $5/month | Personal projects, startups |
| Heroku | ⭐ Easy | $7/month | Simple apps |
| Render | ⭐ Easy | Free → $7/month | Heroku alternative |
| AWS ECS | ⭐⭐⭐ Complex | Variable | Enterprise |
| Kubernetes | ⭐⭐⭐⭐ Advanced | Variable | Microservices |
2. Railway (Recommended for Beginners)
Why Railway?
- ✅ Simple interface
- ✅ Deployment from GitHub
- ✅ Integrated PostgreSQL
- ✅ Free to start
- ✅ Supports Docker
Deployment
Option 1: From GitHub
- Go to railway.app
- "New Project" → "Deploy from GitHub repo"
- Select your repository
- Railway automatically detects Spring Boot
Option 2: With Docker
# Install Railway CLI
npm i -g @railway/cli
# Login
railway login
# Create a project
railway init
# Deploy
railway up
Configuration
# Environment variables (in Railway Dashboard)
SPRING_PROFILES_ACTIVE=prod
DATABASE_URL=${{Postgres.DATABASE_URL}}
Add PostgreSQL
- In the Railway project: "New" → "Database" → "PostgreSQL"
- Variables are automatically injected
railway.json
{
"$schema": "https://railway.app/railway.schema.json",
"build": {
"builder": "DOCKERFILE",
"dockerfilePath": "Dockerfile"
},
"deploy": {
"startCommand": "java -jar app.jar",
"healthcheckPath": "/actuator/health",
"restartPolicyType": "ON_FAILURE"
}
}
3. Heroku
Preparation
Procfile (at the root):
web: java -Dserver.port=$PORT -jar target/*.jar
system.properties:
java.runtime.version=17
Deployment
# Install Heroku CLI
# https://devcenter.heroku.com/articles/heroku-cli
# Login
heroku login
# Create the app
heroku create my-spring-app
# Add PostgreSQL
heroku addons:create heroku-postgresql:mini
# Deploy
git push heroku main
# View logs
heroku logs --tail
Environment Variables
heroku config:set SPRING_PROFILES_ACTIVE=prod
heroku config:set JWT_SECRET=your-secret-key
# View all variables
heroku config
With Docker
# Login to Heroku registry
heroku container:login
# Build and push
heroku container:push web
# Deploy
heroku container:release web
4. Render
Deployment
- Go to render.com
- "New" → "Web Service"
- Connect GitHub
- Configure:
- Build Command:
mvn clean package -DskipTests - Start Command:
java -jar target/*.jar
- Build Command:
render.yaml
services:
- type: web
name: my-spring-app
env: docker
dockerfilePath: ./Dockerfile
envVars:
- key: SPRING_PROFILES_ACTIVE
value: prod
- key: DATABASE_URL
fromDatabase:
name: mydb
property: connectionString
databases:
- name: mydb
plan: free
5. AWS (Options)
Elastic Beanstalk (Simple)
# Install EB CLI
pip install awsebcli
# Initialize
eb init
# Create the environment
eb create production
# Deploy
eb deploy
ECS with Fargate (Docker)
# Create a cluster
aws ecs create-cluster --cluster-name my-cluster
# Create a task definition (JSON)
aws ecs register-task-definition --cli-input-json file://task-definition.json
# Create a service
aws ecs create-service \
--cluster my-cluster \
--service-name my-service \
--task-definition my-task \
--desired-count 2
task-definition.json
{
"family": "my-spring-app",
"containerDefinitions": [
{
"name": "app",
"image": "myuser/myapp:latest",
"portMappings": [
{
"containerPort": 8080,
"hostPort": 8080
}
],
"environment": [
{
"name": "SPRING_PROFILES_ACTIVE",
"value": "prod"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/my-app",
"awslogs-region": "us-east-1"
}
}
}
],
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512"
}
6. Managed Database
Railway PostgreSQL
# Automatically configured
spring.datasource.url=${DATABASE_URL}
Heroku Postgres
# Heroku provides DATABASE_URL automatically
spring.datasource.url=${DATABASE_URL}
AWS RDS
spring.datasource.url=jdbc:postgresql://mydb.xxx.us-east-1.rds.amazonaws.com:5432/mydb
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
Parse DATABASE_URL
Some platforms provide a URL in the format:
postgres://user:password@host:5432/dbname
Spring configuration to parse:
@Configuration
public class DatabaseConfig {
@Bean
@Profile("prod")
public DataSource dataSource() {
String databaseUrl = System.getenv("DATABASE_URL");
if (databaseUrl != null && databaseUrl.startsWith("postgres://")) {
// Parse Heroku/Railway format
URI uri = URI.create(databaseUrl);
String username = uri.getUserInfo().split(":")[0];
String password = uri.getUserInfo().split(":")[1];
String jdbcUrl = "jdbc:postgresql://" + uri.getHost() + ":" + uri.getPort() + uri.getPath();
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl(jdbcUrl);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
// Fallback
return DataSourceBuilder.create().build();
}
}
7. Deployment Checklist
Before Deployment
□ Tests pass locally
□ Production profile configured
□ Secrets externalized
□ Dockerfile tested
□ Health check configured
□ Logs configured
Environment Variables
# Essential
SPRING_PROFILES_ACTIVE=prod
DATABASE_URL=...
JWT_SECRET=...
# Optional
SERVER_PORT=8080
JAVA_OPTS="-Xmx512m"
Post-Deployment
□ Application accessible
□ Health check OK
□ Logs visible
□ Database connected
□ Monitoring in place
8. Monitoring in Production
Actuator
management.endpoints.web.exposure.include=health,info,prometheus
management.endpoint.health.show-details=when_authorized
Cloud Logging
# JSON logs for cloud
logging.pattern.console={"timestamp":"%d","level":"%p","logger":"%c","message":"%m"}%n
Monitoring Services
- Railway: Integrated metrics
- Heroku: Heroku Metrics
- AWS: CloudWatch
- External: Datadog, New Relic
9. Summary
Recommendations by Use Case
Personal project / POC:
→ Railway (free, simple)
Startup / MVP:
→ Railway or Render ($5-20/month)
SME / Production:
→ Heroku or AWS Elastic Beanstalk
Enterprise / Scale:
→ AWS ECS / Kubernetes
Quick Deployment (Railway)
# 1. Have a Dockerfile
# 2. Push to GitHub
# 3. On railway.app:
# - New Project → GitHub
# - Add PostgreSQL
# - Configure variables
# 4. Done! 🚀
🎯 Next Step
Time for practice! Let's Dockerize and deploy an application.
➡️ TP12.1: Complete Dockerization