AWS Lambda, как правило, является одним из самых простых способов развертывания и выполнения кода в облаке, особенно при развертывании кода с помощью sam CLI. Простота определений бессерверных ресурсов в сочетании с возможностью локальной упаковки ресурсов и обеспечения их работы на AWS обеспечивает прекрасный опыт разработки.

За исключением того, что иногда этот красивый процесс может превратиться в чудовище развертывания, когда шаги сборки и пакета увеличиваются до десяти, пятнадцати или (ах!) Дополнительных минут. Есть несколько мест, где парадигма sam build / sam deploy ломается и начинает вызывать неконтролируемое время развертывания:

  • Количество лямбда-выражений в развертывании становится большим (например, более полудюжины).
  • Некоторые или все ваши лямбда-выражения имеют большое количество ресурсов для установки и / или большой размер пакета Lambda (увеличивая время сборки и для sam, чтобы поместить код на S3)
  • Вы вносите согласованные изменения в два Lambdas сразу (перед тестированием необходимо обновить несколько стеков в AWS)
  • Несколько человек одновременно разрабатывают один и тот же стек Lambda.
  • Ваш Интернет медленный (опять же, время размещения пакетов Lambda в S3 увеличивается)

Поскольку sam развертывает все ресурсы в CFT, вы не можете выборочно выбрать, какие из них следует обновлять постепенно. Влияние заключается в том, что вам необходимо собрать и загрузить весь свой код в AWS для каждого развертывания, которое вы хотите протестировать в облаке. Это особенно раздражает, когда вы отправляете код в AWS только для того, чтобы понять, что вы неправильно написали строку и вам нужно повторно развернуть весь стек.

Да, sam действительно предоставляет способ локального вызова лямбда-выражений, но это не помогает, если вы хотите протестировать согласованные изменения между лямбда-выражениями. С sam вы не можете развернуть две лямбда-выражения локально и маршрутизировать трафик между ними (насколько мне известно). Конечно, могут быть более эффективные способы структурирования и развертывания кода для предотвращения проблем с монолитным развертыванием, но всегда найдутся компромиссы. Сколько функционального кода должно уместиться в одной лямбде? Как выбрать, когда разделять функции на разные стеки? Как организовать репозитории вокруг стеков?

Что можно сделать, если у вас есть длинные шаги по упаковке и развертыванию, но вы хотите сократить время, необходимое для сборки и тестирования ваших лямбда-выражений? Или если у вас есть лямбда-выражения из разных стеков, которые вызывают друг друга, и вы хотите протестировать их локально одновременно?

Перенаправьте трафик через прокси

Основной принцип перенаправления трафика с помощью прокси-сервера заключается в том, что мы хотим захватить запрос в полете, который идет в AWS, а затем отправить его обратно на наш локальный компьютер, вместо того, чтобы позволить ему перейти в облако. Этот процесс обычно называют Человеком посередине (MITM). Имя получает плохую репутацию из-за того, что широко используется для взлома, но оно имеет практическое применение, помогая сократить время, необходимое для тестирования лямбда-выражений.

Ключевым моментом здесь является то, что нам нужно только перенаправить предварительно настроенные конечные точки обратно на нашу локальную машину. Если, например, мы развертываем стек с пятью лямбдами, и мы вносим изменения только в одну из этих лямбд, то трафик для остальных четырех должен продолжать поступать в AWS.

Захват трафика, идущего в AWS

Когда вы вызываете AWS Lambda с boto3 или другим пакетом AWS, вы просто вызываете API через HTTPS; пакет AWS выполняет за вас аутентификацию, создание конечных точек и сериализацию. Поскольку весь этот трафик отправляется через HTTPS, вы можете просматривать весь исходящий HTTPS-трафик вашего компьютера через прокси!

Если у вас Mac, вы можете обновить настройки прокси-сервера HTTPS в системных настройках, а затем network > advanced > proxies. Здесь я включил локальный прокси для порта 9090.

Вы можете увидеть трафик, проходящий через трафик, если вы загрузите такой инструмент, как Proxyman, а затем вызовете лямбда-выражения со своего локального компьютера.

Сопоставьте трафик от конечных точек, чтобы перенаправить их локально

Теперь, когда трафик HTTPS проходит через наш прокси, у нас есть возможность манипулировать им. Это делается с помощью программы «человек посередине». Этот MITM будет читать все события, которые проходят через прокси, и при необходимости применять к ним какие-либо действия. Это ключ к локальному тестированию наших лямбда-выражений.

Я использую mitmproxy, сверхмощный инструмент, который позволяет применять логику сценариев к любым записям, также известным как потоки, которые проходят через прокси. Mitmproxy cli принимает файл python в качестве аргумента, в котором он будет передавать события HTTPS сценарию python для выполнения действий. Вот пример сценария, который направляет весь трафик с google на bing и с reddit на medium.

Этот код можно запустить с помощью команды (примечание: 9090 - это порт, на котором работает мой прокси HTTPS):

mitmdump -p 9090 reroute_traffic.py

Перенаправление лямбда-трафика

Возможно, вы заметили на скриншоте выше, что все запросы к AWS подчиняются одному и тому же соглашению об именах; регион, дата версии лямбда и имя лямбда-функции объединяются для построения конечной точки. Когда вы запускаете sam local start-lambda …, аналогичный процесс происходит локально! AWS создает на вашем компьютере локальную конечную точку, которая сопоставляется с определенным портом. Вы даже можете указать этот порт следующим образом:

sam local start-lambda -p 54321 --template /path/to/template.yaml

Ваша Lambda будет работать локально, и вы увидите локальную конечную точку:

До сих пор мы узнали, как захватить и перенаправить трафик с человеком в середине, а также как локально запустить лямбду и выбрать порт, на котором она работает. Осталось только построить карту, которая указывает от конечной точки в AWS до нашего локального порта, на котором работает эта Lambda. Здесь для вас могут возникнуть сложности. Когда sam запускает лямбда локально, вы можете вызвать лямбда только с именем ресурса, но, как мы видели выше, лямбда-URL содержит имя функции.

Я всегда использую стандартизированные соглашения об именах для своих лямбда-выражений, и моя команда очень строго соблюдает их, как вы можете видеть выше, это соглашение об именах «{StackName} - {ResourceName} - {Env}». Это позволяет мне просто удалить имя стека и среду из имени функции при маршрутизации трафика на локально работающую Lambda. Это позволяет сценарию «человек посередине» заменять потоки, используя эту базовую логику!

reroute_flow = {
    'from_route':'my-stack-MyLambda1-dev', 
    'to_route': 'MyLambda1'
}
mf = MatchedFlow(**reroute_flow)
FM = FlowMatcher([mf])

И вуаля! После подключения к скрипту «человек посередине» мы направляем трафик на наши локальные лямбды. Мы даже можем определить несколько перенаправлений, чтобы направлять трафик между локальными версиями наших лямбда-выражений!

reroute_flow1 = {
    'from_route':'my-stack-MyLambda1-dev', 
    'to_route': 'MyLambda1'
}
reroute_flow2 = {
    'from_route':'my-stack-MySecondLambda-dev', 
    'to_route': 'MySecondLambda'
}
mf1 = MatchedFlow(**reroute_flow1)
mf2 = MatchedFlow(**reroute_flow2)
FM = FlowMatcher([mf1, mf2])

LocaLambda - интерфейс командной строки для упрощения работы

Чтобы протестировать Lambdas локально, нужно многое сделать: настроить HTTPS-прокси, определить правила сопоставления, локально обслуживать Lambdas и т. Д. LocaLambda, или для краткости lola, - это облегченный интерфейс командной строки, который здесь, чтобы упростить процесс. Лола выполняет три функции:

  • Настройка: настройте необходимые ресурсы и файлы конфигурации для запуска lola, это одноразовое действие после установки lola
  • Сборка: lola будет создавать определенные ресурсы, определенные в вашем файле lola.yaml. Он делает это путем репликации фактического файла template.yaml с уменьшенной версией, которая содержит только указанные ресурсы.
  • Обслуживание: lola запускает sam local start-lambda... для каждой лямбда-выражения, определенной в вашем файле конфигурации, отслеживая конкретный используемый порт. Затем он автоматически запустит ваш локальный прокси-сервер HTTPS и выполнит человека в среднем сценарии. Следует отметить, что человек в середине работает в другом исполняемом файле, чем lola. Чтобы сообщить человеку в середине, какую логику сопоставления применять, он сериализует сопоставления для локально развернутых ресурсов и размещает их в Redis (который также должен быть запущен локально).

Настройка LocaLambda

LocaLambda доступна на pypi и может быть установлена ​​с помощью:

pip install localambda

При первой установке LocaLambda необходимо настроить несколько файлов ресурсов и конфигурации, которые будут специфичными для вашего компьютера. Вы можете попросить LocaLambda провести вас через одноразовую настройку с помощью:

lola --setup

Результатом этого является .lolarc файл ресурсов, расположенный в вашем домашнем каталоге, и новый каталог lola, расположенный в выбранном вами месте. Вам нужно будет создать файл lola.yaml, такой как приведенный ниже, в каталоге lola, который сообщит LocaLambda, какие ресурсы нужно создавать и обслуживать. Этот файл также можно найти в репозитории GitHub в разделе Примеры.

Многие из этих конфигураций основаны на том, что мы используем, и вполне вероятно, что у вас будут немного другие потребности. Из-за стандартного соглашения об именах, которое я использую для лямбда-выражений, мне нужно сказать lola только о трех вещах:

  1. Расположение файла template.yaml: это объединение repo_home и location, или может быть указано полное местоположение. Это должен быть каталог, в котором находятся код и шаблон.
  2. Имя стека: lola необходимо удалить имя стека и имя среды из HTTPS-запроса, отправляемого к AWS, чтобы найти конкретное имя ресурса. Среда будет статической (dev), так что на данный момент это жестко запрограммировано.
  3. Ресурсы: список имен ресурсов в файле CFT template.yaml, которые следует развернуть или обслужить. Если у вас есть десять лямбд в вашем CFT, здесь вы можете выбрать один, два или любое другое количество для сборки и тестирования, вместо того, чтобы создавать и развертывать все десять.

Бегущая лола

LocaLambda выполняет две основные задачи: создает ресурсы и обслуживает их локально. Вы можете создавать и обслуживать лямбды с помощью lola независимо или можете делать и то, и другое одновременно. Для строительства просто требуется флаг -b, а для обслуживания - -s. Для создания и обслуживания вы можете запустить:

lola -bs

При запуске этой команды с использованием образца файла конфигурации вы получите следующий результат:

LocaLambda будет выполнять несколько шагов в последовательном порядке, некоторые из которых можно пропустить, если вы только создаете или развертываете:

  1. (сборка) Создайте сокращенную версию шаблона развертывания для каждого стека в конфигурации lola.yaml, в сборку включаются только выбранные ресурсы, а не весь стек
  2. (build) Запустите sam build ... для каждого из ваших уменьшенных шаблонов
  3. (serve) Для каждого стека, определенного в lola.yaml, запустите sam local start-lambda ..
  4. (serve) Для каждого стека, определенного в lola.yaml, сериализуйте логику сопоставления для человека в середине и поместите их в Redis
  5. (serve) Запустите человека посередине, который читает конфигурации из Redis и начинает сопоставление событий HTTPS.

Отключить проверку SSL

Поскольку мы захватываем HTTPS-трафик на лету и перенаправляем его на другой хост, мы неизбежно столкнемся с проблемами SSL-сертификата, поскольку у вашего локального компьютера нет возможности иметь сертификаты, покрывающие домен AWS. Чтобы обойти это, разработчики AWS Lambda предоставили отличный способ отключить проверку SSL. При настройке вашего Lambda-клиента просто установите флаг проверки на False, как показано здесь с помощью boto3:

import boto3
lambda_client = boto3.client('lambda', verify=False)

На самом деле, вы не хотите жестко кодировать это значение, потому что во всех других средах вам нужно, чтобы лямбда-клиент проверял сертификат. Одно из предложений здесь - просто использовать переменную среды для среды (например, local, dev, staging, prod и т. Д.) И установить ее только для проверки при локальном развертывании.

Проверка на перехват и перенаправление событий

Теперь, когда все настроено и работает, мы можем проверить правильность маршрутизации трафика на локальную лямбду. Следующий сценарий можно запустить в оболочке, пока lola обслуживает ваши локальные ресурсы.

За кулисами я настроил его так, чтобы эта лямбда развертывалась локально и вызывала другую лямбду, развернутую в AWS. Здесь вы можете видеть, что трафик направляется на первую Lambda, обслуживаемую локально, а не на AWS!

Заключительные мысли

LocaLambda может быть замечательным инструментом в вашем наборе инструментов для ускорения процесса разработки, но это ни в коем случае не серебряная пуля. Он более легкий, чем localstack, но, вероятно, все же слишком тяжелый, если для создания и отправки кода в AWS потребуется всего пара минут. Есть несколько мест, где есть возможности для улучшения и (и обратная связь / PR всегда приветствуются):

  • Разрешить настраиваемую логику сопоставления имени функции с сопоставлением ресурсов
  • Обработка интеграции слоев, как локальных, так и импортированных из AWS
  • Управление туннелями ssh; многие лямбды, которым необходим доступ к базам данных в частных сетях, также развернуты в частных сетях или, по крайней мере, в группах безопасности, которые имеют доступ к базам данных. Возможность быстро тестировать лямбды, которым требуется доступ к БД, без головной боли ручной настройки туннеля, было бы большим улучшением.
  • Возможность развертывания с различными структурами для шаблонов в репо (например, template.yaml не находится в корне репо, несколько шаблонов, встроенный шаблон и т. Д.)
  • Разрешить динамическое связывание и отключение для разных файлов конфигурации lola.yaml, чтобы избежать необходимости обновлять одну конфигурацию

В общем, это изящный и забавный маленький инструмент, который удовлетворяет потребности в нишевых сценариях использования, с которыми время от времени сталкиваются наши команды. Я надеюсь, что вы тоже сможете извлечь пользу из этого проекта!