Рубрики
Uncategorized

» Развертывания CloudFront с лямбда@Edge «

A/B -тестирование, синие/зеленые развертывания, канарейские релизы. Разные, но все же так много общего. Они… Помечено с AWS, DevOps, лямбда.

A/B -тестирование, синие/зеленые развертывания, канарейские релизы. Разные, но все же так много общего. Все они имеют разные цели, но используют в основном одно и то же техническое решение под капотом. Мы делаем такие испытания по нескольким причинам. Один — сделать тест A/B и определить, какую версию наших пользователей нравится лучшие. Уверен, что можно сделать A/B тестирование на клиентской стороне, но лично мне упростить на стороне сервера. Голубые/зеленые и канаречные развертывания сделаны, чтобы убедиться, что новая версия приложений работает так, как мы ожидаем и дам нам простой способ откатываться в предыдущую версию в случае проблемы. Все это важные практики в культуре DevOps.

Многие услуги от AWS предлагают это решение из коробки, одна услуга, которая не является Humentfront. К счастью, Cloudfront имеет возможность запустить лямбда @ kems, которую мы можем использовать для этого.

Весь исходный код для этой настройки найден на GitHub

Представляем Lambda @ Edge

Lambda может работать в четырех разных местах в потоке запросов.

Просмотр просмотра — работает, когда CloudFront получает запрос от зрителя. Происхождение запроса — бежит до того, как Cloudfront пересылает запрос к началу. Ответ происхождения — запускается, когда CloudFront получает ответ от начала координат. Ответ просмотра — запускается до того, как CloudFront возвращает ответ зрителям.

Есть несколько ограничений, когда дело доходит до лямбда@Edge, можно только создавать функции в Python и Node.js. Функции запроса просмотра и ответа могут выделять только 128 МБ памяти и работать только в течение 3 секунд. Вы не можете использовать переменные среды, вы не можете использовать Последние Версия псевдоним, поддерживаются только фиксированные версии. Журналы публикуются в области края, к которой вы получаете доступ, а не в US-EAST-1 регион, даже если функции должны быть развернуты в этом регионе. Обязательно прочитайте Документация Прежде чем начать работать с лямбда @ жрать.

Обзор решения

В этом решении мы собираемся использовать две разные функции Lambda для просмотр просмотра и Ответ происхождения Крюки, мы будем хранить конфигурацию в хранилище параметров, а S3 — наше происхождение.

В просмотр просмотра Крюк Мы проверим специальное cookie, если файл cookie не установлен, мы принесем случайную версию. В Ответ происхождения Мы устанавливаем Set-Cookie Заголовок для хранения версии, которую мы используем. Установив различные значения в хранилище параметров, мы можем управлять весом каждой версии, а также мы можем сбросить и заставить клиентов получать новую случайную версию.

Запрос на зритель

Начнем с функции Lambda, которая будет реагировать на событие запроса зрителя. Эта функция Lambda отвечает за проверку нашего cookie X-версия-имя Если значение установлено, функция обновит путь запроса на основе значения cookie. Если нет установленного значения, он будет катиться в Dice и получить случайную версию и обновить путь запроса. Эта функция также сопоставит значение в cookie X-версию-сброс к значению в магазине параметра, и если значение отличается, он будет игнорировать любое заданное значение в X-версия-имя Анкет Если нет значения в X-версия-имя Или если значение игнорируется, функция бросает кости и выбирает версию наугад. Вес для разных версий контролируется значением в магазине параметра. Наконец, функция передает файл cookie к следующему шагу в цепочке вызовов.

Код запроса просмотра

Полная версия доступна в GitHub Анкет

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    headers = request['headers']

    cookie_version_blue = 'X-Version-Name=Blue'
    cookie_version_green = 'X-Version-Name=Green'
    path_blue = '/Blue'
    path_green = '/Green'

    uri = ''

    if request['uri'].endswith('/'):
        request['uri'] = request['uri'] + 'index.html'

    if 'cookie' not in request['headers']:
        request['headers']['cookie'] = []

    # Reset weights, ignore already set cookie
    reset_weight, reset_cookie = do_weight_reset(headers)
    if not reset_weight:
        for cookie in headers.get('cookie', []):
            if cookie_version_blue in cookie['value']:
                uri = path_blue + request['uri']
                break
            elif cookie_version_green in cookie['value']:
                uri = path_green + request['uri']
                break
    request['headers']['cookie'].append(
        {'key': 'Cookie', 'value': reset_cookie})

    if not uri:
        weight = int(load_parameter('Weight'))
        cookie_value = ''

        if random.random() < float(weight / 100.0):
            uri = path_blue + request['uri']
            cookie_value = cookie_version_blue
        else:
            uri = path_green + request['uri']
            cookie_value = cookie_version_green
        request['headers']['cookie'].append(
            {'key': 'Cookie', 'value': cookie_value})

    request['uri'] = uri
    return request

Ответ зрителя

Ответ просмотра Функция в основном имеет одну задачу, и это должен пройти Set-Cookie заголовок к клиенту. Это необходимо, чтобы клиент установил файлы cookie X-версия-имя и X-версия-сброс Таким образом, клиент отправляет их в следующий запрос. Это важно, чтобы клиент не прыгал между версиями. У этой функции есть небольшая, но очень важная работа.

Код ответа просмотра

Полная версия доступна в GitHub Анкет

def lambda_handler(event, context):
    response = event['Records'][0]['cf']['response']
    request = event['Records'][0]['cf']['request']
    # Persist cookie, set the set-cookie header
    if 'set-cookie' not in response['headers']:
        response['headers']['set-cookie'] = []

    request_headers = request['headers']
    cookie_version_blue = 'X-Version-Name=Blue'
    cookie_version_green = 'X-Version-Name=Green'
    cookie_reset = 'X-Version-Reset'

    for cookie in request_headers.get('cookie', []):
        if cookie_version_blue in cookie['value']:
            response['headers']['set-cookie'].append(
                {'key': 'set-cookie', 'value': cookie_version_blue})
        elif cookie_version_green in cookie['value']:
            response['headers']['set-cookie'].append(
                {'key': 'set-cookie', 'value': cookie_version_green})
        elif cookie_reset in cookie['value']:
            response['headers']['set-cookie'].append(
                {'key': 'set-cookie', 'value': cookie['value']})

    return response

Развертывание функций

Функции лямбда должны быть развернуты в регионе США-Востока-1, поскольку именно этот край лямбда @ Мы также должны использовать фиксированную версию и не можем использовать Последние псевдоним. Как обычный AWS SAM используется для определения и развертывания функций Lambda.

Шаблон SAM

Полная версия доступна в GitHub Анкет

ViewerRequestFunction:
    Type: AWS::Serverless::Function
    Properties:
        AutoPublishAlias: "true"
        Runtime: python3.7
        MemorySize: 128
        Timeout: 3
        CodeUri: ./viewer-request
        Handler: handler.lambda_handler
        AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
            - Effect: Allow
            Principal:
                Service:
                - lambda.amazonaws.com
                - edgelambda.amazonaws.com
            Action:
                - sts:AssumeRole
        Policies:
        - SSMParameterReadPolicy:
            ParameterName: !Sub ${SsmConfigPath}/*
        - Version: "2012-10-17"
            Statement:
            Action:
                - lambda:GetFunction
            Effect: Allow
            Resource: "*"

ViewerResponseFunction:
    Type: AWS::Serverless::Function
    Properties:
        AutoPublishAlias: "true"
        Runtime: python3.7
        MemorySize: 128
        Timeout: 3
        CodeUri: ./viewer-response
        Handler: handler.lambda_handler
        AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
            - Effect: Allow
            Principal:
                Service:
                - lambda.amazonaws.com
                - edgelambda.amazonaws.com
            Action:
                - sts:AssumeRole
        Policies:
        - Version: "2012-10-17"
            Statement:
            Action:
                - lambda:GetFunction
            Effect: Allow
            Resource: "*"

Настройка Cloudfront

Наконец, нам нужно создать распределение CloudFront и установить функции лямбда для запроса запроса зрителя и триггеры ответа. Обычно CloudFront не будет использовать и передавать заголовки к кешу. Поскольку наша настройка зависит от двух файлов cookie, мы должны убедиться, что CloudFront передал их. Это сделано путем добавления их в WhitelistedNames. раздел. Поддержание подстановки, поэтому мы просто добавляем X-version-* к этому разделу.

Шаблон деформации облака

Полная версия доступна в GitHub Анкет

CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Comment: !Sub "Distribution for ${ProjectName}"
        DefaultCacheBehavior:
          AllowedMethods:
            - "GET"
            - "HEAD"
            - "OPTIONS"
          Compress: False
          DefaultTTL: 0
          MaxTTL: 0
          MinTTL: 0
          ForwardedValues:
            QueryString: False
            Cookies:
              Forward: whitelist
              WhitelistedNames:
                - "X-Version-*"
          LambdaFunctionAssociations:
            - !If
              - ViewerRequestLambdaArnSet
              - EventType: viewer-request
                LambdaFunctionARN: !Ref ViewerRequestLambdaArn
              - !Ref AWS::NoValue
            - !If
              - ViewerResponseLambdaArnSet
              - EventType: viewer-response
                LambdaFunctionARN: !Ref ViewerResponseLambdaArn
              - !Ref AWS::NoValue
          TargetOriginId: !Sub ${ProjectName}-origin
          ViewerProtocolPolicy: redirect-to-https
        DefaultRootObject: !Ref DefaultRootObject
        Enabled: True
        Origins:
          - DomainName: !Sub ${StorageBucket}.s3.amazonaws.com
            Id: !Sub ${ProjectName}-origin
            S3OriginConfig:
              OriginAccessIdentity: !Sub origin-access-identity/cloudfront/${OriginAccessIdentity}
        PriceClass: PriceClass_100
      Tags:
        - Key: Name
          Value: !Sub ${ProjectName}

Вывод

Несмотря на то, что Cloudfront не поддерживает эти методы развертывания из коробки Lambda, как и раньше, приходите на помощь. Универсальность AWS Lambda — это действительно чудо! Загрузите код и возьмите его для Spin!

Счастливый взлом!

Оригинал: «https://dev.to/jimmydqv/cloudfront-deployments-with-lambda-edge-4jmh»