Environment configuration#
Plugin, targets, parameters and secret references of each application in each environment can be managed in a configuration system instead of the descriptor. Whoever requests the deploy only states application, environment and artifact:
apiVersion: manent/v1
application: myapp
environment: test
artifact:
type: application
name: myapp
version: 1.2.3
source: https://artifacts.example.com/myapp/myapp-1.2.3.tar.gz
Format#
An environment's configuration is a YAML or JSON document:
plugin: remote-copy
targets:
- host: 192.168.1.10
port: 22
user: deploy
params:
dest_dir: /opt/myapp/releases
ssh_key_secret: deploy-key
post_command: "systemctl restart myapp"
secrets:
- name: deploy-key
ref: env:DEPLOY_SSH_KEY
rollback: # optional: see Rollback
enabled: true
Secret references only
The configuration that is read is saved in the deploy history. It must contain only references to secrets (env:…, file:…), never the values.
Providers#
Configured in manent.yml, section envconfig: each entry of providers has a name, a type and the section of the type. With one provider, call it as you like (default below); for several see Several providers.
envconfig:
required: true
max_retries: 3
providers:
- name: default
type: consul
consul:
address: http://consul:8500 # default: CONSUL_HTTP_ADDR or http://127.0.0.1:8500
datacenter: ""
key: "manent/{tenant}/{application}/{artifact}/{environment}"
# token_file: /run/secrets/consul-token
The configuration is the value of the KV key. The ACL token is read from CONSUL_HTTP_TOKEN or from token_file, never from the configuration file.
envconfig:
providers:
- name: default
type: git
git:
repository: https://git.example.com/platform/envconfig.git
ref: refs/heads/main
path: "{tenant}/{application}/{artifact}/{environment}.yml"
password_ref: vault:secret/manent/git#token
The file is read at a commit: its SHA is recorded on the deploy, and a descriptor can choose a revision within descriptor_policy.config_ref. See Git repository.
| Option | Description |
|---|---|
required |
true: the deploy fails if there is no configuration for the environment. false: only the descriptor is used. |
max_retries |
Additional attempts if the provider does not respond (e.g. Consul unreachable). |
Templates (consul.key, file.path, git.path of each provider) contain {tenant} (the tenant of the release, untenanted for the applications no tenant lists) and {artifact}, the descriptor's artifact.name: one document per artifact of an application of a tenant. See Applications with several artifacts.
Several providers#
One installation can read from several systems at once: for example the payments team from its own Git repository, the applications not migrated yet from the old Consul, everyone else from the default Consul. Every system is an entry of envconfig.providers:
envconfig:
required: true
providers:
- name: payments-git
type: git
git:
repository: https://git.example.com/payments/envconfig.git
password_ref: vault:secret/manent/payments-git#token
match: {applications: ["payments/*"]}
- name: legacy-consul
type: consul
consul:
address: https://consul-old.example.com
key: "manent/{application}/{environment}"
token_file: /etc/manent/consul-old.token
match: {environments: [dev, test]}
on_missing: next # not migrated yet? read the next one
- name: retail-git
type: git
git: {repository: https://git.example.com/retail/envconfig.git}
tenant_only: true
- name: default
type: consul
tenants:
retail:
applications: {shop: {}}
envconfig: retail-git # read first, whatever the match rules say
- Which provider. A deploy reads from the provider its tenant names in the registry (
envconfig), then from the providers whosematchapplies, in order.matchtakes patterns onapplications(qualified with the tenant, as in permissions and rules:payments/*),artifactsandenvironments; a provider withoutmatchserves everything, one withtenant_only: trueonly the tenants that name it. The first one that has the document wins; with no candidate the deploy has no environment configuration (an error withrequired: true). - A missing document. With
on_missing: fail(default) the deploy stops at that provider, as with a single one. Withon_missing: nextit moves to the next candidate: useful to migrate one application at a time. Any other error, such as an unreachable system or an invalid document, never moves on: the deploy retries, and never silently reads another configuration. - Own settings. Each provider has its template, address and credentials.
CONSUL_HTTP_TOKENandCONSUL_HTTP_ADDRare only the defaults of the Consul providers withouttoken_fileandaddress. - Traceability. The
configstep recordsprovider(andskipped, the providers passed over withon_missing: next) next tosourceandrevision; with Git the deploy also recordsconfig_provider, shown in the status next toconfig_revision. - Revisions.
config.refrequires that the provider the deploy reads from is Git. A manual rollback and the reconciliation read the recorded revision from the provider that recorded it, even if the rules now choose another one: a commit SHA belongs to one repository. If that provider is no longer configured, the deploy fails with a permanent error. - Unknown names. A tenant naming a provider that does not exist is logged at startup, and its deploys fail.
- Earlier versions.
envconfig.providerwith theconsul,gitorfilesection next to it is no longer accepted: manent does not start and the error shows theprovidersform. Move the section into an entry, e.g.providers: [{name: default, type: consul, consul: {...}}].
When it is read#
The configuration is read at the start of every deploy, in the config step. Two consequences follow:
- a scheduled deploy uses the configuration valid at run time, not the one at the time it was scheduled;
- once read, it is saved by DBOS. If the deploy is resumed after a crash, it reuses the same configuration even if it has changed in the meantime.
The output of the config step reports the source (source, e.g. consul:manent/untenanted/myapp/myapp/test) and the revision (revision: Consul's ModifyIndex, or the commit SHA with Git), so every deploy can be traced back to the exact configuration it used.
Merge rules#
The environment configuration is authoritative: the descriptor can only add what is not defined there.
| Field | Rule |
|---|---|
policy, plugin, parallel |
If defined in both they must match. parallel is deploy.parallel: the targets of a batch updated at the same time (parallel targets); a value set here is not subject to descriptor_policy.max_parallel. |
targets |
If the configuration defines them, the descriptor can omit them or repeat them identically, labels included. |
params |
The descriptor can add keys; a key present in both must have the same value. |
secrets |
The descriptor can add secrets; the same name must have the same reference. |
step_params |
Parameters of the custom steps, per step: the descriptor (stepParams) can add keys allowed by descriptor_policy.step_params; a key present in both must have the same value. |
rollout |
The environment's wave rollout strategy is authoritative: the descriptor can omit it or repeat it identically. |
traffic |
Load balancer and router of the environment (draining, percentage rollouts): only in the environment configuration, a descriptor that defines it is rejected. |
imports, targets_from, params_from |
Targets and plugin parameters taken from the exports of the release in service of another application (only current imports), resolved when every deploy starts: see Exports and imports. With targets_from the descriptor cannot add its own targets; a parameter in params_from cannot also be set by the descriptor. |
exports |
Outputs of the environment's deploys that other deploys can import; the descriptor can add others, the same name must have the same definition. |
rollback |
enabled, on and locator follow the same rule: if defined in both they must match. This way an environment can enforce rollback without the descriptor being able to disable it. The artifact type's allowed limit still applies. |
A conflicting value makes the deploy fail: it is never silently overwritten. After the merge (and the imports) there must be at least one target.
On top of these rules, descriptor_policy in manent.yml limits what the descriptor can add: for example it can forbid commands (post_command), secret references outside the application's scope and targets not defined by the environment. See Security.
Checking the effective deploy#
The server shows the plan, the source and revision of the configuration (config), the effective deploy section and the names of the secrets. The deployment.read permission on the application and environment is required.
To try a manent configuration before installing it, without a running server, there is manent-server -c manent.yml validate -f <descriptor>, which reads the environment configuration locally (--offline to skip it). See manent-server.