Give Each Environment Its Values
The shop runs on your machine against localhost, and in production against a managed database
and under a real host name. The components are the same in both places. What differs is written
in the Context, per environment.
§A value for one environment
Append @<environment> to a key. The first line is what toa create wrote; the second is added:
# context.toa.yaml
mongodb: mongodb://localhost
mongodb@production: mongodb://mongo.internal.example.com A key without a suffix applies everywhere. A key with a suffix applies in that environment and
wins there: in production the database is mongo.internal.example.com, everywhere else it is localhost.
The environment is named on the command line:
$ npx toa env local
$ npx toa deploy production An environment is not declared anywhere. It exists because a command names it; one that no key mentions takes every unsuffixed value.
§At any depth
Any key of the Context can be suffixed, not only the top-level ones: the host of the gateway,
the limit that Add Configuration declares, the replicas of a composition:
# context.toa.yaml
exposition:
authorities:
local: localhost:8000
local@production: api.example.com
configuration:
store.orders:
limit: 10000
limit@staging: 100
compositions:
- name: core
components: [store.orders, billing.wallets]
replicas: 3
replicas@staging: 1 A suffixed key replaces the whole value of the unsuffixed one. It is not merged into it:
storages:
pictures:
provider: tmp
directory: store-pictures
pictures@production:
provider: s3
bucket: store-pictures
region: eu-west-1 In production, pictures is the s3 declaration alone.
A key may exist only with suffixes. Environments that are not named then have no such key:
evicted@production:
components: [pictures] Because @ marks a suffix, a key of the Context cannot contain @ for any other purpose. A
package name used as a key under annotations is the one exception.
§What you typically vary
- Addresses —
amqp,mongodb,stash, storage buckets, the gateway’sauthorities, the ingresshosts. - Configuration values — a limit that is small in tests, a sender address, a feature that is off locally.
- Shape —
compositions,replicas,resources,mono. - What is deployed —
evicted. - How images are built —
registry.base,registry.platforms,registry.services.
Secret values are never written in the Context, in any environment. The Context names them and each environment is given its own values; see Supply Secrets.
§The local environment
toa env without a name selects local and writes .env beside the Context. In the application toa create wrote, the env script runs it, with --dev to fill secrets with local development
defaults, and npm run restart runs that script before it restarts the processes; What a restart does shows both:
$ npm run env # toa types --quiet && toa env --dev && toa map
$ npm run restart # npm run env, then both processes again Run npm run restart after changing the Context. The .env file is a snapshot. Secret
values already in it are kept, so writing it again does not lose what you typed.
.env* is in the generated .gitignore, and has to stay there: the file holds secrets.
toa env takes more options: --path for a Context elsewhere, --as to write another file, -c and -s to write only what one component or one service needs. See The CLI.
§Several local environments
A common second one runs the application in a container on your machine, where localhost is
the container itself:
mongodb@local: mongodb://localhost:27017
mongodb@docker: mongodb://host.docker.internal:27017 $ npx toa env docker --dev --as .env.docker
$ npx toa compose ./components/* --dock --env .env.docker --as keeps the two environment files side by side.
§Derived environments
Staging is production with a smaller database and a lower limit. Instead of repeating every production key, name the environments as a chain, separated by colons. Each key takes the first name in the chain it has a suffix for:
amqp: amqp://localhost
amqp@production: amqp://rmq.internal.example.com
mongodb@production: mongodb://mongo.internal.example.com
mongodb@staging: mongodb://mongo.staging.example.com
configuration:
store.orders:
limit: 10000
limit@staging: 100 $ npx toa deploy staging:production | Key | staging:production takes |
|---|---|
mongodb | @staging |
amqp | @production, as there is no @staging |
limit | @staging |
A key with neither suffix takes its unsuffixed value. A chain may be longer: preview:staging:production.
- The processes run as the first name.
toa env staging:productionwritesTOA_ENV=staging. - The chain is not stored. It is written on the command line each time, never in the Context.
Give the same chain to every command for that environment: the one
toa deployread is the onetoa export secretsmust read. - An empty name in a chain is refused:
Environment 'staging:' contains an empty name.
§Naming an environment
Every command that reads the Context takes an environment in the same form.
| Command | Default environment |
|---|---|
toa env, toa map, toa npm, toa types | local |
toa deploy, toa push | default |
toa export secrets, toa export tags, toa export deployment, toa export convergence | none; it must be given |
Do not name an environment eight hexadecimal digits, or deps- followed by eight. A deploy
tags images with the environment’s name, and such a name cannot be told from the tags the build
writes; see Build Images.
§What an environment cannot change
An environment changes values in the Context. It cannot give an operation a different implementation, schema or contract in staging. An operation that has to behave differently reads a configuration value, and the environment sets it; see Add Configuration.
A running operation can read the environment’s name as context.env (The Operation Context). Prefer a configuration value to branching on
the name: a value says what differs, a name only says where.
§Keep lower environments capable
Run local and staging infrastructure that can do what production does, at a smaller size: a database with transactions, the same broker. Where the infrastructure is weaker, the runtime says so in the log when it starts, and what you test is no longer what you release. Environments has the reasoning.