As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.
A implantação contínua é uma estratégia de implantação que substitui lentamente as versões anteriores de um aplicativo por novas versões. Para realizar a implantação contínua de uma versão da máquina de estado, envie gradualmente uma quantidade crescente de tráfego de execução para a nova versão. A quantidade de tráfego e a taxa de aumento são parâmetros que você configura.
Você pode realizar a implantação contínua de uma versão usando uma das opções a seguir.
-
Console do Step Functions
: crie um alias que aponte para duas versões da mesma máquina de estado. Para esse alias, você define a configuração de roteamento para transferir o tráfego entre as duas versões. Para obter mais informações sobre como usar o console para implementar versões, consulte Versões e Aliases. -
Scripts para a AWS CLI e o SDK: crie um script de shell usando a AWS CLI ou o AWS SDK. Para obter mais informações, consulte as seções a seguir sobre como usar a AWS CLI e o AWS SDK.
-
Modelos do AWS CloudFormation: use os recursos
AWS::StepFunctions::StateMachineVersion
eAWS::StepFunctions::StateMachineAlias
para publicar várias versões de máquinas de estado e criar um alias para apontar para uma ou duas dessas versões.
O script de exemplo nesta seção mostra como você pode usar a AWS CLI para transferir gradualmente o tráfego de uma versão anterior da máquina de estado para uma nova versão. Você pode usar esse script como exemplo ou atualizá-lo de conforme necessário.
O script mostra a implantação canário para implantar uma nova versão da máquina de estado usando um alias. As etapas a seguir descrevem as tarefas que o script executa:
-
Se o parâmetro
publish_revision
estiver definido como verdadeiro, publique a mais recente de revision como a próxima versão da máquina de estado. Esta versão se tornará a nova versão ativa se a implantação for bem-sucedida.Se você definir o parâmetro
publish_revision
como falso, o script implantará a última versão publicada da máquina de estado. -
Crie um alias se ele ainda não existir. Se o alias não existir, direcione 100% do tráfego desse alias para a nova versão e saia do script.
-
Atualize a configuração de roteamento do alias para transferir uma pequena porcentagem do tráfego da versão anterior para a nova versão. Você define a porcentagem de canário no parâmetro
canary_percentage
. -
Por padrão, monitore os alarmes configuráveis do CloudWatch a cada 60 segundos. Se algum desses alarmes for acionado, reverta a implantação imediatamente, apontando 100% do tráfego para a versão anterior.
Após cada intervalo de tempo, em segundos, definido em
alarm_polling_interval
, continue monitorando os alarmes. Continue monitorando até que o intervalo de tempo definido emcanary_interval_seconds
tenha passado. -
Se nenhum alarme for acionado durante
canary_interval_seconds
, transfira 100% do tráfego para a nova versão. -
Se a nova versão for implementada com êxito, exclua todas as versões anteriores ao número especificado no parâmetro
history_max
.
#!/bin/bash
#
# AWS StepFunctions example showing how to create a canary deployment with a
# State Machine Alias and versions.
#
# Requirements: AWS CLI installed and credentials configured.
#
# A canary deployment deploys the new version alongside the old version, while
# routing only a small fraction of the overall traffic to the new version to
# see if there are any errors. Only once the new version has cleared a testing
# period will it start receiving 100% of traffic.
#
# For a Blue/Green or All at Once style deployment, you can set the
# canary_percentage to 100. The script will immediately shift 100% of traffic
# to the new version, but keep on monitoring the alarms (if any) during the
# canary_interval_seconds time interval. If any alarms raise during this period,
# the script will automatically rollback to the previous version.
#
# Step Functions allows you to keep a maximum of 1000 versions in version history
# for a state machine. This script has a version history deletion mechanism at
# the end, where it will delete any versions older than the limit specified.
#
# For an example that also demonstrates linear (or rolling) deployments, see the following:
# https://github.com/aws-samples/aws-stepfunctions-examples/blob/main/gradual-deploy/sfndeploy.py
set -euo pipefail
# ******************************************************************************
# you can safely change the variables in this block to your values
state_machine_name="my-state-machine"
alias_name="alias-1"
region="us-east-1"
# array of cloudwatch alarms to poll during the test period.
# to disable alarm checking, set alarm_names=()
alarm_names=("alarm1" "alarm name with a space")
# true to publish the current revision as the next version before deploy.
# false to deploy the latest version from the state machine's version history.
publish_revision=true
# true to force routing configuration update even if the current routing
# for the alias does not have a 100% routing config.
# false will abandon deploy attempt if current routing config not 100% to a
# single version.
# Be careful when you combine this flag with publish_revision - if you just
# rerun the script you might deploy the newly published revision from the
# previous run.
force=false
# percentage of traffic to route to the new version during the test period
canary_percentage=10
# how many seconds the canary deployment lasts before full deploy to 100%
canary_interval_seconds=300
# how often to poll the alarms
alarm_polling_interval=60
# how many versions to keep in history. delete versions prior to this.
# set to 0 to disable old version history deletion.
history_max=0
# ******************************************************************************
#######################################
# Update alias routing configuration.
#
# If you don't specify version 2 details, will only create 1 routing entry. In
# this case the routing entry weight must be 100.
#
# Globals:
# alias_arn
# Arguments:
# 1. version 1 arn
# 2. version 1 weight
# 3. version 2 arn (optional)
# 4. version 2 weight (optional)
#######################################
function update_routing() {
if [[ $# -eq 2 ]]; then
local routing_config="[{\"stateMachineVersionArn\": \"$1\", \"weight\":$2}]"
elif [[ $# -eq 4 ]]; then
local routing_config="[{\"stateMachineVersionArn\": \"$1\", \"weight\":$2}, {\"stateMachineVersionArn\": \"$3\", \"weight\":$4}]"
else
echo "You have to call update_routing with either 2 or 4 input arguments." >&2
exit 1
fi
${aws} update-state-machine-alias --state-machine-alias-arn ${alias_arn} --routing-configuration "${routing_config}"
}
# ******************************************************************************
# pre-run validation
if [[ (("${#alarm_names[@]}" -gt 0)) ]]; then
alarm_exists_count=$(aws cloudwatch describe-alarms --alarm-names "${alarm_names[@]}" --alarm-types "CompositeAlarm" "MetricAlarm" --query "length([MetricAlarms, CompositeAlarms][])" --output text)
if [[ (("${#alarm_names[@]}" -ne "${alarm_exists_count}")) ]]; then
echo All of the alarms to monitor do not exist in CloudWatch: $(IFS=,; echo "${alarm_names[*]}") >&2
echo Only the following alarm names exist in CloudWatch:
aws cloudwatch describe-alarms --alarm-names "${alarm_names[@]}" --alarm-types "CompositeAlarm" "MetricAlarm" --query "join(', ', [MetricAlarms, CompositeAlarms][].AlarmName)" --output text
exit 1
fi
fi
if [[ (("${history_max}" -gt 0)) && (("${history_max}" -lt 2)) ]]; then
echo The minimum value for history_max is 2. This is the minimum number of older state machine versions to be able to rollback in the future. >&2
exit 1
fi
# ******************************************************************************
# main block follows
account_id=$(aws sts get-caller-identity --query Account --output text)
sm_arn="arn:aws:states:${region}:${account_id}:stateMachine:${state_machine_name}"
# the aws command we'll be invoking a lot throughout.
aws="aws stepfunctions"
# promote the latest revision to the next version
if [[ "${publish_revision}" = true ]]; then
new_version=$(${aws} publish-state-machine-version --state-machine-arn=$sm_arn --query stateMachineVersionArn --output text)
echo Published the current revision of state machine as the next version with arn: ${new_version}
else
new_version=$(${aws} list-state-machine-versions --state-machine-arn ${sm_arn} --max-results 1 --query "stateMachineVersions[0].stateMachineVersionArn" --output text)
echo "Since publish_revision is false, using the latest version from the state machine's version history: ${new_version}"
fi
# find the alias if it exists
alias_arn_expected="${sm_arn}:${alias_name}"
alias_arn=$(${aws} list-state-machine-aliases --state-machine-arn ${sm_arn} --query "stateMachineAliases[?stateMachineAliasArn==\`${alias_arn_expected}\`].stateMachineAliasArn" --output text)
if [[ "${alias_arn_expected}" == "${alias_arn}" ]]; then
echo Found alias ${alias_arn}
echo Current routing configuration is:
${aws} describe-state-machine-alias --state-machine-alias-arn "${alias_arn}" --query routingConfiguration
else
echo Alias does not exist. Creating alias ${alias_arn_expected} and routing 100% traffic to new version ${new_version}
${aws} create-state-machine-alias --name "${alias_name}" --routing-configuration "[{\"stateMachineVersionArn\": \"${new_version}\", \"weight\":100}]"
echo Done!
exit 0
fi
# find the version to which the alias currently points (the current live version)
old_version=$(${aws} describe-state-machine-alias --state-machine-alias-arn $alias_arn --query "routingConfiguration[?weight==\`100\`].stateMachineVersionArn" --output text)
if [[ -z "${old_version}" ]]; then
if [[ "${force}" = true ]]; then
echo Force setting is true. Will force update to routing config for alias to point 100% to new version.
update_routing "${new_version}" 100
echo Alias ${alias_arn} now pointing 100% to ${new_version}.
echo Done!
exit 0
else
echo Alias ${alias_arn} does not have a routing config entry with 100% of the traffic. This means there might be a deploy in progress, so not starting another deploy at this time. >&2
exit 1
fi
fi
if [[ "${old_version}" == "${new_version}" ]]; then
echo The alias already points to this version. No update necessary.
exit 0
fi
echo Switching ${canary_percentage}% to new version ${new_version}
(( old_weight = 100 - ${canary_percentage} ))
update_routing "${new_version}" ${canary_percentage} "${old_version}" ${old_weight}
echo New version receiving ${canary_percentage}% of traffic.
echo Old version ${old_version} is still receiving ${old_weight}%.
if [[ ${#alarm_names[@]} -eq 0 ]]; then
echo No alarm_names set. Skipping cloudwatch monitoring.
echo Will sleep for ${canary_interval_seconds} seconds before routing 100% to new version.
sleep ${canary_interval_seconds}
echo Canary period complete. Switching 100% of traffic to new version...
else
echo Checking if alarms fire for the next ${canary_interval_seconds} seconds.
(( total_wait = canary_interval_seconds + $(date +%s) ))
now=$(date +%s)
while [[ ((${now} -lt ${total_wait})) ]]; do
alarm_result=$(aws cloudwatch describe-alarms --alarm-names "${alarm_names[@]}" --state-value ALARM --alarm-types "CompositeAlarm" "MetricAlarm" --query "join(', ', [MetricAlarms, CompositeAlarms][].AlarmName)" --output text)
if [[ ! -z "${alarm_result}" ]]; then
echo The following alarms are in ALARM state: ${alarm_result}. Rolling back deploy. >&2
update_routing "${old_version}" 100
echo Rolled back to ${old_version}
exit 1
fi
echo Monitoring alarms...no alarms have triggered.
sleep ${alarm_polling_interval}
now=$(date +%s)
done
echo No alarms detected during canary period. Switching 100% of traffic to new version...
fi
update_routing "${new_version}" 100
echo Version ${new_version} is now receiving 100% of traffic.
if [[ (("${history_max}" -eq 0 ))]]; then
echo Version History deletion is disabled. Remember to prune your history, the default limit is 1000 versions.
echo Done!
exit 0
fi
echo Keep the last ${history_max} versions. Deleting any versions older than that...
# the results are sorted in descending order of the version creation time
version_history=$(${aws} list-state-machine-versions --state-machine-arn ${sm_arn} --max-results 1000 --query "join(\`\"\\n\"\`, stateMachineVersions[].stateMachineVersionArn)" --output text)
counter=0
while read line; do
((counter=${counter} + 1))
if [[ (( ${counter} -gt ${history_max})) ]]; then
echo Deleting old version ${line}
${aws} delete-state-machine-version --state-machine-version-arn ${line}
fi
done <<< "${version_history}"
echo Done!
O script de exemplo em aws-stepfunctions-examples
O script mostra as seguintes estratégias de implantação:
-
Canário: o tráfego é transferido em dois incrementos.
No primeiro incremento, uma pequena porcentagem do tráfego, por exemplo, 10% é transferida para a nova versão. No segundo incremento, antes do fim do intervalo de tempo especificado em segundos, o tráfego restante é transferido para a nova versão. A transferência do tráfego restante para a nova versão ocorre somente se nenhum alarme do CloudWatch for acionado durante o intervalo de tempo especificado.
-
Linear ou contínuo: transfere o tráfego para a nova versão em incrementos iguais com um número igual de segundos entre cada incremento.
Por exemplo, se você especificar a porcentagem de incremento como
20
com um--interval
de600
segundos, a implantação aumentará o tráfego em 20% a cada 600 segundos até que a nova versão receba 100% do tráfego.Essa implantação reverte imediatamente a nova versão se algum alarme do CloudWatch for acionado.
-
Tudo de uma vez ou azul/verde: transfere imediatamente 100% do tráfego para a nova versão. Essa implantação monitora a nova versão e a reverte automaticamente para a versão anterior se algum alarme do CloudWatch for acionado.
O exemplo de modelo do CloudFormation a seguir publica duas versões da máquina de estado chamada
. Ele cria um alias chamado MyStateMachine
, que aponta para essas duas versões e, em seguida, implanta a versão PROD
2
.
Neste exemplo, 10% do tráfego é transferido para a versão a 2
cada cinco minutos até que essa versão receba 100% do tráfego. O exemplo também mostra como você pode configurar os alarmes do CloudWatch. Se algum dos alarmes configurados entrar no estado ALARM
, a implantação falhará e será revertida imediatamente.
MyStateMachine:
Type: AWS::StepFunctions::StateMachine
Properties:
Type: STANDARD
StateMachineName: MyStateMachine
RoleArn: arn:aws:iam::123456789012:role/myIamRole
Definition:
StartAt: PassState
States:
PassState:
Type: Pass
Result: Result
End: true
MyStateMachineVersionA:
Type: AWS::StepFunctions::StateMachineVersion
Properties:
Description: Version 1
StateMachineArn: !Ref MyStateMachine
MyStateMachineVersionB:
Type: AWS::StepFunctions::StateMachineVersion
Properties:
Description: Version 2
StateMachineArn: !Ref MyStateMachine
PROD:
Type: AWS::StepFunctions::StateMachineAlias
Properties:
Name: PROD
Description: The PROD state machine alias taking production traffic.
DeploymentPreference:
StateMachineVersionArn: !Ref MyStateMachineVersionB
Type: LINEAR
Percentage: 10
Interval: 5
Alarms:
# A list of alarms that you want to monitor. If any of these alarms trigger, rollback the deployment immediately by pointing 100 percent of traffic to the previous version.
- !Ref CloudWatchAlarm1
- !Ref CloudWatchAlarm2