diff --git a/README.md b/README.md index 00a85cf..f28dbdb 100644 --- a/README.md +++ b/README.md @@ -3,21 +3,22 @@ This repo is using [Opentofu](https://opentofu.org/) and other tools to create c ## Platform Support Status -| | VM | Docker | K8s | -|-----------------------|-------------|-------------------|--------------| -| Microsoft Azure | VM โœ… | ACI โœ… | AKS ๐Ÿ”ฒ | -| Amazon Web Services | EC2 โœ… | ECS(Fargate) โœ… | EKS ๐Ÿ”ฒ | -| Google Cloud Platform | GCE โœ… | Cloud Run โœ… | GKE ๐Ÿ”ฒ | -| Render | โŒ | DOCKER โœ…๐Ÿšง(See 1) | โŒ | -| Heroku | โŒ | HCR ๐Ÿšง | โŒ | -| DigitalOcean | Droplets ๐Ÿšง | CR ๐Ÿšง | DOKS ๐Ÿ”ฒ | -| Native K8s | โŒ | โŒ | K8S โœ…(See 2) | +| | VM | Docker | K8s | +|-----------------------|------------|-----------------|--------------| +| Microsoft Azure | VM โœ… | ACI โœ… | AKS ๐Ÿ”ฒ | +| Amazon Web Services | EC2 โœ… | ECS(Fargate) โœ… | EKS ๐Ÿ”ฒ | +| Google Cloud Platform | GCE โœ… | Cloud Run โœ… | GKE ๐Ÿ”ฒ | +| Render | โŒ | DOCKER โœ…(See 1) | โŒ | +| DigitalOcean | Droplets โœ… | AP โš ๏ธ(See 3) | DOKS ๐Ÿ”ฒ | +| Native K8s | โŒ | โŒ | K8S โœ…(See 2) | The following icons are used to represent the status of support for each platform: - โœ…๏ผš completed +- โš ๏ธ๏ผš partially completed - ๐Ÿšง๏ผš in progress - โŒ๏ผš not applicable - ๐Ÿ”ฒ๏ผš not started -1. Completed by Aaron, you can find Render deployment file here: [onebusaway-docker](https://github.com/OneBusAway/onebusaway-docker), will be integrated into this repo. +1. Completed by Aaron, you can find Render deployment file here: [onebusaway-docker](https://github.com/OneBusAway/onebusaway-docker), has been integrated into this repo. 2. Completed by Neo2308, you can find `oba.yaml` here: [onebusaway-docker](https://github.com/OneBusAway/onebusaway-docker), will be rewrite in [Kustomize](https://github.com/kubernetes-sigs/kustomize). +3. DigitalOcean app engine's gVisor is conflicting with supervisor, they already know this issue and will fix it in the future. \ No newline at end of file diff --git a/modules/aws-ec2/variables.tf b/modules/aws-ec2/variables.tf index 1e02b66..9329a6c 100644 --- a/modules/aws-ec2/variables.tf +++ b/modules/aws-ec2/variables.tf @@ -17,7 +17,7 @@ variable "username" { } variable "caddy" { - description = "Wheather to use Caddy or not, leave empty to disable" + description = "Whether to use Caddy or not, leave empty to disable" type = string default = "1" } diff --git a/modules/azure-vm/variables.tf b/modules/azure-vm/variables.tf index f8fb000..49911e8 100644 --- a/modules/azure-vm/variables.tf +++ b/modules/azure-vm/variables.tf @@ -11,7 +11,7 @@ variable "size" { } variable "caddy" { - description = "Wheather to use Caddy or not, leave empty to disable" + description = "Whether to use Caddy or not, leave empty to disable" type = string default = "1" } diff --git a/modules/digitalocean-ap/.terraform.lock.hcl b/modules/digitalocean-ap/.terraform.lock.hcl new file mode 100644 index 0000000..4f09530 --- /dev/null +++ b/modules/digitalocean-ap/.terraform.lock.hcl @@ -0,0 +1,26 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/digitalocean/digitalocean" { + version = "2.40.0" + constraints = "~> 2.0" + hashes = [ + "h1:71yfpCVVq+OoNzl7SX/7ObnFUQeZL4vHOOalLzEZ4U0=", + "zh:00235830abae70642ebefc4d9c00e5eb978e28b74abc6b34f16b078f242aa217", + "zh:09d77785f768bd568f85a121d3d79316083befe903ce4ccd5567689a23236fb0", + "zh:0c9c4e19b411702d316a6bd044903e2ec506a69d38495ed32cc31e3f3f26acae", + "zh:12b34c88faad5b6149e9a3ad1396680588e1bae263b20d6b19835460f111c190", + "zh:15f041fc57ea46673a828919efe2ef3f05f7c4b863b7d7881336b93e92bd1159", + "zh:45e01972de2fab1687a09ea8fb3e4519be11c93ef93a63f28665630850858a20", + "zh:4e18bf5c1d2ec1ec6b6a9f4b58045309006f510edf770168fc18e273e6a09289", + "zh:575528b7e36e3489d2309e0c6cb9bd9952595cac5459b914f2d2827de1a1e4fc", + "zh:67462192212f810875d556462c79f574a8f5713b7a869ba4fce25953bfcf2dd2", + "zh:7024637b31e8276b653265fdf3f479220182edde4b300b034562b4c287faefa5", + "zh:a7904721b2680be8330dde98dd826be15c67eb274da7876f042cbcd6592ac970", + "zh:b225d4b67037a19392b0ab00d1f5fc9e729db4dfc32d18d4b36225693270ef52", + "zh:bd1e8768819d6113b2ec16f939196a1f2ae6d2803824fde463a20d06e071b212", + "zh:c5da40dc0749548ee2e1943776fb41b952c994e50bbc404251df20a81f730242", + "zh:dabc3387392aaba297739e1e97fadf059258fc3efb4dff2f499dbc407b6e088d", + "zh:f42137cf424c3e7c9c935b3f73618e51096bd0367a8d364073e2d70588d2cbf2", + ] +} diff --git a/modules/digitalocean-ap/main.tf b/modules/digitalocean-ap/main.tf new file mode 100644 index 0000000..e546457 --- /dev/null +++ b/modules/digitalocean-ap/main.tf @@ -0,0 +1,104 @@ +terraform { + required_providers { + digitalocean = { + source = "digitalocean/digitalocean" + version = "~> 2.0" + } + } +} + +provider "digitalocean" { + token = var.digitalocean_token +} + +resource "digitalocean_app" "main" { + spec { + name = "onebusaway-api-server" + region = var.region + + service { + name = "onebusaway-api-webapp" + image { + registry_type = "DOCKER_HUB" + registry = "opentransitsoftwarefoundation" + repository = "onebusaway-api-webapp" + tag = "2.5.12-cs-v1.0.0" + } + instance_size_slug = var.instance_size_slug + instance_count = var.num_instances + + env { + key = "TZ" + value = var.env_var_tz + scope = "RUN_AND_BUILD_TIME" + } + env { + key = "GTFS_URL" + value = var.env_var_gtfs_url + scope = "RUN_AND_BUILD_TIME" + } + env { + key = "VEHICLE_POSITIONS_URL" + value = var.env_var_vehicle_positions_url + scope = "RUN_AND_BUILD_TIME" + } + env { + key = "TRIP_UPDATES_URL" + value = var.env_var_trip_updates_url + scope = "RUN_AND_BUILD_TIME" + } + env { + key = "ALERTS_URL" + value = var.env_var_alerts_url + scope = "RUN_AND_BUILD_TIME" + } + env { + key = "FEED_API_KEY" + value = var.env_var_feed_api_key + scope = "RUN_AND_BUILD_TIME" + } + env { + key = "FEED_API_VALUE" + value = var.env_var_feed_api_value + scope = "RUN_AND_BUILD_TIME" + } + env { + key = "REFRESH_INTERVAL" + value = var.env_var_refresh_interval + scope = "RUN_AND_BUILD_TIME" + } + env { + key = "AGENCY_ID" + value = var.env_var_agency_id + scope = "RUN_AND_BUILD_TIME" + } + env { + key = "JDBC_USER" + value = var.env_var_jdbc_user + scope = "RUN_AND_BUILD_TIME" + } + env { + key = "JDBC_PASSWORD" + value = var.env_var_jdbc_password + scope = "RUN_AND_BUILD_TIME" + } + env { + key = "JDBC_URL" + value = var.env_var_jdbc_url + scope = "RUN_AND_BUILD_TIME" + } + env { + key = "PORT" + value = var.env_var_port + scope = "RUN_AND_BUILD_TIME" + } + + http_port = var.env_var_port + + health_check { + http_path = "/onebusaway-api-webapp/api/where/current-time.json?key=org.onebusaway.iphone" + port = var.env_var_port + } + } + } +} diff --git a/modules/digitalocean-ap/readme.md b/modules/digitalocean-ap/readme.md new file mode 100644 index 0000000..638b09f --- /dev/null +++ b/modules/digitalocean-ap/readme.md @@ -0,0 +1,73 @@ +# Deployment Guide for DigitalOcean App Platform + +DigitalOcean App Platform is a platform-as-a-service (PaaS) that makes it easy to build, deploy, and scale apps quickly. This guide will walk you through deploying the OneBusAway server on DigitalOcean App Platform using Opentofu. + +> [!WARNING] +> Currently DigitalOcean App Platform's gVisor is conflicting with supervisor, they already know this issue and will fix it in the future. +> +> FYI: [App platform supervisor error](https://www.digitalocean.com/community/questions/app-platform-supervisor-error) + +## Prerequisites + +1. A [DigitalOcean](https://www.digitalocean.com/) account. If you don't have one, you can create an account [here](https://cloud.digitalocean.com/registrations/new). + +2. A DigitalOcean API token, which you can generate from the [DigitalOcean Control Panel](https://cloud.digitalocean.com/account/api/tokens). + +3. Opentofu, an open-source Terraform alternative. You can install it by following the instructions [here](https://opentofu.org/docs/intro/install/). + +4. Ensure you have *ALL* the prerequisites installed before starting the deployment. + +## Steps + +1. Clone this repository to your local machine. You can run: + +```bash +git clone https://github.com/OneBusAway/onebusaway-deployment.git +cd onebusaway-deployment/modules/digitalocean-ap +``` + +2. Initialize the project. This will download the necessary plugins and providers for the project: + +```bash +tofu init +``` + +3. Create a `terraform.tfvars` file by copying the example variables file, and then modify it according to your needs: + +```bash +cp terraform.tfvars.example terraform.tfvars +``` + +4. Edit the `terraform.tfvars` file and update the variable values to match your specific requirements, such as your DigitalOcean API token, region, instance size, environment variables, and more. + +5. Run Tofu plan to preview the infrastructure changes: + +```bash +tofu plan +``` + +6. Apply the Tofu configuration to create the actual resources: + +```bash +tofu apply +``` + +Type `yes` when prompted to confirm the resource creation. + +7. After the deployment is complete, verify the created resources in the DigitalOcean Control Panel. Ensure the App Platform service, environment variables, and other related resources are created and running correctly. + +8. Access the OneBusAway server by visiting the public URL of the App Platform service. You can find the service URL in the DigitalOcean Control Panel under the App Platform service details. + +## Clean up + +If you want to shut down the server and clean up the resources, you can run the following command: + +```bash +tofu destroy +``` + +Opentofu will destroy all resources created by this project, including the DigitalOcean App Platform service and associated resources. + +## Conclusion + +This guide shows you how to deploy the OneBusAway server on DigitalOcean App Platform using Opentofu. If you have any questions or suggestions, feel free to open an issue in this repository. diff --git a/modules/digitalocean-ap/terraform.tfvars.example b/modules/digitalocean-ap/terraform.tfvars.example new file mode 100644 index 0000000..fa3d450 --- /dev/null +++ b/modules/digitalocean-ap/terraform.tfvars.example @@ -0,0 +1,18 @@ +digitalocean_token = "" +region = "nyc3" +instance_size_slug = "basic-xxs" +num_instances = 1 + +env_var_tz = "America/Toronto" +env_var_gtfs_url = "https://api.cityofkingston.ca/gtfs/gtfs.zip" +env_var_vehicle_positions_url = "https://api.cityofkingston.ca/gtfs-realtime/vehicleupdates.pb" +env_var_trip_updates_url = "https://api.cityofkingston.ca/gtfs-realtime/tripupdates.pb" +env_var_alerts_url = "https://api.cityofkingston.ca/gtfs-realtime/alerts.pb" +env_var_feed_api_key = "" +env_var_feed_api_value = "" +env_var_refresh_interval = 30 +env_var_agency_id = "0" +env_var_jdbc_user = "oba_user" +env_var_jdbc_password = "oba_password" +env_var_jdbc_url = "jdbc:mysql://:/oba_database" +env_var_port = 8080 diff --git a/modules/digitalocean-ap/variables.tf b/modules/digitalocean-ap/variables.tf new file mode 100644 index 0000000..34e2585 --- /dev/null +++ b/modules/digitalocean-ap/variables.tf @@ -0,0 +1,89 @@ +variable "digitalocean_token" { + description = "DigitalOcean API Token" + type = string +} + +variable "region" { + description = "The slug for the DigitalOcean data center region hosting the app." + type = string + default = "nyc3" +} + +variable "instance_size_slug" { + description = "The instance size to use for this component. This determines the plan (basic or professional) and the available CPU and memory. " + type = string + default = "basic-xxs" +} + +variable "num_instances" { + description = "Number of instances" + type = number + default = 1 +} + +variable "env_var_tz" { + description = "Timezone" + type = string +} + +variable "env_var_gtfs_url" { + description = "GTFS URL" + type = string +} + +variable "env_var_vehicle_positions_url" { + description = "Vehicle positions URL" + type = string +} + +variable "env_var_trip_updates_url" { + description = "Trip updates URL" + type = string +} + +variable "env_var_alerts_url" { + description = "Alerts URL" + type = string +} + +variable "env_var_feed_api_key" { + description = "Feed API Key" + type = string +} + +variable "env_var_feed_api_value" { + description = "Feed API Value" + type = string +} + +variable "env_var_refresh_interval" { + description = "Refresh interval" + type = number + default = 30 +} + +variable "env_var_agency_id" { + description = "Agency ID" + type = string +} + +variable "env_var_jdbc_user" { + description = "JDBC User" + type = string +} + +variable "env_var_jdbc_password" { + description = "JDBC Password" + type = string +} + +variable "env_var_jdbc_url" { + description = "JDBC URL" + type = string +} + +variable "env_var_port" { + description = "Port" + type = number + default = 8080 +} diff --git a/modules/digitalocean-droplets/.env.example b/modules/digitalocean-droplets/.env.example new file mode 100644 index 0000000..2d8d507 --- /dev/null +++ b/modules/digitalocean-droplets/.env.example @@ -0,0 +1,16 @@ +GTFS_URL=https://api.cityofkingston.ca/gtfs/gtfs.zip +TEST_API_KEY=test +VEHICLE_POSITIONS_URL=https://api.cityofkingston.ca/gtfs-realtime/vehicleupdates.pb +TRIP_UPDATES_URL=https://api.cityofkingston.ca/gtfs-realtime/tripupdates.pb +ALERTS_URL=https://api.cityofkingston.ca/gtfs-realtime/alerts.pb +REFRESH_INTERVAL=30 +AGENCY_ID=0 +TZ=America/Toronto +GOOGLE_MAPS_API_KEY= +GOOGLE_MAPS_CHANNEL_ID= +GOOGLE_MAPS_CLIENT_ID= +# Your Domain Name, leave blank if you don't have one +DOMAIN=oba.example.com +# OBA image version. You can find the available versions at: +# https://hub.docker.com/r/opentransitsoftwarefoundation/onebusaway-api-webapp/tags +OBA_VERSION=latest diff --git a/modules/digitalocean-droplets/.terraform.lock.hcl b/modules/digitalocean-droplets/.terraform.lock.hcl new file mode 100644 index 0000000..da63d6e --- /dev/null +++ b/modules/digitalocean-droplets/.terraform.lock.hcl @@ -0,0 +1,97 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/digitalocean/digitalocean" { + version = "2.40.0" + constraints = "~> 2.0" + hashes = [ + "h1:aSdQ10H0usPL8me9mz6KofChCU/YVLPWgJlG9FlCVCU=", + "zh:00235830abae70642ebefc4d9c00e5eb978e28b74abc6b34f16b078f242aa217", + "zh:09d77785f768bd568f85a121d3d79316083befe903ce4ccd5567689a23236fb0", + "zh:0c9c4e19b411702d316a6bd044903e2ec506a69d38495ed32cc31e3f3f26acae", + "zh:12b34c88faad5b6149e9a3ad1396680588e1bae263b20d6b19835460f111c190", + "zh:15f041fc57ea46673a828919efe2ef3f05f7c4b863b7d7881336b93e92bd1159", + "zh:45e01972de2fab1687a09ea8fb3e4519be11c93ef93a63f28665630850858a20", + "zh:4e18bf5c1d2ec1ec6b6a9f4b58045309006f510edf770168fc18e273e6a09289", + "zh:575528b7e36e3489d2309e0c6cb9bd9952595cac5459b914f2d2827de1a1e4fc", + "zh:67462192212f810875d556462c79f574a8f5713b7a869ba4fce25953bfcf2dd2", + "zh:7024637b31e8276b653265fdf3f479220182edde4b300b034562b4c287faefa5", + "zh:a7904721b2680be8330dde98dd826be15c67eb274da7876f042cbcd6592ac970", + "zh:b225d4b67037a19392b0ab00d1f5fc9e729db4dfc32d18d4b36225693270ef52", + "zh:bd1e8768819d6113b2ec16f939196a1f2ae6d2803824fde463a20d06e071b212", + "zh:c5da40dc0749548ee2e1943776fb41b952c994e50bbc404251df20a81f730242", + "zh:dabc3387392aaba297739e1e97fadf059258fc3efb4dff2f499dbc407b6e088d", + "zh:f42137cf424c3e7c9c935b3f73618e51096bd0367a8d364073e2d70588d2cbf2", + ] +} + +provider "registry.opentofu.org/hashicorp/local" { + version = "2.5.1" + hashes = [ + "h1:87L+rpGao062xifb1VuG9YVFwp9vbDP6G2fgfYxUkQs=", + "h1:IAqLUucFw7Q7R4r+buIJ1AjsDtIX5i3xGYItI4+t07E=", + "zh:031c2c2070672b7e78e0aa15560839278dc57fe7cf1e58a617ac13c67b31d5fb", + "zh:1ef64ea4f8382cd538a76f3d319f405d18130dc3280f1c16d6aaa52a188ecaa4", + "zh:422ce45691b2f384dbd4596fdc8209d95cb43d85a82aaa0173089d38976d6e96", + "zh:7415fbd8da72d9363ba55dd8115837714f9534f5a9a518ec42268c2da1b9ed2f", + "zh:92aa22d071339c8ef595f18a9f9245c287266c80689f5746b26e10eaed04d542", + "zh:9cd0d99f5d3be835d6336c19c4057af6274e193e677ecf6370e5b0de12b4aafe", + "zh:a8c1525b389be5809a97f02aa7126e491ba518f97f57ed3095a3992f2134bb8f", + "zh:b336fa75f72643154b07c09b3968e417a41293358a54fe03efc0db715c5451e6", + "zh:c66529133599a419123ad2e42874afbd9aba82bd1de2b15cc68d2a1e665d4c8e", + "zh:c7568f75ba6cb7c3660b69eaab8b0e4278533bd9a7a4c33ee6590cc7e69743ea", + ] +} + +provider "registry.opentofu.org/hashicorp/null" { + version = "3.2.2" + hashes = [ + "h1:VGyIk6jYf5QJIS4qvU8uhXGq+HBHjNHTBiuEZOjYsOE=", + "h1:sU0t6ANQ4IfEwZbbBmcNeOCg2CDCViVb7L7QVfIHrCs=", + "zh:00e5877d19fb1c1d8c4b3536334a46a5c86f57146fd115c7b7b4b5d2bf2de86d", + "zh:1755c2999e73e4d73f9de670c145c9a0dc5a373802799dff06a0e9c161354163", + "zh:2b29d706353bc9c4edda6a2946af3322abe94372ffb421d81fa176f1e57e33be", + "zh:34f65259c6d2bd51582b6da536e782b181b23725782b181193b965f519fbbacd", + "zh:370f6eb744475926a1fa7464d82d46ad83c2e1148b4b21681b4cec4d75b97969", + "zh:5950bdb23b4fcc6431562d7eba3dea37844aa4220c4da2eb898ae3e4d1b64ec4", + "zh:8f3d5c8d4b9d497fec36953a227f80c76d37fc8431b683a23fb1c42b9cccbf8a", + "zh:8f6eb5e65c047bf490ad3891efecefc488503b65898d4ee106f474697ba257d7", + "zh:a7040eed688316fe00379574c72bb8c47dbe2638b038bb705647cbf224de8f72", + "zh:e561f28df04d9e51b75f33004b7767a53c45ad96e3375d86181ba1363bffbc77", + ] +} + +provider "registry.opentofu.org/hashicorp/random" { + version = "3.6.2" + hashes = [ + "h1:V5b9JmAN3KmYnWrptzPHfVn1ZOSALkMoMM2FJBR1ak8=", + "zh:1f27612f7099441526d8af59f5b4bdcc35f46915df5d243043d7337ea5a3e38a", + "zh:2a58e66502825db8b4b96116c04bd0323bca1cf1f5752bdd8f9c26feb84d3b1e", + "zh:4f0a4fa479e29de0c3c90146fd58799c097f7a55401cb00560dd4e9b1e6fad9d", + "zh:9c93c0fe6ef685513734527e0c8078636b2cc07591427502a7260f4744b1af1d", + "zh:a466ff5219beb77fb3b18a3d7e7fe30e7edd4d95c8e5c87f4f4e3fe3eeb8c2d7", + "zh:ab33e6176d0c757ddb31e40e01a941e6918ad10f7a786c8e8e4f35e5cff81c96", + "zh:b6eabf377a1c12cb3f9ddd97aacdd5b49c1646dc959074124f81d40fcd216d7e", + "zh:ccec5d03d0d1c0f354be299cdd6a417b2700f1a6781df36bcce77246b2f57e50", + "zh:d2a7945eeb691fdd2b1474da76ddc2d1655e2aedbb14b57f06d4f5123d47adf9", + "zh:ed62351f4ad9d1469c6798b77dee5f63b18b29c473620a0046ba3d4f111b621d", + ] +} + +provider "registry.opentofu.org/hashicorp/tls" { + version = "4.0.5" + hashes = [ + "h1:LWGTWAUrC+/iTsNq0vxANvGOp+7Jnl4wAnSOW2Shqjc=", + "h1:S4aD5Lo6Q6/lDSj0UtSmYQG9eNmuo/+sQZFh3fxYUOI=", + "zh:05a7dc3ac92005485714f87541ad6d0d478988b478c5774227a7d39b01660050", + "zh:547e0def44080456169bf77c21037aa6dc9e7f3e644a8f6a2c5fc3e6c15cf560", + "zh:6842b03d050ae1a4f1aaed2a2b1ca707eae84ae45ae492e4bb57c3d48c26e1f1", + "zh:6ced0a9eaaba12377f3a9b08df2fd9b83ae3cb357f859eb6aecf24852f718d9a", + "zh:766bcdf71a7501da73d4805d05764dcb7c848619fa7c04b3b9bd514e5ce9e4aa", + "zh:84cc8617ce0b9a3071472863f43152812e5e8544802653f636c866ef96f1ed34", + "zh:b1939e0d44c89315173b78228c1cf8660a6924604e75ced7b89e45196ce4f45e", + "zh:ced317916e13326766427790b1d8946c4151c4f3b0efd8f720a3bc24abe065fa", + "zh:ec9ff3412cf84ba81ca88328b62c17842b803ef406ae19152c13860b356b259c", + "zh:ff064f0071e98702e542e1ce00c0465b7cd186782fe9ccab8b8830cac0f10dd4", + ] +} diff --git a/modules/digitalocean-droplets/docker-compose.caddy.yml b/modules/digitalocean-droplets/docker-compose.caddy.yml new file mode 100644 index 0000000..2db3e6d --- /dev/null +++ b/modules/digitalocean-droplets/docker-compose.caddy.yml @@ -0,0 +1,15 @@ +version: '3' + +services: + caddy: + image: lucaslorentz/caddy-docker-proxy:ci-alpine + ports: + - 80:80 + - 443:443 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - caddy_data:/data + restart: unless-stopped + +volumes: + caddy_data: {} diff --git a/modules/digitalocean-droplets/main.tf b/modules/digitalocean-droplets/main.tf new file mode 100644 index 0000000..01db4cc --- /dev/null +++ b/modules/digitalocean-droplets/main.tf @@ -0,0 +1,97 @@ +terraform { + required_providers { + digitalocean = { + source = "digitalocean/digitalocean" + version = "~> 2.0" + } + } +} + +provider "digitalocean" { + token = var.do_token +} + +resource "random_id" "key" { + byte_length = 4 +} + +resource "digitalocean_ssh_key" "oba" { + name = "oba-key-${random_id.key.hex}" + public_key = local_file.public_key.content + + depends_on = [local_file.public_key] +} + +resource "digitalocean_droplet" "main" { + name = var.vm_name + region = var.region + size = var.size + image = "docker-20-04" + ssh_keys = [digitalocean_ssh_key.oba.fingerprint] + + user_data = <<-EOF + #!/bin/bash + mkdir -p /home/${var.user} + cd /home/${var.user} + + # clone repo + git clone https://github.com/onebusaway/onebusaway-docker.git + + cd /home/${var.user}/onebusaway-docker + + # create .env file + echo "${file("${path.module}/.env")}" > .env + + # onebusaway-api-webapp depends on mysql, normally this will handle by docker-compose + # but in Azure, the mysql container will not be ready when onebusaway-api-webapp starts + # which leads to the error `Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set` + # so we need to start mysql container first + docker compose -f docker-compose.prod.yml up -d oba_database + + sleep 5s + + # start Docker Compose + docker compose -f docker-compose.prod.yml up -d + + if [ -n "${var.caddy}" ]; then + # create docker-compose.caddy.yml + echo "${file("${path.module}/docker-compose.caddy.yml")}" > docker-compose.caddy.yml + # start Caddy + docker compose -f docker-compose.caddy.yml up -d + fi + + ufw allow 8080/tcp + EOF + + tags = ["web"] + + depends_on = [tls_private_key.ssh_key] +} + +resource "tls_private_key" "ssh_key" { + algorithm = "RSA" + rsa_bits = 4096 +} + +resource "local_sensitive_file" "private_key" { + content = tls_private_key.ssh_key.private_key_pem + filename = "${path.module}/ssh/id_rsa" +} + +resource "local_file" "public_key" { + content = tls_private_key.ssh_key.public_key_openssh + filename = "${path.module}/ssh/id_rsa.pub" +} + +# remove ssh keys after destroy +resource "null_resource" "remove_ssh_keys" { + triggers = { + always_run = timestamp() + } + + provisioner "local-exec" { + # replace with `del ${path.module}\\ssh\\id_rsa ${path.module}\\ssh\\id_rsa.pub` on Windows + command = "rm -f ${path.module}/ssh/id_rsa ${path.module}/ssh/id_rsa.pub" + when = destroy + } +} diff --git a/modules/digitalocean-droplets/output.tf b/modules/digitalocean-droplets/output.tf new file mode 100644 index 0000000..fb81cf1 --- /dev/null +++ b/modules/digitalocean-droplets/output.tf @@ -0,0 +1,3 @@ +output "droplet_public_ip" { + value = digitalocean_droplet.main.ipv4_address +} \ No newline at end of file diff --git a/modules/digitalocean-droplets/readme.md b/modules/digitalocean-droplets/readme.md new file mode 100644 index 0000000..725213d --- /dev/null +++ b/modules/digitalocean-droplets/readme.md @@ -0,0 +1,76 @@ +ๆ„Ÿ่ฐขๆ้†’ใ€‚ไปฅไธ‹ๆ˜ฏไฟฎๆ”นๅŽ็š„ๆŒ‡ๅ—๏ผŒๅŽปๆŽ‰ไบ†ไธๅฟ…่ฆ็š„DigitalOcean CLI็™ปๅฝ•ๆญฅ้ชคใ€‚ + +--- + +# Deployment Guide for DigitalOcean Droplets + +DigitalOcean Droplets provide a reliable and cost-effective solution for deploying the OneBusAway server. This guide will walk you through deploying the OneBusAway server on a DigitalOcean Droplet using Opentofu, an open-source Terraform alternative. + +## Prerequisites + +1. A DigitalOcean account. If you don't have one, you can sign up [here](https://cloud.digitalocean.com/registrations/new). + +2. Opentofu, an open-source Terraform alternative, you can install it by following the instructions [here](https://opentofu.org/docs/intro/install/). + +3. Make sure you install *ALL* the prerequisites before you start the deployment. + +## Steps + +1. Clone the repository to your local machine: + ```bash + git clone https://github.com/OneBusAway/onebusaway-deployment.git + ``` + +2. Change the directory to `modules/digitalocean-droplet`: + ```bash + cd onebusaway-deployment/modules/digitalocean-droplets + ``` + +3. Initialize the project, which will download the necessary plugins and providers: + ```bash + tofu init + ``` + +4. Create a `terraform.tfvars` file by copying the `terraform.tfvars.example` file: + ```bash + cp terraform.tfvars.example terraform.tfvars + ``` + +5. Modify the `terraform.tfvars` file according to your needs: + +6. Customize your `.env` file by copying the `.env.example` file from the `onebusaway-docker` repository and modifying it as needed: + ```bash + cp .env.example .env + ``` + +7. Deploy the project: + ```bash + tofu apply + ``` + +8. Opentofu will automatically generate SSH key pairs in the `ssh` folder. You can connect to the server using: + ```bash + ssh -i ./ssh/id_rsa @ + ``` + The `server_ip` can be found in the output of the `tofu apply` command. + +9. After the deployment is complete, wait a few minutes for the server to start. You can access the OneBusAway server by visiting: + ```http://:8080``` + +10. (Optional) If you configured your domain in the `terraform.tfvars` and `.env` file: + - Add an A record pointing to the server's IP address in your domain provider's DNS settings. + - For example, if you use Cloudflare, follow the instructions [here](https://support.cloudflare.com/hc/en-us/articles/360019093151-Managing-DNS-records-in-Cloudflare). + - Caddy will handle the SSL certificate configuration based on this DNS record, allowing you to visit your server securely at `https://`. + +## Clean Up + +If you need to shut down the server and clean up resources, you can run the following command: +```bash +tofu destroy +``` + +Opentofu will destroy all resources created by this project, including the Droplet, network, SSH key pairs, and other related resources. + +## Conclusion + +This guide has demonstrated how to deploy the OneBusAway server on a DigitalOcean Droplet using Opentofu. If you have any questions or suggestions, feel free to open an issue in the repository. diff --git a/modules/digitalocean-droplets/ssh/.gitkeep b/modules/digitalocean-droplets/ssh/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/modules/digitalocean-droplets/terraform.tfvars.example b/modules/digitalocean-droplets/terraform.tfvars.example new file mode 100644 index 0000000..fc9af1b --- /dev/null +++ b/modules/digitalocean-droplets/terraform.tfvars.example @@ -0,0 +1,7 @@ +do_token = "" +vm_name = "OBA" +region = "nyc3" +size = "s-2vcpu-4gb" +firewall_name = "oba-firewall" +user = "oba" +caddy = "" diff --git a/modules/digitalocean-droplets/variables.tf b/modules/digitalocean-droplets/variables.tf new file mode 100644 index 0000000..4dac95c --- /dev/null +++ b/modules/digitalocean-droplets/variables.tf @@ -0,0 +1,25 @@ +variable "do_token" { + description = "DigitalOcean API token" + type = string + sensitive = true +} + +variable "vm_name" { + description = "Name of the Droplet" +} + +variable "region" { + description = "DigitalOcean region" +} + +variable "size" { + description = "Droplet size" +} + +variable "user" { + description = "user name" +} + +variable "caddy" { + description = "Whether to use Caddy or not, leave empty to disable" +} \ No newline at end of file diff --git a/modules/render/.terraform.lock.hcl b/modules/render/.terraform.lock.hcl new file mode 100644 index 0000000..f1742f7 --- /dev/null +++ b/modules/render/.terraform.lock.hcl @@ -0,0 +1,24 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/render-oss/render" { + version = "0.2.1" + hashes = [ + "h1:KpxkBJ2mj9cQVm9dc0CHzYY+zRPxGMMq8h8OjJ6onwc=", + "zh:0736bc9e06ac9b8d806278e92247e6c082aa3987d78cc51ffe6a023bb3e5f1a3", + "zh:07a0d1c11a19cc46116e3ce7b5ee32182ba0306af54fe355d50a8e2c2d457058", + "zh:08be93141b97889f5cc564c502c59aaec5c28bded253b0e8218c144848106d3d", + "zh:20660b1eb167bfe423cc29a7099e1b9d89c0fa73ae4fa423b5bb0c24afe4123b", + "zh:2ecea5c0be1ced95a867523dc1f7caf4ed99a3f1eeb7e5a179043bdc61d1e2a8", + "zh:4ee0845cb302663d02633fbf75ecb1dea5db537e573afd169c36c06227fe5ffd", + "zh:6c9050d4ddc95e5c8aab3354c235bae6af5a12b1b8794713241d14a4d8e46b1b", + "zh:782f637188628502fa0c05dcab3d3554328478f1701670e6f712560d0c38220b", + "zh:7d93528fdc90cd7a0e42b00878c7c956170bf5661ae1e62709671db032e35cce", + "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f", + "zh:92ad3c832678a0e8d99101fa0c2e197b005927c5d00dfcd1792deae6a0e69486", + "zh:9c831d7e0f2d40c29ed66a1cb0f902cb9609d45eedf3b146e43700f968829c39", + "zh:a8c26e49778086f9cc1c249c6be27c9acb81ebacc4a608bd3b21f2f492a50986", + "zh:dcd4312c041c3887afa8e76f7d386090ef9d5ed5cb097c740cf72fbbb9b76b14", + "zh:f14df0dce1c0cbb0e0af950a8e808ffd8f91e193596ed3c05dd55cd0f19bfec3", + ] +} diff --git a/modules/render/main.tf b/modules/render/main.tf new file mode 100644 index 0000000..e75072d --- /dev/null +++ b/modules/render/main.tf @@ -0,0 +1,50 @@ +terraform { + required_providers { + render = { + source = "registry.terraform.io/render-oss/render" + } + } +} + +provider "render" { + api_key = var.api_key + owner_id = var.owner_id +} + +resource "render_web_service" "web" { + name = "OneBusAway API Server" + plan = var.plan + region = var.region + num_instances = var.num_instances + + runtime_source = { + image = { + image_url = var.image_url + } + } + + disk = { + name = "Bundle" + size_gb = var.disk_size_gb + mount_path = "/bundle" + } + + env_vars = { + "TZ" = { value = var.env_var_tz }, + "GTFS_URL" = { value = var.env_var_gtfs_url }, + "VEHICLE_POSITIONS_URL" = { value = var.env_var_vehicle_positions_url }, + "TRIP_UPDATES_URL" = { value = var.env_var_trip_updates_url }, + "ALERTS_URL" = { value = var.env_var_alerts_url }, + "FEED_API_KEY" = { value = var.env_var_feed_api_key }, + "FEED_API_VALUE" = { value = var.env_var_feed_api_value }, + "REFRESH_INTERVAL" = { value = var.env_var_refresh_interval }, + "AGENCY_ID" = { value = var.env_var_agency_id }, + "JDBC_USER" = { value = var.env_var_jdbc_user }, + "JDBC_PASSWORD" = { value = var.env_var_jdbc_password }, + "JDBC_URL" = { value = var.env_var_jdbc_url }, + "PORT" = { value = var.env_var_port } + } + + health_check_path = "/onebusaway-api-webapp/api/where/current-time.json?key=org.onebusaway.iphone" +} + diff --git a/modules/render/readme.md b/modules/render/readme.md new file mode 100644 index 0000000..1965b58 --- /dev/null +++ b/modules/render/readme.md @@ -0,0 +1,66 @@ +# Deployment Guide for Render + +Render is a modern cloud provider that makes it easy to deploy web services, static sites, and databases. This guide will walk you through deploying the OneBusAway server on Render using Opentofu. + +## Prerequisites + +1. A [Render](https://render.com/) account. If you don't have one, you can create a free account [here](https://dashboard.render.com/register). + +2. Opentofu, an open-source Terraform alternative. You can install it by following the instructions [here](https://opentofu.org/docs/intro/install/). + +3. Ensure you have *ALL* the prerequisites installed before starting the deployment. + +## Steps + +1. Clone this repository to your local machine. You can run: + +```bash +git clone https://github.com/OneBusAway/onebusaway-deployment.git +cd onebusaway-deployment/modules/render +``` + +2. Initialize the project. This will download the necessary plugins and providers for the project: + +```bash +tofu init +``` + +3. Create a `terraform.tfvars` file by copying the example variables file, and then modify it according to your needs: + +```bash +cp terraform.tfvars.example terraform.tfvars +``` + +4. Edit the `terraform.tfvars` file and update the variable values to match your specific requirements, such as Render API key, service plan, region, container image details, and environment variables. + +5. Run Tofu plan to preview the infrastructure changes: + +```bash +tofu plan +``` + +6. Apply the Tofu configuration to create the actual resources: + +```bash +tofu apply +``` + +Type `yes` when prompted to confirm the resource creation. + +7. After the deployment is complete, verify the created resources in the Render Dashboard. Ensure the web service, environment variables, and other related resources are created and running correctly. + +8. Access the OneBusAway server by visiting the public URL of the Render service. You can find the service URL in the Render Dashboard under the service details. + +## Clean up + +If you want to shut down the server and clean up the resources, you can run the following command: + +```bash +tofu destroy +``` + +Opentofu will destroy all resources created by this project, including the Render web service and associated resources. + +## Conclusion + +This guide shows you how to deploy the OneBusAway server on Render using Opentofu. If you have any questions or suggestions, feel free to open an issue in this repository. diff --git a/modules/render/terraform.tfvars.example b/modules/render/terraform.tfvars.example new file mode 100644 index 0000000..b24f779 --- /dev/null +++ b/modules/render/terraform.tfvars.example @@ -0,0 +1,21 @@ +api_key = "" +owner_id = "" +region = "oregon" +plan = "standard" +num_instances = 1 +image_url = "opentransitsoftwarefoundation/onebusaway-api-webapp:2.5.12-cs-v1.0.0" +disk_size_gb = 1 + +env_var_tz = "America/Toronto" +env_var_gtfs_url = "https://api.cityofkingston.ca/gtfs/gtfs.zip" +env_var_vehicle_positions_url = "https://api.cityofkingston.ca/gtfs-realtime/vehicleupdates.pb" +env_var_trip_updates_url = "https://api.cityofkingston.ca/gtfs-realtime/tripupdates.pb" +env_var_alerts_url = "https://api.cityofkingston.ca/gtfs-realtime/alerts.pb" +env_var_feed_api_key = "" +env_var_feed_api_value = "" +env_var_refresh_interval = 30 +env_var_agency_id = "0" +env_var_jdbc_user = "oba_user" +env_var_jdbc_password = "oba_password" +env_var_jdbc_url = "jdbc:mysql://:/oba_database" +env_var_port = 8080 diff --git a/modules/render/variables.tf b/modules/render/variables.tf new file mode 100644 index 0000000..f65de1c --- /dev/null +++ b/modules/render/variables.tf @@ -0,0 +1,106 @@ +variable "api_key" { + description = "API key for Render" + type = string +} + +variable "owner_id" { + description = "Owner ID" + type = string +} + +variable "region" { + description = "Region to deploy the service" + type = string + default = "oregon" +} + +variable "plan" { + description = "Service plan" + type = string + default = "starter" +} + +variable "num_instances" { + description = "Number of instances" + type = number + default = 1 +} + +variable "image_url" { + description = "Image URL" + type = string + default = "opentransitsoftwarefoundation/onebusaway-api-webapp:2.4.18-cs-v1.3.0" +} + +variable "disk_size_gb" { + description = "Disk size in GB" + type = number + default = 1 +} + +variable "env_var_tz" { + description = "Timezone" + type = string +} + +variable "env_var_gtfs_url" { + description = "GTFS URL" + type = string +} + +variable "env_var_vehicle_positions_url" { + description = "Vehicle positions URL" + type = string +} + +variable "env_var_trip_updates_url" { + description = "Trip updates URL" + type = string +} + +variable "env_var_alerts_url" { + description = "Alerts URL" + type = string +} + +variable "env_var_feed_api_key" { + description = "Feed API Key" + type = string +} + +variable "env_var_feed_api_value" { + description = "Feed API Value" + type = string +} + +variable "env_var_refresh_interval" { + description = "Refresh interval" + type = number + default = 30 +} + +variable "env_var_agency_id" { + description = "Agency ID" + type = string +} + +variable "env_var_jdbc_user" { + description = "JDBC User" + type = string +} + +variable "env_var_jdbc_password" { + description = "JDBC Password" + type = string +} + +variable "env_var_jdbc_url" { + description = "JDBC URL" + type = string +} + +variable "env_var_port" { + description = "Port" + type = number + default = 8080 +}