Migrate state
This commit is contained in:
1 parent
e0db317146
commit
c34ccf60e5
4 files changed
+53
-6
No files matched your search
@@ -7,3 +7,9 @@ RAILWAY_API_TOKEN=
|
|||||||
# Cloudflare API token for the aerlinn.net DNS records: Zone.DNS Edit and
|
# Cloudflare API token for the aerlinn.net DNS records: Zone.DNS Edit and
|
||||||
# Zone.Zone Read, on that zone only.
|
# Zone.Zone Read, on that zone only.
|
||||||
CLOUDFLARE_API_TOKEN=
|
CLOUDFLARE_API_TOKEN=
|
||||||
|
|
||||||
|
# Keys for the tfstate bucket on Railway, where every project's Terraform state
|
||||||
|
# lives: `railway bucket credentials` in the tfstate project, or the bucket's
|
||||||
|
# Credentials tab in the dashboard.
|
||||||
|
TFSTATE_ACCESS_KEY_ID=
|
||||||
|
TFSTATE_SECRET_ACCESS_KEY=
|
||||||
@@ -41,6 +41,13 @@ services:
|
|||||||
terraform:
|
terraform:
|
||||||
<<: *tool
|
<<: *tool
|
||||||
image: hashicorp/terraform:1.16.3
|
image: hashicorp/terraform:1.16.3
|
||||||
|
environment:
|
||||||
|
- RAILWAY_TOKEN=${RAILWAY_API_TOKEN:-}
|
||||||
|
- CLOUDFLARE_API_TOKEN
|
||||||
|
# The S3 backend reads AWS_* names; the bucket is Railway's.
|
||||||
|
- AWS_ACCESS_KEY_ID=${TFSTATE_ACCESS_KEY_ID:-}
|
||||||
|
- AWS_SECRET_ACCESS_KEY=${TFSTATE_SECRET_ACCESS_KEY:-}
|
||||||
|
- HOME=/tmp
|
||||||
|
|
||||||
railway:
|
railway:
|
||||||
<<: *tool
|
<<: *tool
|
||||||
|
|||||||
+24
-5
@@ -32,8 +32,9 @@ Commit `.terraform.lock.hcl`; it pins the provider builds.
|
|||||||
## First-time setup
|
## First-time setup
|
||||||
|
|
||||||
1. **Tokens.** A Railway workspace token (account settings -> Tokens, with the
|
1. **Tokens.** A Railway workspace token (account settings -> Tokens, with the
|
||||||
workspace selected; a project token cannot make projects) and the
|
workspace selected; a project token cannot make projects), the Cloudflare
|
||||||
Cloudflare token. `cp .env.example .env` and fill both in.
|
token, and the state bucket's keys (below). `cp .env.example .env` and fill
|
||||||
|
them in.
|
||||||
|
|
||||||
2. **Project and domains.**
|
2. **Project and domains.**
|
||||||
```
|
```
|
||||||
@@ -63,12 +64,30 @@ config-as-code (healthchecks, start commands); Railway's defaults do.
|
|||||||
|
|
||||||
## State
|
## State
|
||||||
|
|
||||||
Local: `infra/railway/terraform.tfstate`, gitignored. Back it up. If it is
|
In a bucket on Railway: project `tfstate`, bucket `tfstate` (S3 name
|
||||||
lost, nothing on Railway goes away; `terraform import` each resource back
|
`tfstate-9p20m8qvmqf8gqk-z`, endpoint `https://t3.storageapi.dev`, US East).
|
||||||
(IDs from the dashboard URLs; the Cloudflare records as `<zone_id>/<id>`).
|
Every project keeps its state there under its own key, `<project>/terraform.tfstate`,
|
||||||
|
with Terraform's lock file next to it. The bucket's keys are `TFSTATE_*` in
|
||||||
|
`.env`; compose passes them to Terraform as `AWS_*`, the names the S3 backend
|
||||||
|
reads.
|
||||||
|
|
||||||
|
The bucket is made outside Terraform, once: the provider has no bucket
|
||||||
|
resource, and a bucket cannot hold the state that creates it. It was made
|
||||||
|
through the API, since the CLI refuses a workspace token for `init`/`link`:
|
||||||
|
`projectCreate`, then `bucketCreate`, then `environmentPatchCommit` with
|
||||||
|
`{buckets: {<id>: {region: "iad", isCreated: true}}}`.
|
||||||
|
|
||||||
|
A new project's stack copies the `backend "s3"` block from
|
||||||
|
`railway/main.tf` with a new `key`.
|
||||||
|
|
||||||
|
If the state is ever lost, nothing on Railway goes away; `terraform import`
|
||||||
|
each resource back (IDs from the dashboard URLs; the Cloudflare records as
|
||||||
|
`<zone_id>/<id>`).
|
||||||
|
|
||||||
## Cost
|
## Cost
|
||||||
|
|
||||||
|
The state bucket is $0.015 per GB-month: nothing, at a few KB.
|
||||||
|
|
||||||
Hobby plan: $5 a month, which includes $5 of usage. The service idles at a
|
Hobby plan: $5 a month, which includes $5 of usage. The service idles at a
|
||||||
few tens of MB and next to no CPU in each environment ($10 per GB-month of
|
few tens of MB and next to no CPU in each environment ($10 per GB-month of
|
||||||
memory, $20 per vCPU-month), so both fit in the included usage. Egress is
|
memory, $20 per vCPU-month), so both fit in the included usage. Egress is
|
||||||
|
|||||||
+16
-1
@@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
# Terraform makes the project, the service and the domains, and puts their
|
# Terraform makes the project, the service and the domains, and puts their
|
||||||
# records on Cloudflare. It never deploys: deploy.sh uploads the site with
|
# records on Cloudflare. It never deploys: deploy.sh uploads the site with
|
||||||
# Railway's CLI. State is local (terraform.tfstate here, gitignored).
|
# Railway's CLI. State is in the tfstate bucket on Railway (infra/README.md).
|
||||||
|
|
||||||
terraform {
|
terraform {
|
||||||
required_version = ">= 1.10"
|
required_version = ">= 1.10"
|
||||||
@@ -12,6 +12,21 @@ terraform {
|
|||||||
railway = { source = "terraform-community-providers/railway", version = "~> 0.6.2" }
|
railway = { source = "terraform-community-providers/railway", version = "~> 0.6.2" }
|
||||||
cloudflare = { source = "cloudflare/cloudflare", version = "~> 5.25" }
|
cloudflare = { source = "cloudflare/cloudflare", version = "~> 5.25" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# The tfstate project's bucket on Railway, which holds every project's state
|
||||||
|
# under its own key. S3-compatible, not AWS: hence the skips. Its keys come
|
||||||
|
# from TFSTATE_* in .env (compose.yaml passes them as AWS_*).
|
||||||
|
backend "s3" {
|
||||||
|
bucket = "tfstate-9p20m8qvmqf8gqk-z"
|
||||||
|
key = "bible/terraform.tfstate"
|
||||||
|
region = "auto"
|
||||||
|
endpoints = { s3 = "https://t3.storageapi.dev" }
|
||||||
|
use_lockfile = true
|
||||||
|
skip_credentials_validation = true
|
||||||
|
skip_region_validation = true
|
||||||
|
skip_requesting_account_id = true
|
||||||
|
skip_metadata_api_check = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Reads RAILWAY_TOKEN (compose.yaml sets it from RAILWAY_API_TOKEN in .env):
|
# Reads RAILWAY_TOKEN (compose.yaml sets it from RAILWAY_API_TOKEN in .env):
|
||||||
|
|||||||
Reference in new issue
Block a user