
SAM Accelerate
Praca nad aplikacjami Serverless powoduje zmianę podejścia do testowania. Przynajmniej powinna powodować. Testowanie na lokalnych maszynach, choć czasem możliwe, jest trudne. Emulowanie infrastruktury chmurowej lokalnie jest trudne i czasochłonne. AWS udostępnił własnie wszystkim SAM Accelerate, które znakomicie przyśpiesza testy bezpośrednio w chmurze AWS.
Programista może teraz tworzyć kod aplikacji lokalnie na swojej maszynie i szybko testować go w natywnym środowisku w AWS.
O sam pisałem juz wielokrotnie. Tutaj na przykład tworzyliśmy customowy runtime dla Golang, a tu filtrowaliśmy wiadomości w kolejce SQS, które wyzwalają funkcje Lambda. Przyjrzyjmy się jednak sam accelerate.
SAM Accelerate
Aplikacja
Na początek utwórzmy jakiś bardzo prosty projekt z funkcją Lambda i endpointem w API Gateway.
Tworzymy katalog mkdir sam-accelerate
i wchodzimy do niego cd sam-accelerate
. Najlepiej nazwijcie sobie katalog tak jak ja, później będzie łatwiej.
Mamy katalog, czas na zainicjowanie projektu sam init --runtime python3.9 --name sam-test
W kreatorze wybieramy AWS Quick Start Templates i Hello World Example. Nic więcej nie będzie nam potrzebne.
Po chwili projekt będzie utworzony, a jeżeli zajrzycie do kodu Lambdy, to zobaczycie, że zwraca ona po prostu ciąg znaków. Będziemy go później zmieniali.
return { "statusCode": 200, "body": json.dumps({ "message": "hello world", # "location": ip.text.replace("\n", "") }), }
Możemy teraz wykonać synchronizację z AWS, czyli zdelpoyować naszą aplikację sam sync --stack-name sam-accelerate
Za pierwszym razem zostanie zbudowana całość i będzie tworzona także infrastruktura dla aplikacji. W zwracnych danych dostaniemy między innymi adres naszego endpointa w API Gateway. Dobrze jest gdzieś go sobie zapisać, będziemy go używali.
Infrastruktura
Jeżeli wejdziemy do usługi CloudFormation to zobaczymy tam trzy stacki utworzone podczas deploymentu. W jednym z nich (na screenie najniżej) umieszone zostały artefakty potrzebne do zdeployowania aplikacji. Ciekawsze są jednak dwa następne.
W pierwszym jest infrastruktura. W naszym przypadku mamy tu między innymi funkcję Lambda, API Gateway i oczywiście rolę dla funkcji.
Idźmy dalej. Mamy trzeci layer. Domyślnie sam pakuje zależności naszej funkcji w reużywalną warstwę. Pozwala to na przyśpieszenie kolejnych synchronizacji funkcji. Nie jest konieczne wypychanie do chmury, za każdym razem, wszystkich bibliotek, z których Lambda korzysta.
Możemy sobie taki layer ściągnąć i zobaczyć co w nim jest,
Czas wywołać nasze API i samą funkcję. Posłużymy się narzędziem curl. Nie zapomnijcie zmienić adresu endpointa na swój curl https://5ydjca7b6b.execute-api.eu-central-1.amazonaws.com/Prod/hello/
I spróbujmy po chwili podejrzeć logi sam logs --stack-name sam-accelerate
Widać logi z wywołanej funkcji, ale to co oferuje name sam cli, to możliwość podpięcia się na stałe do CloudWatcha i obserwowanie na bieżąco logów funkcji. Dodajmy do polecenia opcję tail sam logs --stack-name sam-accelerate --tail
i wywołajmy jeszcze kilka razy naszą funkcję za pomocą curla curl https://5ydjca7b6b.execute-api.eu-central-1.amazonaws.com/Prod/hello/
Przypominam ponownie o zamianie endpointa na swój.
Po chwili powinniśmy zobaczyć w oknie terminal spływające na bieżąco logi z funkcji Lambda.
Jeżeli wszystko zadziałało, zobaczmy jak działa sam accelerate.
Testy w chmurze
Na początku napisałem, że najlepiej jest testować aplikacje serverless w chmurze. Zobaczmy jak sam accelerate nam to ułatwia.
Zmieńmy teraz kod funkcji tak aby zwracała hello sam zamiast hello world.
return { "statusCode": 200, "body": json.dumps({ "message": "hello sam", # "location": ip.text.replace("\n", "") }), }
I teraz wchodzi sam accelerate, czyli możliwość monitorowania zmian w kodzie lub szablonie infrastruktury. Wykonajmy synchronizację za pomocą polecenia sam sync --stack-name sam-accelerate --watch
Teraz, po wykonaniu synchronizacji sam cli będzie monitorował nasz kod i każda zmiana będzie automatycznie synchronizowana z AWS. Co ważne, w przypadku zmiany tylko kodu funkcji, nie będzie wykonywany cały deployment poprzez CloudFormation, zostanie zaktualizowana tylko sama funkcja. Zajmuje to o wiele mniej czasu.
Spróbujmy jeszcze raz zrobić request do naszego API curl https://5ydjca7b6b.execute-api.eu-central-1.amazonaws.com/Prod/hello/
Jeszcze raz zmieńmy kod naszej funkcji.
return { "statusCode": 200, "body": json.dumps({ "message": "hello sam accelerate", # "location": ip.text.replace("\n", "") }), }
Po zapisaniu zmian sam cli wykryje zmiany i wykona deployment tylko zmienionych zasobów do AWS
Aby to pokazać otwórzmy sobie trzy okna terminala. W pierwszym mamy włączoną synchronizację z AWS za pomocą polecania sam sync --stack-name sam-accelerate --watch
. Drugie to podgląd logów, czyli sam logs --stack-name sam-accelerate --tail
. W trzecim za pomocą curla wywołamy nasze API po synchronizacji zmian.
Kolejna zmiana funkcji Lambda
return { "statusCode": 200, "body": json.dumps({ "message": "hello sam accelerate 2", # "location": ip.text.replace("\n", "") }), }
i po zapisaniu zmian nasąpi automatyczna synchronizacja. Po jej zakończeniu wywołujemy API curl https://5ydjca7b6b.execute-api.eu-central-1.amazonaws.com/Prod/hello/
Jak widać, po zmianach w kodzie funkcji zostały one automatycznie zdeployowane do AWS i możemy bezpośrednio w chmurze testować naszą aplikację. Szybkie i wygodne.
Na koniec warto po sobie posprzątać, kasujemy więc wszystkie zasoby za pomocą polecenia sam delete --stack-name sam-accelerate
Podsumowanie
Testowanie aplikacji jest ważne. O ile testy jednostkowe możemy dość łatwo przeprowadzić lokalnie, gorzej to wygląda, jeżeli chodzi o testy integracyjne czy e2e.
Możemy posiłkować się protezami, takimi jak localstack czy moto. Na dłuższą metę staje się to jednak bardzo uciążliwe, odechciewa się wszelkiego testowania. Ponad to, ciężko na przykład przetestować uprawnienia takie jak role.
sam accelerate bardzo ułatwia i przyśpiesza testy. Nie musimy już czekać na deployment całego stacka przy każdej zmianie.
Polecam sprawdzić.