diff --git a/README.md b/README.md index 8efb9eb..4d8fe85 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,55 @@ -# Terraform Provider Tsuru [![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/tsuru/terraform-provider-tsuru?label=release)](https://github.com/tsuru/terraform-provider-tsuru/releases) [![license](https://img.shields.io/github/license/tsuru/terraform-provider-tsuru.svg)]() +# Terraform Provider Tsuru - Improved Documentation -- Usage - - [Provider Documentation](https://registry.terraform.io/providers/tsuru/tsuru/latest/docs) - - [Tsuru Documentation](https://docs.tsuru.io/) +Better docs for the terraform-provider-tsuru with practical examples, migration guides, detailed resource documentation, and step-by-step tutorials. -The tsuru provider for Terraform is a plugin that enables lifecycle management of Tsuru resources. This provider is under early development by Tsuru Team. +## Quick Links -## Requirements +**New to Terraform + Tsuru?** Start with [Getting Started](tutorials/01-getting-started.md) + +**Migrating from manual management?** Read the [Migration Guide](guides/migration-guide.md) + +**Need a reference?** Check the [Resource Documentation](resources/) + +## Tutorials + +| Tutorial | What you'll learn | Time | +|----------|-------------------|------| +| [Getting Started](tutorials/01-getting-started.md) | Initial setup and first app | 15 min | +| [Managing Apps](tutorials/02-managing-apps.md) | Environment variables, CNAMEs, autoscaling | 20 min | +| [Jobs](tutorials/03-jobs.md) | Scheduled and manual jobs | 15 min | +| [Infrastructure](tutorials/04-infrastructure.md) | Clusters, pools, and plans | 25 min | + +## Examples + +Ready-to-use examples for common scenarios: + +- [Complete Web App](examples/complete-web-app/) - App with env vars, CNAME, and autoscaling +- [Scheduled Job](examples/scheduled-job/) - Job with cron schedule +- [Cluster Setup](examples/cluster-setup/) - Cluster and pool configuration + +## Resource Documentation + +Detailed docs for key resources: + +- [tsuru_app](resources/app.md) - Application management +- [tsuru_cluster](resources/cluster.md) - Kubernetes cluster configuration + +## Migration Guide + +Moving from manual Tsuru management to Terraform? The [Migration Guide](guides/migration-guide.md) covers: + +- Migration strategies (big bang vs gradual) +- Using `terraform import` +- Import order and validation +- Rollback procedures + +## Contributing + +Found an issue or want to add more examples? Contributions welcome. + +## Additional Resources + +- [Official Provider Docs](https://registry.terraform.io/providers/tsuru/tsuru/latest/docs) +- [Tsuru Documentation](https://docs.tsuru.io/) +- [Provider Repository](https://github.com/tsuru/terraform-provider-tsuru) -- [Terraform](https://www.terraform.io/downloads.html) 1.4.4 -- [Go](https://golang.org/doc/install) 1.21.0 (to build the provider plugin) diff --git a/examples/cluster-setup/README.md b/examples/cluster-setup/README.md new file mode 100644 index 0000000..56980d1 --- /dev/null +++ b/examples/cluster-setup/README.md @@ -0,0 +1,19 @@ +# Cluster Setup Example + +This example shows how to add a Kubernetes cluster to Tsuru and associate it with a pool. + +## Usage + +```bash +terraform init +terraform apply +``` + +After applying, you'll have a new cluster `my-k8s-cluster` connected to the pool `my-pool`. + +## Resources used + +- `tsuru_cluster` - Kubernetes cluster +- `tsuru_pool` - Resource pool +- `tsuru_cluster_pool` - Cluster-pool association + diff --git a/examples/cluster-setup/main.tf b/examples/cluster-setup/main.tf new file mode 100644 index 0000000..bd986f8 --- /dev/null +++ b/examples/cluster-setup/main.tf @@ -0,0 +1,22 @@ +resource "tsuru_cluster" "k8s_cluster" { + name = "my-k8s-cluster" + provisioner = "kubernetes" + crio = true + + kube_config { + cluster { + server = "https://my-k8s-cluster.example.com" + } + } +} + +resource "tsuru_pool" "my_pool" { + name = "my-pool" + provisioner = "kubernetes" +} + +resource "tsuru_cluster_pool" "cluster_pool_attachment" { + cluster = tsuru_cluster.k8s_cluster.name + pool = tsuru_pool.my_pool.name +} + diff --git a/examples/complete-web-app/README.md b/examples/complete-web-app/README.md new file mode 100644 index 0000000..30c6cae --- /dev/null +++ b/examples/complete-web-app/README.md @@ -0,0 +1,24 @@ +# Complete Web Application Example + +This example shows how to set up a production-ready web application on Tsuru with environment variables, custom domain, and autoscaling. + +## What's included + +This configuration creates an app with environment variables for database and cache connections, adds a custom CNAME, and configures autoscaling based on CPU usage and business hours. + +## Usage + +```bash +terraform init +terraform apply +``` + +After applying, your app will be available at `www.complete-web-app.com` with automatic scaling between 2-5 units based on CPU load, maintaining at least 3 units during weekday business hours (8am-8pm). + +## Resources used + +- `tsuru_app` - Base application +- `tsuru_app_env` - Environment variables +- `tsuru_app_cname` - Custom domain +- `tsuru_app_autoscale` - Scaling configuration + diff --git a/examples/complete-web-app/main.tf b/examples/complete-web-app/main.tf new file mode 100644 index 0000000..01a99a2 --- /dev/null +++ b/examples/complete-web-app/main.tf @@ -0,0 +1,57 @@ +resource "tsuru_app" "web_app" { + name = "complete-web-app" + description = "Complete web application example" + plan = "c0.1m0.2" + pool = "staging" + platform = "python" + team_owner = "admin" + tags = ["terraform", "example", "web"] + + metadata { + labels = { + "app" = "web-app" + "component" = "frontend" + } + annotations = { + "owner" = "team-alpha" + } + } + + restart_on_update = true +} + +resource "tsuru_app_env" "app_env" { + app = tsuru_app.web_app.name + + environment_variables = { + "DATABASE_URL" = "postgres://user:password@host:port/dbname" + "CACHE_URL" = "redis://host:port" + } + + no_restart = false +} + +resource "tsuru_app_cname" "app_cname" { + app = tsuru_app.web_app.name + cname = "www.complete-web-app.com" +} + +resource "tsuru_app_autoscale" "app_autoscale" { + app = tsuru_app.web_app.name + + min_units = 2 + max_units = 5 + + cpu { + target = "80%" + } + + schedules = [ + { + start = "0 8 * * 1-5" + end = "0 20 * * 1-5" + min_replicas = 3 + } + ] +} + diff --git a/examples/scheduled-job/README.md b/examples/scheduled-job/README.md new file mode 100644 index 0000000..f4e32b6 --- /dev/null +++ b/examples/scheduled-job/README.md @@ -0,0 +1,23 @@ +# Scheduled Job Example + +This example demonstrates how to create and deploy a scheduled job that runs every hour. + +## Usage + +```bash +terraform init +terraform apply +``` + +The job will run automatically every hour. You can check its execution logs with: + +```bash +tsuru job info -j my-scheduled-job +tsuru job log -j my-scheduled-job +``` + +## Resources used + +- `tsuru_job` - Job definition with schedule +- `tsuru_job_deploy` - Job deployment + diff --git a/examples/scheduled-job/main.tf b/examples/scheduled-job/main.tf new file mode 100644 index 0000000..d9357d8 --- /dev/null +++ b/examples/scheduled-job/main.tf @@ -0,0 +1,19 @@ +resource "tsuru_job" "scheduled_job" { + name = "my-scheduled-job" + description = "Scheduled job example" + pool = "staging" + team_owner = "admin" + + container { + image = "ubuntu:latest" + command = ["echo", "Hello from Tsuru Job!"] + } + + schedule = "@every 1h" +} + +resource "tsuru_job_deploy" "job_deploy" { + job = tsuru_job.scheduled_job.name + image = "ubuntu:latest" +} + diff --git a/guides/migration-guide.md b/guides/migration-guide.md new file mode 100644 index 0000000..feb23eb --- /dev/null +++ b/guides/migration-guide.md @@ -0,0 +1,102 @@ +# Migration Guide + +Moving from manual Tsuru management to Terraform gives you version control, automation, and reproducibility for your infrastructure. + +## Before you start + +Take inventory of your current Tsuru resources. List everything you have: + +```bash +tsuru app list +tsuru service instance list +tsuru pool list +tsuru cluster list +tsuru job list +``` + +Save this output - you'll need it to write your Terraform configs. + +## Migration strategies + +**Big Bang** +Import everything at once. Faster but riskier. Best for small environments or non-production. + +**Gradual** +Import resources in phases. Safer for production. Start with one team or a few non-critical apps. + +## How terraform import works + +Terraform import brings existing resources under Terraform management without recreating them. You need to: + +1. Write the resource definition in your `.tf` file +2. Run `terraform import` to link it to the real resource +3. Run `terraform plan` to verify everything matches + +### Example: Importing an app + +First, write the resource definition: + +```terraform +resource "tsuru_app" "my_app" { + name = "my-app" + description = "Imported app" + plan = "c0.1m0.2" + pool = "staging" + platform = "python" + team_owner = "admin" +} +``` + +Then import it: + +```bash +terraform import tsuru_app.my_app "my-app" +``` + +Check if it worked: + +```bash +terraform plan +``` + +If you see changes, your definition doesn't match reality. Adjust it until `terraform plan` shows no changes. + +## Import order + +Follow this sequence to avoid dependency issues: + +1. Clusters and pools +2. Apps and their resources (env vars, CNAMEs, autoscale) +3. Services and bindings +4. Jobs + +## Validation + +After each import: + +- Run `terraform plan` - should show zero changes +- Test the app/service to make sure it still works +- Commit your code + +## Rollback + +If something breaks: + +- Revert to the previous git commit +- Run `terraform apply` to restore the old state +- Or remove the resource from Terraform with `terraform state rm` + +## Checklist + +- [ ] Inventory all Tsuru resources +- [ ] Choose migration strategy +- [ ] Set up Terraform with tsuru provider +- [ ] Write resource definitions +- [ ] Import clusters and pools +- [ ] Import apps and related resources +- [ ] Import services +- [ ] Import jobs +- [ ] Validate with `terraform plan` after each step +- [ ] Test apps functionality +- [ ] Backup `terraform.tfstate` + diff --git a/resources/app.md b/resources/app.md new file mode 100644 index 0000000..d938f78 --- /dev/null +++ b/resources/app.md @@ -0,0 +1,100 @@ +# tsuru_app + +Manages a Tsuru application. + +## Basic example + +```terraform +resource "tsuru_app" "simple" { + name = "my-app" + description = "My application" + plan = "c0.1m0.2" + pool = "staging" + platform = "python" + team_owner = "my-team" +} +``` + +## Advanced example with processes + +```terraform +resource "tsuru_app" "api" { + name = "web-api" + description = "Web API with custom processes" + plan = "c0.2m0.5" + pool = "production" + platform = "go" + team_owner = "api-team" + tags = ["api", "backend"] + + metadata { + labels = { + "app.kubernetes.io/name": "web-api" + } + annotations = { + "monitoring.tsuru.io/scrape": "true" + } + } + + process { + name = "web" + plan = "c0.5m1.0" + } + + process { + name = "worker" + plan = "c0.2m0.5" + } + + restart_on_update = true +} +``` + +## Arguments + +### Required + +- `name` - App name (must be unique) +- `plan` - Resource plan (CPU/memory allocation) +- `platform` - Platform (python, go, nodejs, etc) +- `pool` - Pool where the app runs +- `team_owner` - Team that owns the app + +### Optional + +- `custom_cpu_burst` - CPU burst factor +- `default_router` - Default router for the app +- `description` - App description +- `metadata` - Labels and annotations +- `process` - Per-process configuration +- `restart_on_update` - Restart app when config changes (default: false) +- `tags` - List of tags + +### Read-only + +- `cluster` - Cluster name where app is running +- `id` - Resource ID (same as name) +- `internal_address` - Internal addresses +- `router` - Router information + +## Import + +```bash +terraform import tsuru_app.my_app "app-name" +``` + +## Common issues + +**404 Not Found when importing** +Check the app name and verify you have access to it. + +**Plan shows unexpected changes after import** +Your Terraform config doesn't match the real app. Check metadata and process configs carefully. + +## Related resources + +- `tsuru_app_deploy` +- `tsuru_app_env` +- `tsuru_app_cname` +- `tsuru_app_autoscale` + diff --git a/resources/cluster.md b/resources/cluster.md new file mode 100644 index 0000000..23e0bc7 --- /dev/null +++ b/resources/cluster.md @@ -0,0 +1,95 @@ +# tsuru_cluster + +Manages a Kubernetes cluster in Tsuru. + +## Token authentication example + +```terraform +resource "tsuru_cluster" "gke" { + name = "my-gke-cluster" + provisioner = "kubernetes" + + kube_config { + cluster { + server = "https://k8s.example.com" + ca_cert = filebase64("~/.kube/ca.crt") + } + user { + token = var.k8s_token + } + } + + pools = ["pool1", "pool2"] + default = true +} +``` + +## Certificate authentication example + +```terraform +resource "tsuru_cluster" "on_prem" { + name = "on-premises-cluster" + provisioner = "kubernetes" + crio = true + + kube_config { + cluster { + server = "https://k8s-api.internal" + } + user { + client_certificate = filebase64("path/to/client.crt") + client_key = filebase64("path/to/client.key") + } + } +} +``` + +## Arguments + +### Required + +- `name` - Cluster name (must be unique) +- `provisioner` - Provisioner type (currently only "kubernetes") +- `kube_config` - Kubernetes connection config + +### Optional + +- `crio` - Use CRI-O as container runtime (default: false) +- `custom_data` - Custom data map +- `default` - Make this the default cluster (default: false) +- `pools` - List of pools to associate with this cluster + +### kube_config block + +**cluster block:** +- `server` - Kubernetes API server URL +- `ca_cert` - CA certificate (base64) +- `insecure_skip_tls_verify` - Skip TLS verification (not recommended for production) + +**user block:** +- `token` - Bearer token for auth +- `client_certificate` - Client cert (base64) +- `client_key` - Client key (base64) + +## Import + +```bash +terraform import tsuru_cluster.my_cluster "cluster-name" +``` + +## Common issues + +**Connection errors** +Check that the server URL is correct and accessible from where Tsuru runs. + +**Authentication failures** +Verify your token/certs are valid and have the right RBAC permissions in Kubernetes. + +**Pool association fails** +Make sure the pools exist before associating them. Consider using `tsuru_cluster_pool` resource instead. + +## Related resources + +- `tsuru_pool` +- `tsuru_cluster_pool` + diff --git a/tutorials/01-getting-started.md b/tutorials/01-getting-started.md new file mode 100644 index 0000000..139250c --- /dev/null +++ b/tutorials/01-getting-started.md @@ -0,0 +1,92 @@ +# Getting Started + +This tutorial walks you through setting up the Tsuru provider and creating your first app. + +## Setup + +Create a new directory and a `main.tf` file: + +```bash +mkdir tsuru-terraform +cd tsuru-terraform +``` + +Add the provider configuration to `main.tf`: + +```terraform +terraform { + required_providers { + tsuru = { + source = "tsuru/tsuru" + version = "~> 2.17.0" + } + } +} + +provider "tsuru" {} +``` + +## Authentication + +Set your Tsuru credentials as environment variables: + +```bash +export TSURU_TARGET="https://tsuru.example.com" +export TSURU_TOKEN="your-auth-token" +``` + +Don't put credentials in your Terraform files. + +## Create an app + +Add this to your `main.tf`: + +```terraform +resource "tsuru_app" "first_app" { + name = "my-first-app" + description = "My first Terraform-managed app" + platform = "python" + team_owner = "my-team" + pool = "my-pool" + plan = "small" +} +``` + +Update `team_owner`, `pool`, and `plan` to match your Tsuru environment. + +## Apply + +```bash +terraform init +terraform plan +terraform apply +``` + +Type `yes` when prompted. Your app is now created in Tsuru. + +## Deploy + +Creating the app doesn't deploy code. Deploy using the Tsuru client: + +```bash +echo "web: python app.py" > Procfile +echo "print('Hello!')" > app.py +tsuru app deploy -a my-first-app -f . +``` + +Check the app: + +```bash +tsuru app info -a my-first-app +tsuru app log -a my-first-app +``` + +## Next steps + +Now that you have a basic app, you can add: +- Environment variables with `tsuru_app_env` +- Custom domains with `tsuru_app_cname` +- Autoscaling with `tsuru_app_autoscale` + +Check out the next tutorial to learn more. + diff --git a/tutorials/02-managing-apps.md b/tutorials/02-managing-apps.md new file mode 100644 index 0000000..6465fa6 --- /dev/null +++ b/tutorials/02-managing-apps.md @@ -0,0 +1,124 @@ +# Managing Applications + +This tutorial covers environment variables, custom domains, and autoscaling. + +## Environment variables + +Add environment variables to your app: + +```terraform +resource "tsuru_app_env" "app_config" { + app = tsuru_app.first_app.name + + environment_variables = { + "DATABASE_URL" = "postgres://user:pass@host:port/db" + "DEBUG" = "false" + } +} +``` + +For secrets, use a secrets manager instead of hardcoding values. + +## Custom domain + +Add a CNAME to your app: + +```terraform +resource "tsuru_app_cname" "app_domain" { + app = tsuru_app.first_app.name + cname = "app.example.com" +} +``` + +Remember to configure your DNS to point to Tsuru's router. + +## Autoscaling + +Scale based on CPU and schedule: + +```terraform +resource "tsuru_app_autoscale" "app_scaling" { + app = tsuru_app.first_app.name + + min_units = 2 + max_units = 10 + + cpu { + target = "70%" + } + + schedules = [ + { + start = "0 9 * * 1-5" + end = "0 18 * * 1-5" + min_replicas = 3 + timezone = "America/Sao_Paulo" + } + ] +} +``` + +This keeps 2-10 units, scales at 70% CPU, and guarantees 3 units during weekday business hours. + +## Complete example + +Your `main.tf` should now look like this: + +```terraform +terraform { + required_providers { + tsuru = { + source = "tsuru/tsuru" + version = "~> 2.17.0" + } + } +} + +provider "tsuru" {} + +resource "tsuru_app" "first_app" { + name = "my-first-app" + description = "My first Terraform-managed app" + platform = "python" + team_owner = "my-team" + pool = "my-pool" + plan = "small" +} + +resource "tsuru_app_env" "app_config" { + app = tsuru_app.first_app.name + + environment_variables = { + "DATABASE_URL" = "postgres://user:pass@host:port/db" + "DEBUG" = "false" + } +} + +resource "tsuru_app_cname" "app_domain" { + app = tsuru_app.first_app.name + cname = "app.example.com" +} + +resource "tsuru_app_autoscale" "app_scaling" { + app = tsuru_app.first_app.name + + min_units = 2 + max_units = 10 + + cpu { + target = "70%" + } + + schedules = [ + { + start = "0 9 * * 1-5" + end = "0 18 * * 1-5" + min_replicas = 3 + timezone = "America/Sao_Paulo" + } + ] +} +``` + +Run `terraform apply` to update your app with these new configurations. + diff --git a/tutorials/03-jobs.md b/tutorials/03-jobs.md new file mode 100644 index 0000000..6cf70e9 --- /dev/null +++ b/tutorials/03-jobs.md @@ -0,0 +1,76 @@ +# Jobs and Scheduled Tasks + +Jobs are tasks that run and finish, unlike apps that run continuously. + +## Create a scheduled job + +Add this to a new file `job.tf`: + +```terraform +resource "tsuru_job" "daily_report" { + name = "daily-report-job" + description = "Generates daily report" + team_owner = "my-team" + pool = "my-pool" + plan = "small" + + schedule = "0 8 * * *" + + container { + image = "my-registry/report-generator:v1.0" + command = ["/app/generate-report", "--type=daily"] + } +} +``` + +The schedule uses cron format. This job runs every day at 8am. + +## Deploy the job + +```terraform +resource "tsuru_job_deploy" "report_deploy" { + job = tsuru_job.daily_report.name + image = "my-registry/report-generator:v1.0" +} +``` + +Apply the changes: + +```bash +terraform apply +``` + +## Check job status + +```bash +tsuru job info -j daily-report-job +tsuru job log -j daily-report-job +``` + +## Manual jobs + +For jobs that run on demand, omit the schedule: + +```terraform +resource "tsuru_job" "manual_task" { + name = "db-migration" + description = "Database migration job" + team_owner = "my-team" + pool = "my-pool" + plan = "medium" + + container { + image = "my-registry/db-migrator:latest" + command = ["/app/run-migrations"] + } +} +``` + +Run it manually: + +```bash +tsuru job run -j db-migration +``` + +This is useful for maintenance tasks or migrations that need manual triggering. + diff --git a/tutorials/04-infrastructure.md b/tutorials/04-infrastructure.md new file mode 100644 index 0000000..8170848 --- /dev/null +++ b/tutorials/04-infrastructure.md @@ -0,0 +1,99 @@ +# Infrastructure and Clusters + +Manage your Tsuru infrastructure: clusters, pools, and resource plans. + +## Add a Kubernetes cluster + +Create `infrastructure.tf`: + +```terraform +resource "tsuru_cluster" "prod" { + name = "prod-cluster" + provisioner = "kubernetes" + + kube_config { + cluster { + server = "https://k8s.prod.example.com" + ca_cert = filebase64("~/.kube/prod-ca.crt") + } + user { + token = var.k8s_token + } + } + + default = true +} +``` + +Use variables for sensitive data like tokens. + +## Create pools + +```terraform +resource "tsuru_pool" "production" { + name = "production" + provisioner = "kubernetes" +} + +resource "tsuru_pool" "staging" { + name = "staging" + provisioner = "kubernetes" +} +``` + +## Connect clusters to pools + +```terraform +resource "tsuru_cluster_pool" "prod_to_prod" { + cluster = tsuru_cluster.prod.name + pool = tsuru_pool.production.name +} + +resource "tsuru_cluster_pool" "prod_to_staging" { + cluster = tsuru_cluster.prod.name + pool = tsuru_pool.staging.name +} +``` + +Now the prod cluster can run apps from both pools. + +## Define resource plans + +```terraform +resource "tsuru_plan" "small" { + name = "small" + cpu = "100m" + memory = "256Mi" +} + +resource "tsuru_plan" "medium" { + name = "medium" + cpu = "500m" + memory = "1Gi" +} + +resource "tsuru_plan" "large" { + name = "large" + cpu = "2000m" + memory = "4Gi" +} +``` + +Apps can now reference these plans by name. + +## Apply and verify + +```bash +terraform apply +``` + +Check what was created: + +```bash +tsuru cluster list +tsuru pool list +tsuru plan list +``` + +Managing infrastructure as code makes it easy to replicate environments and keep everything in version control. +