Tyto 6 lekcí práce s cloudformation jsem se naučil na celý život

Začal jsem pracovat s cloudformation před 4 lety. Od té doby jsem rozbil spoustu infrastruktur, dokonce i ty, které již byly v produkci. Ale pokaždé, když jsem něco pokazil, jsem se naučil něco nového. Díky této zkušenosti se chci podělit o některé z nejdůležitějších lekcí, které jsem se naučil.

Tyto 6 lekcí práce s cloudformation jsem se naučil na celý život

Lekce 1: kontrolujte změny před jejich nasazením

Tuto lekci jsem se naučil brzy poté, co jsem začal pracovat s cloudformation. Nepamatuji si, co přesně jsem tenkrát rozbil, ale určitě si pamatuji, že jsem použil příkaz aws cloudformation update. Tento příkaz jednoduše vydává šablonu bez jakékoliv kontroly změn, které budou nasazeny. Nemyslím si, že je potřeba vysvětlovat, proč je důležité zkontrolovat všechny změny před jejich nasazením.

Po tomto selhání jsem okamžitě změnil deployment pipeline, když jsem nahradil příkaz update příkazem create-change-set

# OPERATION is either "UPDATE" or "CREATE"
changeset_id=$(aws cloudformation create-change-set 
    --change-set-name "$CHANGE_SET_NAME" 
    --stack-name "$STACK_NAME" 
    --template-body "$TPL_PATH" 
    --change-set-type "$OPERATION" 
    --parameters "$PARAMETERS" 
    --output text 
    --query Id)

aws cloudformation wait 
    change-set-create-complete --change-set-name "$changeset_id"

Když je změnový set vytvořen, nijak neovlivňuje existující stack. Na rozdíl od příkazu update, přístup se změnovým setem nevyvolává skutečné nasazení. Místo toho vytváří seznam změn, které si můžete prohlédnout před nasazením. Změny si můžete prohlédnout v rozhraní AWS konzole. Ale pokud upřednostňujete automatizaci všeho, co se dá, zkontrolujte je v CLI:

# this command is presented only for demonstrational purposes.
# the real command should take pagination into account
aws cloudformation describe-change-set 
    --change-set-name "$changeset_id" 
    --query 'Changes[*].ResourceChange.{Action:Action,Resource:ResourceType,ResourceId:LogicalResourceId,ReplacementNeeded:Replacement}' 
    --output table

Tento příkaz by měl vrátit výstup podobný následujícímu:

--------------------------------------------------------------------
|                         DescribeChangeSet                        |
+---------+--------------------+----------------------+------------+
| Action  | ReplacementNeeded  |      Resource        | ResourceId |
+---------+--------------------+----------------------+------------+
|  Modify | True               |  AWS::ECS::Cluster   |  MyCluster |
|  Replace| True               |  AWS::RDS::DBInstance|  MyDB      |
|  Add    | None               |  AWS::SNS::Topic     |  MyTopic   |
+---------+--------------------+----------------------+------------+

Ze zvláštního hlediska si dejte pozor na změny, kde Action je Replace, Delete nebo kde ReplacementNeeded — True. To jsou nejnebezpečnější změny a obvykle vedou ke ztrátě dat.

Jakmile byly změny prozkoumány, mohou být nasazeny

aws cloudformation execute-change-set --change-set-name "$changeset_id"

operation_lowercase=$(echo "$OPERATION" | tr '[:upper:]' '[:lower:]')
aws cloudformation wait "stack-${operation_lowercase}-complete" 
    --stack-name "$STACK_NAME"

Lekce 2: použijte stack policy k zabránění nahrazení nebo odstranění zdrojů za zachování stavu

Někdy je prostý pohled na změny nedostatečný. Všichni jsme lidé a všichni děláme chyby. Krátce poté, co jsme začali používat sady změn, můj kolega nevědomky provedl nasazení, což vedlo k aktualizaci databáze. Nic hrozného se nestalo, protože to byla testovací prostředí.

I když naše skripty zobrazovaly seznam změn a žádaly o potvrzení, změna Replace byla přehlédnuta, protože seznam změn byl tak velký, že se na obrazovku nevlezl. A protože to byla běžná aktualizace v testovací prostředí, změnám nebyla věnována taková pozornost.

Existují zdroje, které nikdy nechcete nahradit nebo odstranit. Jsou to statefull služby, jako instance databáze RDS nebo cluster elastichsearch atd. Bylo by dobré, kdyby aws automaticky odmítal nasazení, pokud by prováděná operace vyžadovala odstranění takového zdroje. Naštěstí má cloudformation zabudovaný způsob, jak to udělat. Říká se tomu stack policy a o tom se můžete dozvědět více v dokumentaci:

STACK_NAME=$1
RESOURCE_ID=$2

POLICY_JSON=$(cat <<EOF
{
    "Statement" : [{
        "Effect" : "Deny",
        "Action" : [
            "Update:Replace",
            "Update:Delete"
        ],
        "Principal": "*",
        "Resource" : "LogicalResourceId/$RESOURCE_ID"
    }]
}
EOF
)

aws cloudformation set-stack-policy --stack-name "$STACK_NAME" 
    --stack-policy-body "$POLICY_JSON"

Lekce 3: používejte UsePreviousValue při aktualizaci stacku se šifrovanými parametry.

Když vytváříte entitu RDS mysql, AWS po vás požaduje poskytnout MasterUsername a MasterUserPassword. Protože je lepší neskladovat tajemství v zdrojovém kódu a já chtěl automatizovat naprosto všechno, realizoval jsem "chytrý mechanismus", při kterém před nasazením budou přihlašovací údaje získány z s3, a pokud přihlašovací údaje nebudou nalezeny, nové přihlašovací údaje se vygenerují a uloží do s3.

Tyto přihlašovací údaje budou poté předány jako parametry příkazu cloudformation create-change-set. Během experimentování se skriptem došlo k tomu, že připojení k s3 bylo ztraceno, a můj "chytrý mechanismus" to považoval za signál pro generování nových přihlašovacích údajů.

Kdybych začal používat tento skript v pracovním prostředí a problém s připojením by se znovu objevil, aktualizoval by zásobník novými přihlašovacími údaji. V tomto konkrétním případě se nic špatného nestane. Odmítl jsem však tento přístup a začal používat jiný, přičemž jsem přihlašovací údaje poskytoval pouze jednou - při vytváření zásobníku. A později, kdyby zásobník potřeboval aktualizaci, místo uvedení tajné hodnoty parametru bych jednoduše použil UsePreviousValue=true:

aws cloudformation create-change-set 
    --change-set-name "$CHANGE_SET_NAME" 
    --stack-name "$STACK_NAME" 
    --template-body "$TPL_PATH" 
    --change-set-type "UPDATE" 
    --parameters "ParameterKey=MasterUserPassword,UsePreviousValue=true"

Lekce 4: použijte rollback configuration

Jiný příkaz, se kterým jsem pracoval, používal funkci cloudformation, nazvanou rollback configuration. S tím jsem se dříve nesetkal a rychle jsem pochopil, že to udělá nasazení mých zásobníků ještě úžasnější. Nyní to používám pokaždé, když nasazuji svůj kód v lambda nebo ECS pomocí cloudformation.

Jak to funguje: uvádíte CloudWatch alarm arn v parametru —rollback-configuration, když vytváříte sadu změn. Později, když provedete sadu změn, aws sleduje alarm po dobu alespoň jedné minuty. Pokud se alarm během této doby změní na stav ALARM, nasazení se vrátí zpět.

Níže je uveden příklad úryvku šablony cloudformation, ve které vytvářím cloudwatch alarm, který sleduje vlastní metriku cloudu ve formě počtu chyb v cloudových protokolech (metrika je vytvářena prostřednictvím MetricFilter):

Resources:
  # tato metrika sleduje počet chyb v protokolech cloudwatch. V tomto
  # konkrétním případě se předpokládá, že protokoly jsou ve formátu json a chybové protokoly jsou
  # identifikovány podle úrovně "error". Viz FilterPattern
  ErrorMetricFilter:
    Type: AWS::Logs::MetricFilter
    Properties:
      LogGroupName: !Ref LogGroup
      FilterPattern: !Sub '{$.level = "error"}'
      MetricTransformations:
      - MetricNamespace: !Sub "${AWS::StackName}-log-errors"
        MetricName: Errors
        MetricValue: 1
        DefaultValue: 0

  ErrorAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub "${AWS::StackName}-errors"
      Namespace: !Sub "${AWS::StackName}-log-errors"
      MetricName: Errors
      Statistic: Maximum
      ComparisonOperator: GreaterThanThreshold
      Period: 1 # 1 minuta
      EvaluationPeriods: 1
      Threshold: 0
      TreatMissingData: notBreaching
      ActionsEnabled: yes

Teď alarm může být použit jako rollback spouštěč při provádění sady nástrojů:

ALARM_ARN=$1

ROLLBACK_TRIGGER=$(cat <<EOF
{
  "RollbackTriggers": [
    {
      "Arn": "$ALARM_ARN",
      "Type": "AWS::CloudWatch::Alarm"
    }
  ],
  "MonitoringTimeInMinutes": 1
}
EOF
)

aws cloudformation create-change-set 
    --change-set-name "$CHANGE_SET_NAME" 
    --stack-name "$STACK_NAME" 
    --template-body "$TPL_PATH" 
    --change-set-type "UPDATE" 
    --rollback-configuration "$ROLLBACK_TRIGGER"

Lekce 5: Ujistěte se, že nasazujete poslední verzi šablony

Je snadné nasadit starší verzi šablony CloudFormation, ale může to způsobit vážné škody. Jednou jsme to zažili: vývojář neodeslal poslední změny z Git a nevědomky nasadil předchozí verzi stacku. To vedlo k výpadku aplikace, která tento stack používala.

Něco jednoduchého, například přidání kontroly, zda je větev aktuální, před provedením nasazení, by bylo dobré (předpokládáme, že git je vaším nástrojem pro správu verzí):

git fetch
HEADHASH=$(git rev-parse HEAD)
UPSTREAMHASH=$(git rev-parse master@{upstream})

if [[ "$HEADHASH" != "$UPSTREAMHASH" ]] ; then
   echo "Větev není aktualizována s originem. Přerušení"
   exit 1
fi

Lekce 6: Neinventujte kolo

Může se zdát, že nasazení s cloudformation je snadné. Potřebujete jen spoustu bash skriptů, které spouští příkazy aws cli.

Před čtyřmi lety jsem začínal s jednoduchými skripty, které spouštěly příkaz aws cloudformation create-stack. Brzy skript již nebyl jednoduchý. Každá získaná lekce činila skript stále složitějším. Nebylo to jen obtížné, ale plné chyb.

Nyní pracuji v malém IT oddělení. Zkušenosti ukazují, že každému týmu se vyvinul svůj vlastní způsob nasazování stacků CloudFormation. A to je špatně. Bylo by lepší, kdyby všichni používali jednotný přístup. Naštěstí existuje mnoho nástrojů, které pomáhají nasazovat a spravovat stacky CloudFormation.

Tyto lekce vám pomohou vyhnout se chybám.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster