Skip to content

Commit e8cb0db

Browse files
committed
PaaS: add deployment on ACI, AWS ECS and Google Cloud Run
1 parent 4e4b06b commit e8cb0db

18 files changed

+1108
-9
lines changed

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ This repo is using [Opentofu](https://opentofu.org/) and other tools to create c
33

44
## Platform Support Status
55

6-
| | VM | Docker | K8s |
7-
|-----------------------|-------------|-----------------|--------------|
8-
| Microsoft Azure | VM ✅ | ACI 🚧 | AKS 🔲 |
9-
| Amazon Web Services | EC2 ✅ | ECS 🚧 | EKS 🔲 |
10-
| Google Cloud Platform | GCE ✅ | GAE 🚧 | GKE 🔲 |
11-
| Render || DOCKER ✅(See 1) ||
12-
| Heroku || HCR 🔲 ||
13-
| DigitalOcean | Droplets 🔲 | CR 🔲 | DOKS 🔲 |
14-
| Native K8s ||| K8S ✅(See 2) |
6+
| | VM | Docker | K8s |
7+
|-----------------------|-------------|-------------------|--------------|
8+
| Microsoft Azure | VM ✅ | ACI | AKS 🔲 |
9+
| Amazon Web Services | EC2 ✅ | ECS(Fargate) ✅ | EKS 🔲 |
10+
| Google Cloud Platform | GCE ✅ | Cloud Run ✅ | GKE 🔲 |
11+
| Render || DOCKER ✅🚧(See 1) ||
12+
| Heroku || HCR 🚧 ||
13+
| DigitalOcean | Droplets 🚧 | CR 🚧 | DOKS 🔲 |
14+
| Native K8s || | K8S ✅(See 2) |
1515

1616
The following icons are used to represent the status of support for each platform:
1717
- ✅: completed

modules/aws-ecs/.terraform.lock.hcl

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

modules/aws-ecs/main.tf

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
provider "aws" {
2+
region = var.region
3+
}
4+
5+
locals {
6+
liveness_probe_path = "/onebusaway-api-webapp/api/where/current-time.json?key=org.onebusaway.iphone"
7+
liveness_probe_port = 8080
8+
liveness_probe_initial_delay_seconds = 120
9+
liveness_probe_period_seconds = 30
10+
}
11+
12+
resource "aws_vpc" "main" {
13+
cidr_block = "10.0.0.0/16"
14+
enable_dns_hostnames = true
15+
}
16+
17+
resource "aws_internet_gateway" "main" {
18+
vpc_id = aws_vpc.main.id
19+
}
20+
21+
resource "aws_route_table" "public" {
22+
vpc_id = aws_vpc.main.id
23+
24+
route {
25+
cidr_block = "0.0.0.0/0"
26+
gateway_id = aws_internet_gateway.main.id
27+
}
28+
}
29+
30+
resource "aws_route_table_association" "public" {
31+
subnet_id = aws_subnet.main.id
32+
route_table_id = aws_route_table.public.id
33+
}
34+
35+
resource "aws_subnet" "main" {
36+
vpc_id = aws_vpc.main.id
37+
cidr_block = "10.0.1.0/24"
38+
availability_zone = "${var.region}a"
39+
map_public_ip_on_launch = true
40+
}
41+
42+
resource "aws_security_group" "main" {
43+
vpc_id = aws_vpc.main.id
44+
45+
ingress {
46+
from_port = 8080
47+
to_port = 8080
48+
protocol = "tcp"
49+
cidr_blocks = ["0.0.0.0/0"]
50+
}
51+
52+
ingress {
53+
from_port = 2049
54+
to_port = 2049
55+
protocol = "tcp"
56+
cidr_blocks = ["0.0.0.0/0"]
57+
}
58+
59+
egress {
60+
from_port = 0
61+
to_port = 0
62+
protocol = "-1"
63+
cidr_blocks = ["0.0.0.0/0"]
64+
}
65+
}
66+
67+
resource "aws_efs_file_system" "main" {
68+
creation_token = "ecs-efs-oba"
69+
}
70+
71+
resource "aws_efs_mount_target" "main" {
72+
file_system_id = aws_efs_file_system.main.id
73+
subnet_id = aws_subnet.main.id
74+
security_groups = [aws_security_group.main.id]
75+
}
76+
77+
resource "aws_ecs_cluster" "main" {
78+
name = var.cluster_name
79+
}
80+
81+
resource "aws_cloudwatch_log_group" "main" {
82+
name = "/ecs/${var.container_name}"
83+
retention_in_days = 7
84+
}
85+
86+
resource "aws_iam_role" "ecs_task_execution_role" {
87+
name = "ecsTaskExecutionRole"
88+
89+
assume_role_policy = jsonencode({
90+
Version = "2012-10-17"
91+
Statement = [{
92+
Action = "sts:AssumeRole"
93+
Effect = "Allow"
94+
Principal = {
95+
Service = "ecs-tasks.amazonaws.com"
96+
}
97+
}]
98+
})
99+
}
100+
101+
resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy" {
102+
role = aws_iam_role.ecs_task_execution_role.name
103+
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
104+
}
105+
106+
resource "aws_ecs_task_definition" "main" {
107+
family = var.container_name
108+
network_mode = "awsvpc"
109+
requires_compatibilities = ["FARGATE"]
110+
cpu = var.container_cpu
111+
memory = var.container_memory
112+
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
113+
114+
container_definitions = jsonencode([{
115+
name = var.container_name
116+
image = var.container_image
117+
cpu = var.container_cpu
118+
memory = var.container_memory
119+
memoryReservation = var.container_memory
120+
essential = true
121+
122+
environment = [
123+
{ name = "TZ", value = var.env_var_tz },
124+
{ name = "GTFS_URL", value = var.env_var_gtfs_url },
125+
{ name = "VEHICLE_POSITIONS_URL", value = var.env_var_vehicle_positions_url },
126+
{ name = "TRIP_UPDATES_URL", value = var.env_var_trip_updates_url },
127+
{ name = "ALERTS_URL", value = var.env_var_alerts_url },
128+
{ name = "REFRESH_INTERVAL", value = var.env_var_refresh_interval },
129+
{ name = "AGENCY_ID", value = var.env_var_agency_id },
130+
{ name = "FEED_API_KEY", value = var.env_var_feed_api_key },
131+
{ name = "FEED_API_VALUE", value = var.env_var_feed_api_value },
132+
{ name = "JDBC_USER", value = var.env_var_jdbc_user },
133+
{ name = "JDBC_PASSWORD", value = var.env_var_jdbc_password },
134+
{ name = "JDBC_URL", value = var.env_var_jdbc_url },
135+
{ name = "GOOGLE_MAPS_API_KEY", value = var.env_var_google_maps_api_key },
136+
{ name = "GOOGLE_MAPS_CHANNEL_ID", value = var.env_var_google_maps_channel_id },
137+
{ name = "GOOGLE_MAPS_CLIENT_ID", value = var.env_var_google_maps_client_id },
138+
]
139+
140+
portMappings = [
141+
{
142+
containerPort = 8080
143+
hostPort = 8080
144+
protocol = "tcp"
145+
}
146+
]
147+
148+
mountPoints = [
149+
{
150+
sourceVolume = "bundle"
151+
containerPath = "/bundle"
152+
readOnly = false
153+
}
154+
]
155+
156+
healthCheck = {
157+
command = ["CMD-SHELL", "curl -f http://localhost:8080${local.liveness_probe_path} || exit 1"]
158+
interval = local.liveness_probe_period_seconds
159+
timeout = 5
160+
retries = 3
161+
startPeriod = local.liveness_probe_initial_delay_seconds
162+
}
163+
164+
logConfiguration = {
165+
logDriver = "awslogs"
166+
options = {
167+
"awslogs-group" = "/ecs/${var.container_name}"
168+
"awslogs-region" = var.region
169+
"awslogs-stream-prefix" = "ecs"
170+
}
171+
}
172+
}])
173+
174+
volume {
175+
name = "bundle"
176+
177+
efs_volume_configuration {
178+
file_system_id = aws_efs_file_system.main.id
179+
root_directory = "/"
180+
}
181+
}
182+
183+
depends_on = [
184+
aws_efs_file_system.main, aws_efs_mount_target.main
185+
]
186+
}
187+
188+
resource "aws_ecs_service" "main" {
189+
name = var.service_name
190+
cluster = aws_ecs_cluster.main.id
191+
task_definition = aws_ecs_task_definition.main.arn
192+
desired_count = 1
193+
launch_type = "FARGATE"
194+
195+
network_configuration {
196+
subnets = [aws_subnet.main.id]
197+
security_groups = [aws_security_group.main.id]
198+
assign_public_ip = true
199+
}
200+
}

modules/aws-ecs/readme.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Deployment Guide for AWS ECS(Fargate)
2+
3+
AWS ECS is a robust choice for deploying the OneBusAway server, providing a managed container orchestration service that simplifies running and scaling containerized applications. This guide will walk you through deploying the OneBusAway server on AWS ECS using Opentofu.
4+
5+
## Prerequisites
6+
7+
1. An AWS account. If you don't have one, you can create a free account [here](https://aws.amazon.com/free/).
8+
9+
2. AWS CLI. You can install it by following the instructions [here](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html).
10+
11+
3. Opentofu, an open-source Terraform alternative, you can install it by following the instructions [here](https://opentofu.org/docs/intro/install/).
12+
13+
4. Ensure you have *ALL* the prerequisites installed before starting the deployment.
14+
15+
## Steps
16+
17+
1. Clone this repository to your local machine. You can run:
18+
19+
```bash
20+
git clone https://github.com/OneBusAway/onebusaway-deployment.git
21+
cd onebusaway-deployment/modules/aws-ecs
22+
```
23+
24+
2. Initialize the project. This will download the necessary plugins and providers for the project:
25+
26+
```bash
27+
tofu init
28+
```
29+
30+
3. Create a `terraform.tfvars` file by copying the example variables file, and then modify it according to your needs:
31+
32+
```bash
33+
cp terraform.tfvars.example terraform.tfvars
34+
```
35+
36+
4. Edit the `terraform.tfvars` file and update the variable values to match your specific requirements, such as AWS region, cluster name, container details, and environment variables.
37+
38+
5. Run Tofu plan to preview the infrastructure changes:
39+
40+
```bash
41+
tofu plan
42+
```
43+
44+
6. Apply the Tofu configuration to create the actual resources:
45+
46+
```bash
47+
tofu apply
48+
```
49+
50+
Type `yes` when prompted to confirm the resource creation.
51+
52+
7. After the deployment is complete, verify the created resources in the AWS Management Console. Ensure the ECS cluster, tasks, service, and other related resources are created and running correctly.
53+
54+
8. Access the OneBusAway server by visiting the public IP of the ECS service. You can find the server IP in the AWS Management Console under the ECS service details.
55+
56+
## Clean up
57+
58+
If you want to shut down the server and clean up the resources, you can run the following command:
59+
60+
```bash
61+
tofu destroy
62+
```
63+
64+
Opentofu will destroy all resources created by this project, including the ECS cluster, task definition, security groups, and other resources.
65+
66+
## Conclusion
67+
68+
This guide shows you how to deploy the OneBusAway server on AWS ECS using Opentofu. If you have any questions or suggestions, feel free to open an issue in this repository.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
region = "us-east-1"
2+
cluster_name = "oba-cluster"
3+
container_name = "onebusaway-api-server"
4+
container_image = "ghcr.io/onebusaway/onebusaway-api-webapp:latest"
5+
container_cpu = 2048
6+
container_memory = 4096
7+
log_group_name = "/ecs/oba-container-logs"
8+
service_name = "oba-service"
9+
10+
env_var_tz = "America/Toronto"
11+
env_var_gtfs_url = "https://api.cityofkingston.ca/gtfs/gtfs.zip"
12+
env_var_vehicle_positions_url = "https://api.cityofkingston.ca/gtfs-realtime/vehicleupdates.pb"
13+
env_var_trip_updates_url = "https://api.cityofkingston.ca/gtfs-realtime/tripupdates.pb"
14+
env_var_alerts_url = "https://api.cityofkingston.ca/gtfs-realtime/alerts.pb"
15+
env_var_feed_api_key = ""
16+
env_var_feed_api_value = ""
17+
env_var_refresh_interval = "30"
18+
env_var_agency_id = "0"
19+
env_var_jdbc_user = "oba_user"
20+
env_var_jdbc_password = "oba_password"
21+
env_var_jdbc_url = "jdbc:mysql://<DATABASE_HOST>:<PORT>/oba_database"
22+
env_var_google_maps_api_key = ""
23+
env_var_google_maps_channel_id = ""
24+
env_var_google_maps_client_id = ""

0 commit comments

Comments
 (0)