Tych 6 lekcji pracy z chmurami nauczyłem się do końca życia.

Zacząłem pracować z tworzenie się chmur 4 lata temu. Od tego czasu zniszczyłem wiele infrastruktur, nawet tych, które były już w produkcji. Ale za każdym razem, gdy coś schrzaniłem, uczyłem się czegoś nowego. Dzięki temu doświadczeniu podzielę się najważniejszymi lekcjami, jakie wyciągnąłem.

Tych 6 lekcji pracy z chmurami nauczyłem się do końca życia.

Lekcja 1: Testuj zmiany przed ich wdrożeniem

Nauczyłem się tej lekcji wkrótce po tym, jak zacząłem z nią pracować tworzenie się chmur. Nie pamiętam już co dokładnie wtedy zepsułem, ale na pewno pamiętam, że użyłem polecenia aktualizacja chmury aws. To polecenie po prostu wdraża szablon bez sprawdzania zmian, które zostaną wdrożone. Nie sądzę, że potrzebne jest jakiekolwiek wyjaśnienie, dlaczego należy testować wszystkie zmiany przed ich wdrożeniem.

Po tej porażce natychmiast się zmieniłem rurociąg wdrożeniowy, zastępując polecenie aktualizacji poleceniem utwórz-zestaw zmian

# 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"

Po utworzeniu zestawu zmian nie ma on wpływu na istniejący stos. W przeciwieństwie do polecenia update podejście oparte na zestawie zmian nie powoduje faktycznego wdrożenia. Zamiast tego tworzy listę zmian, które można przejrzeć przed wdrożeniem. Zmiany możesz zobaczyć w interfejsie konsoli aws. Ale jeśli wolisz zautomatyzować wszystko, co możesz, sprawdź je w 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

To polecenie powinno dać wynik podobny do poniższego:

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

Zwróć szczególną uwagę na zmiany tam, gdzie jest Akcja zastąpić, Usuń czy gdzie Konieczna wymiana – prawda. Są to najbardziej niebezpieczne zmiany i zwykle prowadzą do utraty informacji.

Po sprawdzeniu zmian można je wdrożyć

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"

Lekcja 2: Użyj zasad stosu, aby zapobiec zastępowaniu lub usuwaniu zasobów stanowych

Czasami samo obejrzenie zmian nie wystarczy. Wszyscy jesteśmy ludźmi i wszyscy popełniamy błędy. Krótko po tym, jak zaczęliśmy używać zestawów zmian, mój kolega z zespołu nieświadomie przeprowadził wdrożenie, które spowodowało aktualizację bazy danych. Nic złego się nie wydarzyło, ponieważ było to środowisko testowe.

Mimo że nasze skrypty wyświetlały listę zmian i prosiły o potwierdzenie, zmiana Zamień została pominięta, ponieważ lista zmian była tak duża, że ​​nie zmieściła się na ekranie. A ponieważ była to normalna aktualizacja w środowisku testowym, zmianom nie poświęcono zbyt wiele uwagi.

Istnieją zasoby, których nigdy nie chcesz wymieniać ani usuwać. Są to usługi stanowe, takie jak instancja bazy danych RDS lub klaster Elasticsearch itp. Byłoby miło, gdyby aws automatycznie odmawiał wdrożenia, jeśli wykonywana operacja wymagałaby usunięcia takiego zasobu. Na szczęście chmura ma wbudowany sposób, aby to zrobić. Nazywa się to polityką stosu i możesz przeczytać więcej na ten temat w dokumentacja:

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"

Lekcja 3: Użyj UsePreviousValue podczas aktualizacji stosu z tajnymi parametrami

Kiedy tworzysz encję mysql RDS, AWS wymaga podania nazwy użytkownika MasterUsername i hasła MasterUserPassword. Ponieważ w kodzie źródłowym lepiej nie trzymać tajemnic w kodzie źródłowym, a chciałem absolutnie wszystko zautomatyzować, zaimplementowałem „inteligentny mechanizm”, w którym przed wdrożeniem będą pobierane dane uwierzytelniające z s3, a jeśli dane uwierzytelniające nie zostaną znalezione, generowane są nowe dane uwierzytelniające i zapisane w s3.

Te poświadczenia zostaną następnie przekazane jako parametry do polecenia Cloudformation create-change-set. Podczas eksperymentów ze skryptem zdarzyło się, że połączenie z s3 zostało utracone, a mój „inteligentny mechanizm” potraktował to jako sygnał do wygenerowania nowych uwierzytelnień.

Jeśli zacznę używać tego skryptu w środowisku produkcyjnym, a problem z połączeniem wystąpi ponownie, stos zostanie zaktualizowany o nowe dane uwierzytelniające. W tym konkretnym przypadku nic złego się nie stanie. Porzuciłem jednak to podejście i zacząłem stosować inne, podając dane uwierzytelniające tylko raz – podczas tworzenia stosu. A później, gdy stos wymaga aktualizacji, zamiast podawać tajną wartość parametru, po prostu użyłbym 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"

Lekcja 4: Użyj konfiguracji przywracania

Inny zespół, z którym pracowałem, korzystał z tej funkcji tworzenie się chmurnazywa konfiguracja wycofania. Nie spotkałem się z tym wcześniej i szybko zdałem sobie sprawę, że dzięki temu rozmieszczanie moich ładunków będzie jeszcze fajniejsze. Teraz używam go za każdym razem, gdy wdrażam mój kod w lambdzie lub ECS przy użyciu chmury.

Jak to działa: określasz Alarm CloudWatcha w parametrze --konfiguracja wycofaniapodczas tworzenia zestawu zmian. Później, gdy wykonasz zestaw zmian, aws będzie monitorował alarm przez co najmniej jedną minutę. Wycofuje wdrożenie, jeśli w tym czasie alarm zmieni stan na ALARM.

Poniżej znajduje się przykładowy fragment szablonu tworzenie się chmurw którym tworzę alarm w chmurze, który śledzi metrykę użytkownika chmury jako liczbę błędów w dziennikach chmury (metryka jest generowana poprzez Filtr metryczny):

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

Teraz alarm może być używany jako rollback wyzwalacz podczas wykonywania zestawu narzędzi:

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"

Lekcja 5: Upewnij się, że wdrażasz najnowszą wersję szablonu

Wdrożenie nowszej wersji szablonu cloudformation jest łatwe, ale spowoduje to wiele szkód. Zdarzyło nam się to raz: programista nie przesłał najnowszych zmian z Git i nieświadomie wdrożył poprzednią wersję stosu. Spowodowało to przestój aplikacji korzystającej z tego stosu.

Coś tak prostego, jak dodanie sprawdzenia, czy gałąź jest aktualna przed zatwierdzeniem, byłoby w porządku (zakładając, że git jest Twoim narzędziem kontroli wersji):

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

Lekcja 6: Nie wymyślaj koła na nowo

Może się wydawać, że wdrażanie za pomocą tworzenie się chmur - To jest łatwe. Potrzebujesz tylko kilku skryptów bash wykonujących polecenia aws cli.

4 lata temu zacząłem od prostych skryptów nazywanych poleceniem aws cloudformation create-stack. Wkrótce scenariusz nie był już prosty. Każda lekcja sprawiała, że ​​scenariusz był coraz bardziej złożony. Było to nie tylko trudne, ale także pełne błędów.

Obecnie pracuję w małym dziale IT. Doświadczenie pokazało, że każdy zespół ma swój własny sposób wdrażania stosów chmurowych. I to jest złe. Byłoby lepiej, gdyby wszyscy przyjęli takie samo podejście. Na szczęście dostępnych jest wiele narzędzi ułatwiających wdrażanie i konfigurowanie stosów chmurowych.

Te lekcje pomogą Ci uniknąć błędów.

Źródło: www.habr.com

Dodaj komentarz