Environment Constraints
Prerequisite: understand the environment concept offered by Delivery Configs
What is an Environment Constraint?
Environment constraints control how an artifact version flows through environments. A constraint can
be as simple as ensuring an artifact isn’t promoted into Environment B
unless it has successfully deployed into
Environment A
. Constraints can also specify that an artifact needs to have a canary evaluated by Kayenta before
it can be deployed into an environment, while also defining how the canary should be deployed and evaluated.
Defining Constraints
Every environment defined in a Delivery Config supports a top-level constraints
list property.
The following example ensures that artifact versions are only promoted into the staging
environment after
successful deployment to the test
environment, and only if the current time is within the days Monday thru
Thursday and the hours of 8am and 4pm.
environments:
- name: staging
resources: # omitted for brevity
notifications: # omitted for brevity
constraints:
- type: depends-on
environment: testing
- type: allowed-times
windows:
- days: Monday-Thursday
hours: 8-16
Constraint Types and Ordering
Constraints are currently bucketed into stateless and stateful types. Stateless constraints can always be fully
evaluated in a single pass and do not interact with users or external systems. The current stateless constraint
types are depends-on
and allowed-times
.
Stateless constraints are always evaluated first, and must be satisfied before any stateful constraints are evaluated. Stateful constraints are a powerful construct, with the ability to mutate cloud state during their evaluation. Examples include deploying a new artifact version into an environment for the sake of canary analysis, or launching a smoke-test pipeline against a prior environment, gating promotion on its success.
This implicit ordering by type ensures that a pipeline constraint gating promotion to a production environment on smoke-tests run against a prior environment will only invoke the test pipeline after the artifact version under evaluation is deployed to the prior environment.
All stateful constraints can be manually overridden, such as when a canary failure is deemed to be expected for a given change, or a false alarm. When an environment defines multiple constraints, all must pass before a new artifact is promoted into the environment.
Available Constraints
Depends On
The depends-on
constraint ensures that an artifact version will not deploy into the environment it is
attached to, unless it has successfully deployed into the dependent environment.
Parameters
environment
: The name of the dependent environment. It must be defined within the same delivery config as
the target environment containing the constraint.
Example
constraints:
- type: depends-on
environment: testing
Allowed Times
The allowed-times
constraints provides a time based gate on promotion into an environment. It can be used to
ensure promotion to an environment only occurs during business hours, or quiet times.
Parameters
windows
: A list of time windows; multiple windows can be specified on a single constraint. The constraint is
satisfied if the current time matches any single window.
tz
: Optional The timezone to evaluate the constraint in. This is optional, by default the timezone specified via
the default.time-zone
spring configuration property is used, not the JVM or OS timezone. If your organization
operates in a single timezone, this property should likely be set that timezone.
Window Parameters
hours
: Supports ranges (i.e. 10-20
) and comma separated lists (i.e. 5,6,7,8
) or a combination
of the two.
days
: Supports aliases (weekdays
and weekends
), as well as ranges and comma separated lists of
days in their java standard (java.util.Calendar
) short (mon-thu
) or full (monday-thursday
) names.
Example
constraints:
- type: allowed-times
windows:
- days: Monday-Wednesday,Friday
hours: 8-16
- days: Thursday
hours: 14-16
This allows artifacts to deploy into the environment between 8am-4pm on Monday, Tuesday, Wednesday, and Friday or between 2-4pm on Thursday.
Manual Judgement
The manual-judgement
constraint prevents an artifact from deploying to an environment without explicit
approval via an external API client. UI support for approving or rejecting judgements as well as an
interactive slack bot are under development but direct use of Spinnaker’s REST API is currently required to
answer a manual judgement. See
Interacting with and Overriding Constraints
for details.
Parameters
timeout
: (Optional); Type: Duration
; Default Value: PT1W
If judgement is not provided within this time (starting when the constraint is initially evaluated for a given environment and artifact version), it is considered rejected.
Example
constraints:
- type: manual-judgement
Pipeline
The pipeline
constraint launches a pipeline, optionally passing along constraint provided trigger
parameters. The pipeline execution is periodically monitored and the constraint status derived from
the final status of the execution.
Parameters
pipelineId
: Type: String
The configuration id of the pipeline to be executed during constraint evaluation. If unknown,
edit the given pipeline from the Spinnaker UI. From the edit configuration view, the pipelineId
is the
final part of the URL. The pipeline can be a part of any application, but must be runnable via
the service account defined in the target environment’s delivery config.
retries
: (Optional); Type: Integer
If set, pipeline failures will be retried up-to this many times if pipeline execution goes terminal for any reason. The constraint evaluation will fail once retries are exhausted.
parameters
: (Optional); Type: Map<String, Object>
If set, the contents of this map are passed as trigger parameters when executing the pipeline. Expressions are not currently supported.
timeout
: (Optional); Type: Duration
; Default Value: PT2H
If the pipeline execution does not complete within this time, it is considered a failure.
Example
constraints:
- type: pipeline
pipelineId: fn0rd5d1-6217-4fcf-aa3d-ce7f59af9cac
retries: 1
parameters:
foo: bar
Canary
The canary
constraint supports deploying experiment and control clusters across multiple regions within
the target environment. Experiment/control cluster health is evaluated via Kayenta and the clusters
removed once evaluation is complete. By default, a multi-region constraint must pass in all regions
for the constraint to pass but this behavior is configurable.
The canary
constraint currently only supports EC2. Keel configuration properties may need to be set
depending on how Kayenta accesses time-series data and persists state.
System Configuration Properties
defaults.constraint.canary.metrics-account
: Default Value: atlas-global.prod
Unless your time series data is stored in Netflix Atlas, this should be set to the equivalent value used with the Orca Kayenta stage.
defaults.constraint.canary.storage-account
: Default Value: s3-objects
This should be set to the value of Kayenta’s default-storage-account
.
Parameters
canaryConfigId
: Type: String
The configuration id of the canary rules used for evaluation. If unknown, select a specific
configuration from Spinnaker’s Canary Config UI. The canaryConfigId
is the final segment of the resulting url.
beginAnalysisAfter
: (Optional); Type: Duration
; Default Value: PT10M
After the deployment of canary clusters completes, Spinnaker will wait this amount of time before launching the first Kayenta analysis. This allows for the filtering or inclusion of service warmup behavior in the analysis.
canaryAnalysisInterval
: (Optional); Type: Duration
; Default Value: PT30M
After the completion of any beginAnalysisAfter
delay, Kayenta analysis are launched at this recurring interval,
until post-beginAnalysisAfter
runtime exceeds the lifetime
parameter.
lifetime
: (Optional); Type: Duration
; Default Value: PT30M
Maximum runtime for the canary, exempting deployment times and any initial delay configured via beginAnalysisAfter
.
cleanupDelay
: (Optional); Type: Duration
; Default Value: 0
When a canary fails due to a failing Kayenta score, Spinnaker will wait this amount of time before deleting canary clusters. Useful if engineers desire an opportunity to manually inspect instances involved in the failure.
marginalScore
: Type: Integer
If Kayenta generates a canary score below the marginalScore
, it is considered an immediate failure.
passScore
: Type: Integer
If Kayenta generates a final canary score >= passScore
, the constraint will pass.
regions
: Type: Set<String>
Each region will get its own independently deployed and analyzed control/experiment pair.
capacity
: Type: Integer
Control and experiment clusters have their min/max/desired pinned to this value.
source
: Type: CanarySource
Defined in yaml as a Map<String, String>
with the following properties:
account
cloudProvider
cluster
This should refer to an active cluster in the target environment deployed in all of the regions the constraint is configured to run canaries in. Control/experiment clusters are configured based on the source cluster (i.e. account, subnet, instance type, firewall rules).
minSuccessfulRegions
: (Optional); Type: Integer
; Default Value: 0
If set to >0 on a multi-region canary, the constraint will pass if Kayenta analysis passes in this many regions. I.e. if set to 2 on a constraint that defines a 3-region canary, the failure of a single region is ignored.
failureCancelsRunningRegions
: (Optional); Type: Boolean
; Default Value: true
If true, the failure of any region
that violates the minSuccessfulRegions
parameter triggers the immediate cancellation of any canaries still
running in other regions.
metricsAccount
: (Optional); Type: String
If set, overrides the defaults.constraint.canary.metrics-account
property.
This may be required in environments with multiple TSD instances.
storageAccount
: (Optional); Type: String
If set, overrides the defaults.constraint.canary.storage-account
property. Not typically required.
Example
constraints:
- type: canary
canaryConfigId: fn0rd5d1-6217-4fcf-aa3d-ce7f59af9cac
beginAnalysisAfter: PT3M
canaryAnalysisInterval: PT10M
lifetime: PT90M
marginalScore: 75
passScore: 90
capacity: 2
source:
account: appaccount
cloudProvider: aws
cluster: app-prod
regions:
- us-east-1
- us-west-2
- eu-west-1
minSuccessfulRegions: 2
Interacting with and Overriding Constraints
Apart from the depends-on constraint, all constraint types either expect interaction from a user (in the case of manual-judgement ) or can have their automated judgements overruled by a user.
Approving or rejecting Manual Judgement constraints from Slack
If your operator has configured Slack app integration with Spinnaker, then a very convenient way to approve managed deployments gated by a Manual Judgement constraint is to use interactive Slack notifications.
All you need to do is set up Slack notifications in your delivery config, which will enable interactive notifications to a Slack channel of your choice, where you can simply click a button to approve or reject the deployment of the artifact into the environment.
Consider the following simplified delivery config:
name: myspinapp
application: myspinapp
serviceAccount: myteam@mycompany.com
artifacts:
- name: myspinapp
type: deb
environments:
- name: test
constraints:
- type: manual-judgement
notifications:
- type: slack
address: "#myteam"
frequency: verbose
resources:
- apiVersion: bakery.spinnaker.netflix.com/v1
kind: image
spec:
artifactName: myspinapp
baseLabel: RELEASE
baseOs: xenial
regions:
- us-east-1
storeType: EBS
application: myspinapp
- apiVersion: "ec2.spinnaker.netflix.com/v1"
kind: "cluster"
spec:
moniker:
app: "myspinapp"
imageProvider:
deliveryArtifact:
name: "myspinapp"
type: "deb"
locations:
account: "test"
regions:
- name: "us-east-1"
Upon evaluating whether a new Debian artifact for myspinapp
should be deployed into the test
environment,
Spinnaker will gate the deployment on the manual-judgement
constraint and send a notification that looks like
the following to the #myteam
Slack channel.
Once a user in the channel clicks on the Approve
button, the notification changes to reflect the approval:
:warning: Note that the
frequency
setting for notifications does not affect this behavior – interactive notifications will always be sent unless your operator has chosen to disable this feature entirely on your company’s instance of Spinnaker.
APIs to interact with constraints
In addition to Slack integration, the following API endpoints are currently available to interact with constraints.
Note: we limit to one delivery config per app, so these APIs currently use app name.
Reading status of pending and recent constraints
GET
https://gate/managed/application/{application}/environment/{environment-name}/constraints?limit=20
Returns: List<ConstraintState>
consisting of:
String deliveryConfigName;
String environmentName;
String artifactVersion;
String type;
String status;
Instant createdAt;
String judgedBy;
Instant judgedAt;
String comment;
Map<String, Object> attributes;
Setting or Overriding Constraint State
POST
https://gate/managed/application/{application}/environment/{environment-name}/constraint
POST
Body:
{
"type": "canary",
"artifactVersion": "fnord-1.2.3",
"status": "OVERRIDE_PASS",
"comment": "overriding false positive kayenta failure"
}
Valid status
values: PENDING
, PASS
, FAIL
, OVERRIDE_PASS
, OVERRIDE_FAIL