Гэтыя 6 урокаў працы з cloudformation я засвоіў на ўсё жыццё

Я пачаў працаваць з аблокаўтварэнне 4 гады таму. З таго часу я зламаў шмат інфраструктур, нават тыя, якія ўжо былі ў прадукцыі. Але кожны раз, калі я нешта псаваў, даведваўся пра новае. Дзякуючы гэтаму досведу, я падзялюся некаторымі з самых важных урокаў, якія я вывучыў.

Гэтыя 6 урокаў працы з cloudformation я засвоіў на ўсё жыццё

Урок 1: правярайце змены перад тым, як разгарнуць іх

Я засвоіў гэты ўрок неўзабаве як пачаў працаваць з аблокаўтварэнне. Не памятаю, што менавіта я тады зламаў, але дакладна памятаю, што выкарыстоўваў каманду aws cloudformation update. Гэтая каманда проста выкочвае шаблон без якой-небудзь праверкі змен, якія будуць разгорнутыя. Не думаю, што патрабуюцца тлумачэнні, для чаго трэба праверыць усе змены перад тым, як разгарнуць іх.

Пасля гэтага правалу, я адразу ж змяніў канвеер разгортвання, замяніўшы каманду update камандай 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"

Калі набор змен створаны, ён ніяк не ўплывае на існуючы стэк. У адрозненне ад каманды update, падыход з выкарыстаннем набору змен не выклікае фактычнага разгортвання. Замест гэтага ён стварае спіс змен, якія вы можаце прагледзець да разгортвання. Вы можаце прагледзець змены ў інтэрфейсе кансолі aws. Але калі вы аддаеце перавагу аўтаматызаваць усё, што толькі можна, то правярайце іх у 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

Гэтая каманда павінна выдаць выснову, падобную на наступную:

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

Звярніце асаблівую ўвагу на змены, дзе Action гэта Замяняць, Выдаляць ці дзе ReplacementNeeded - True. Гэта самыя небяспечныя змены і звычайна яны прыводзяць да страты інфармацыі.

Калі змены прагледжаны, яны могуць быць разгорнуты

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"

Урок 2: выкарыстоўвайце stack policy для прадухілення замены ці выдаленні рэсурсаў з захаваннем стану

Часам простага прагляду змен недастаткова. Усе мы людзі і ўсё дапускаем памылкі. Неўзабаве пасля таго, як мы пачалі выкарыстоўваць наборы змен, мой таварыш па камандзе неўсвядомлена выканаў разгортванне, што прывяло да абнаўлення базы дадзеных. Нічога страшнага не адбылося, таму што гэта было асяроддзе тэставання.

Нягледзячы на ​​тое, што нашы скрыпты адлюстроўвалі спіс змен і прасілі пацверджання, змена Replace было прапушчана, таму што спіс змен быў настолькі вялікім, што не змяшчаўся на экране. І паколькі гэта было звычайнае абнаўленне ў асяроддзі тэсціравання, зменам надавалася не так шмат увагі.

Ёсць рэсурсы, якія вы ніколі не захочаце замяніць ці выдаліць. Гэта statefull сэрвісы, такія як асобнік базы дадзеных RDS або кластар elastichsearch і г. д. Было б добра, калі б aws аўтаматычна адмаўляў у разгортванні, калі выкананая аперацыя запатрабуе выдалення такога рэсурсу. На шчасце, cloudformation мае ўбудаваны спосаб зрабіць гэта. Гэта называецца stack policy, і пра гэта мага больш даведацца ў дакументацыі:

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"

Урок 3: выкарыстоўвайце UsePreviousValue, калі абнаўляеце стэк з сакрэтнымі параметрамі

Калі вы ствараеце сутнасць RDS mysql AWS патрабуе ад вас даць MasterUsername і MasterUserPassword. Паколькі лепш не захоўваць сакрэты ў зыходным кодзе, і я хацеў аўтаматызаваць абсалютна ўсё, я рэалізаваў "разумны механізм", пры якім перад разгортваннем уліковыя дадзеныя будуць атрыманы з s3, і калі ўліковыя дадзеныя не будуць знойдзеныя, новыя ўліковыя дадзеныя генеруюцца і захоўваюцца ў s3 .

Затым гэтыя ўліковыя дадзеныя будуць перададзены ў якасці параметраў камандзе cloudformation create-change-set. Падчас эксперыментаў са скрыптам здарылася, што злучэнне з s3 было страчана, і мой "разумны механізм" разглядаў яго як сігнал для генерацыі новых уліковых дадзеных.

Калі б я пачаў выкарыстоўваць гэты скрыпт у працоўным асяроддзі, і праблема з падключэннем узнікла б зноў, ён бы абнавіў стэк новымі ўліковымі дадзенымі. У гэтым канкрэтным выпадку нічога кепскага не адбудзецца. Аднак я адмовіўся ад такога падыходу і пачаў выкарыстоўваць іншы, падаючы уліковыя дадзеныя толькі адзін раз - пры стварэнні стэка. І пазней, калі стэк запатрабуе абнаўленні, я б замест указання сакрэтнага значэння параметру проста выкарыстаў 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"

Урок 4: выкарыстоўвайце rollback configuration

Іншая каманда, з якой я працаваў, выкарыстоўвала функцыю аблокаўтварэнне, званую rollback configuration. Я не сустракаўся з ёй раней і хутка зразумеў, што гэта зробіць разгортванне маіх стэкаў яшчэ страмчэй. Цяпер я выкарыстоўваю кожны раз, калі разгортваю свой код у lambda ці ECS з дапамогай cloudformation.

Як гэта працуе: вы паказваеце CloudWatch alarm arn у параметры -rollback-configuration, калі ствараеце набор змен. Пазней, калі вы выканаеце набор змен, aws адсочвае alarm не менш за адну хвіліну. Ён адкочвае разгортванне зваротна, калі на працягу гэтага часу alarm змяняе стан на ALARM.

Ніжэй прыведзены прыклад урыўка пра шаблон аблокаўтварэнне, у якім я ствараю cloudwatch alarm, які адсочвае карыстацкую метрыку аблокі ў выглядзе колькасці памылак у часопісах аблокі (метрыка ствараецца праз MetricFilter):

Resources:
  # this metric tracks number of errors in the cloudwatch logs. In this
  # particular case it's assumed logs are in json format and the error logs are
  # identified by level "error". See 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 minute
      EvaluationPeriods: 1
      Threshold: 0
      TreatMissingData: notBreaching
      ActionsEnabled: yes

Зараз трывога можа быць выкарыстаны як адмена трыгер пры выкананні набору прылад:

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"

Урок 5: пераканайцеся, што вы разгортваеце самую апошнюю версію шаблону

Лёгка разгарнуць не самую апошнюю версію шаблону cloudformation, але гэта нанясе вялікую шкоду. Аднойчы так было ў нас: распрацоўнік не адправіў апошнія змены з Git і неўсвядомлена разгарнуў папярэднюю версію стэка. Гэта прывяло да простай прыкладання, якое выкарыстоўвала гэты стэк.

Нешта простае, напрыклад, даданне праверкі, ці актуальная галінка, перш чым выконваць разгортванне, будзе добра (калі выказаць здагадку, што git - гэта ваша прылада кантролю версій):

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

if [[ "$HEADHASH" != "$UPSTREAMHASH" ]] ; then
   echo "Branch is not up to date with origin. Aborting"
   exit 1
fi

Урок 6: не вынаходзьце ровар

Можа здацца, што разгортванне з аблокаўтварэнне - Гэта лёгка. Вам проста патрэбна куча скрыптоў bash, якія выконваюць каманды aws cli.

4 гады таму я пачынаў з простых скрыптоў, якія называюць aws cloudformation create-stack камандай. Неўзабаве скрыпт ужо не быў простым. Кожны вывучаны ўрок рабіў скрыпт усё больш і больш складаным. Было не толькі складана, але і з кучай багаў.

Цяпер я працую ў невялікім ІТ-аддзеле. Досвед паказвае, што ў кожнай каманды ёсць свой спосаб разгортвання стэкаў cloudformation. І гэта дрэнна. Было б лепш, калі б усе выкарыстоўвалі адзіны падыход. На шчасце, існуе мноства прылад, якія дапамагаюць разгарнуць і наладзіць стэкі cloudformation.

Гэтыя ўрокі дапамогуць вам пазбегнуць памылак.

Крыніца: habr.com

Дадаць каментар