Scott Tiger Tech Blog

Blog technologiczny firmy Scott Tiger S.A.

Skalowalne aplikacje w chmurze AWS

Autor: Piotr Karpiuk o piątek 9. Czerwiec 2017

Wprowadzenie

W dzisiejszym artykule zajmiemy się zagadanieniem tworzenia skalowalnych, odpornych na awarie rozproszonych aplikacji w chmurze AWS. Kluczowy jest tu styl zarządzania infrastrukturą zobrazowany schematycznie na poniższym rysunku:

  1. Nowe komponenty infrastruktury są automatycznie aprowizowane z repozytorium systemu kontroli wersji w powtarzalny i przewidywalny sposób.
  2. Instancje EC2 są bezstanowe, w związku z tym mogą być wyjmowane z sieci i niszczone w dowolnym momencie, bez ryzyka utraty stanu aplikacji i jej danych.

Aprowizacja nowych instancji EC2

Zdarzenia inicjujące pojawienie się nowych instancji w aplikacji rozproszonej mogą być rozmaite:

  • pierwotne uruchomienie podstawowych instancji aplikacji,
  • zastąpienie nowym egzemplarzem instancji która uległa awarii,
  • reakcja na zwiększony ruch klientów poprzez zwiększenie liczby instancji w grupie autoskalowania,
  • stopniowe wdrażanie nowej wersji oprogramowania (np. metodą blue-green).

Proces automatycznej aprowizacji nowych instancji i uruchomienie ich w kontekście aplikacji nosi nazwę rozruchu (ang. bootstrapping). Dwa najpopularniejsze sposoby rozruchu to wykorzystanie odpowiednio przygotowanych AMI (Amazon Machine Image) oraz użycie konfiguracji dynamicznej.

Własne AMI

Co ma się znaleźć w obrazie AMI? Istnieją różne szkoły. Na poniższym rysunku trzy rodzaje AMI: Base, Foundational i Full stack.

W praktyce najlepiej sprawdzi się podejście hybrydowe: AMI będzie zawierało system operacyjny i rzadko aktualizowane oprogramowanie (np. maszyna wirtualna Javy), a po uruchomieniu instancji z tego obrazu trzeba jeszcze będzie wgrać najnowszy kod aplikacji i jego konfigurację.

Wielu ludzi ręcznie przygotowuje nową wersję AMI według przepisu:

  1. Uruchamiamy instancję z poprzednią wersją AMI.
  2. SSH-ujemy się do tej instancji i ręcznie modyfikujemy jej system plików (aktualizujemy źródła i pakiety, instalujemy nowe aplikacje),
  3. Tworzymy nowe AMI na podstawie działającej instancji.
  4. Usuwamy instancję.

To podejście działa, ale jest niewygodne i mało wydajne na większą skalę gdy trzeba takie operacje wykonywać regularnie i często. Duże firmy takie jak Netflix używają innego podejścia:

  1. Mamy cały czas działającą instancję EC2.
  2. Podpinamy do niej wolumen EBS utworzony na bazie AMI z poprzednią wersją.
  3. Wykonujemy skrypty modyfikujące system plików na wolumenie EBS.
  4. Wykonujemy migawkę (ang. snapshot zmodyfikowanego wolumenu.
  5. Rejestrujemy migawkę jako nową wersję AMI.

Dynamiczna konfiguracja

Mamy tu bardzo duży zakres możliwości – od prostych skryptów po scentralizowane narzędzia do zarządzania konfiguracją.

Skrypty

Gdy uruchamiamy instancję EC2, wybieramy jej typ, obraz AMI i ustalamy wartości szeregu innych parametrów. Jednym z nich są dane użytkownika (ang. user data) w postaci ciągu znaków. Po uruchomieniu instancja może odczytać wartość tego parametru ze swoich metadanych, ale ważniejsze jest to, że gdy na maszynie uruchamiamy któryś z oficjalnych obrazów Linuksa, dane użytkownika są interpretowane albo jako skrypt shella (gdy łańcuch zaczyna się od „#!”):

#!/bin/sh
yum update -y
yum -y install httpd php php-mysql
chkconfig httpd on
/etc/init.d/httpd start

albo tzw. skrypt cloud-init:

#cloud-config

repo_update: true
repo_upgrade: all

packages:
- httpd
- php
- php-mysql

runcmd:
- service httpd start
- chkconfig httpd on

Z kolei oficjalne obrazy Windows zawierają usługę EC2Config która aktywuje system, ustawia hasło administratora, ale też interpretuje łańcuch danych użytkownika jako skrypt cmd.exe lub Windows PowerShell.

Ponieważ dane użytkownika są ograniczone do 16KB, więc w razie gdy mamy dużo zadań do wykonania warto w skrypcie umieścić zaciągnięcie dodatkowych skryptów z usługi S3, i wykonanie ich.

Metadane EC2

Gdy instancja jest uruchamiana, wykonujące się na niej oprogramowanie chce mieć dostęp do kontekstu w jakim działa instancja – nazwa hosta, w jakim regionie, łańcuch danych użytkownika itp. Tego rodzaju informacje są serwowane przez usługę EC2 metadata, dostępną poprzez wywołanie HTTP GET z poziomu instancji. Przykładowo, aby otrzymać nazwę hosta, wystarczy curlem sięgnąć pod adres:

http://169.254.169.254/latest/meta-data/hostname
Tagowanie zasobów

Każdą instancję możemy otagować, przypinając do niej pary klucz/wartość. Podczas rozruchu instancja może ze swoich tagów wyczytać rolę jaką ma pełnić w środowisku aplikacji rozproszonej.

Praktyczny przykład

Na poniższym rysunku przedstawiono dość rozbudowany przykład dynamicznej konfiguracji instancji. Najpierw na podstawie łańcucha danych użytkownika ładujemy z S3 podstawowy skrypt konfiguracyjny. Jego zadaniem jest konfiguracja systemu do postaci bazowej wspólnej dla wszystkich instancji niezależnie od przyjmowanej roli w systemie (np. łatanie systemu operacyjnego, instalacja agentów monitorujących). Ten sam skrypt odczytuje tagi instancji i na ich podstawie decyduje o wyborze i uruchomieniu kolejnych skryptów nakładkowych (ang. overlay scripts) wykonujących działania zależne od ustalonej roli instancji (np. instalowanie serwera Apache dla serwerów webowych). Ostatni rodzaj skryptów to te, które na podstawie tagów przeprowadzają ostateczną, najbardziej drobiazgową konfigurację (np. ustawiają poziom logowania na DEBUG dla środowisk testowych).

Narzędzia zarządzania konfiguracją

Podejście skryptowe działa, ale szybko staje się zbyt skomplikowane dla dużych środowisk. Narzędzia zarządzania konfiguracją (takie jak Chef, Puppet, Ansible czy SaltStack) pozwalają zdefiniować konfigurację środowiska w języku dedykowanym (ang. domain specific language) deklaratywnie opisującym docelowy stan który chcemy osiągnąć (w odróżnieniu od imperatywnego określania jak osiągnąć końcowy efekt w metodzie skryptowej). Taki deklaratywny opis jest kodem, który można przechowywać w systemach kontroli wersji tak jak kod aplikacji. Wiele narzędzi zarządzania konfiguracją oferuje dodatkowe funkcjonalności, takie jak zapewnienie zgodności z regulacjami prawnymi (ang. compliance), możliwość przeprowadzania audytu czy wyszukiwanie zasobów w środowisku.

Modele push vs pull

Narzędzia zarządzania konfiguracją zwykle wykorzystują jeden z dwóch modeli: push albo pull, w zależności od tego jak instancja EC2 wchodzi w interakcję z głównym serwerem zarządzania konfiguracją.

W modelu push serwer konfiguracji wpycha konfigurację do wszystkich instancji za pośrednictwem np. SSH albo zainstalowanych na instancjach agentów. Aby to działało, serwer konfiguracji musi znać wszystkich swoich klientów, a instancje EC2 muszą mieć odblokowane odpowiednie porty. Jak pokazuje praktyka, metoda push słabo się skaluje.

W modelu pull wszystkie instancje mają zainstalowanego agenta systemu zarządzania konfiguracją. Ten agent łączy się z serwerem konfiguracji (HTTPS) i wyciąga z niego wszystkie potrzebne informacje do poprawnego skonfigurowania instancji. Może to robić tylko podczas rozruchu instancji, ale również systematycznie odpytywać serwer później.

Przykład: Chef

Chef to otwartoźródłowe narzędzie do zarządzania konfiguracją używające modelu pull. Rozważmy użycie go do rozruchu instancji w naszej aplikacji chmurowej. Zakładamy, że w obrazy AMI mamy wbudowane narzędzia CLI do komunikacji z chmurą AWS, jak również klienta (agenta) Chef. Książka kucharska Chefa (ang. a Chef cookbook) to kolekcja przepisów, a przepis to definicja zasobów (pliki, pakiety, uprawnienia itp.) jakie powinny zostać skonfigurowane na instancji. Książka kucharska jest ładowana na serwer Chefa. Chef daje możliwość grupowania książek kucharskich według ról, bardzo użytecznych w wielkoskalowych środowiskach gdzie instancje mogą mieć różne role (role mogą się nakładać). O roli instancji decyduje jej tagowanie. Serwer webowy i bazodanowy mogą używać tego samego łańcucha danych użytkownika, o ile mają różne tagi. Instancje zgłaszają się do serwera Chefa i autoryzują się w nim używając prywatnego klucza pobranego z zaszyfrowanego kubełka S3, do którego ograniczamy dostęp za pomocą ról usługi IAM. Instancje muszą też wiedzieć gdzie jest serwer Chefa – tę informację pobierają z pliku umiejscowionego w S3.

Zarządzanie środowiskiem za pomocą usług AWS

Amazon sam oferuje usługi wspomagające wdrożenie aplikacji rozproszonej i późniejsze zarządzanie jej cyklem życia. Powodów dla których ktoś chciałby użyć tych usług jest kilka:

  • wdrożenie jest zautomatyzowane, przewidywalne i powtarzalne,
  • wdrożenie dotyczy nie tylko instancji EC2, ale również innych usług AWS takich jak grupy autoskalowania, komponenty sieciowe czy kolejki komunikatów,
  • uwzględniane są uprawnienia i role (usługa IAM).
  • widoczny jest postęp procesu wdrażania i generowane są logi dostępne do wglądu,
  • wdrożenie można parametryzować aby np. odróżniać środowisko testowe od produkcyjnego,
  • wszystkie alokowane zasoby mogą być automatycznie tagowane, np. nazwą projektu, co ułatwia zarządzanie zasobami i śledzenie kosztów.

Poniższy obrazek pomaga wybrać właściwą usługę dla naszych aplikacji w zależności od poziomu kontroli jaki nas interesuje.

Elastic Beanstalk

Elastic Beanstalk troszczy się o wdrożenie, zapewnienie zdolności produkcyjnej (ang. capacity provisioning), równoważenie obciążenia, automatyczne skalowanie i monitorowanie stanu aplikacji. Nie jest to czarna skrzynka: mamy pełny wgląd i kontrolę nad używanymi pod spodem zasobami AWS. Beanstalk obsługuje wdrożenie aplikacji pisanych w językach Java, .NET, Ruby, PHP, Python, Node.js i Dockera na powszechnie używanych technologiach takich jak serwery webowe Apache, Nginx, Passenger i IIS oraz bazy danych MySQL, PostgreSQL czy Oracle. Typowe zastosowania obejmują aplikacje webowe i systemy zarządzania treścią (ang. content management systems, CMS). Domyślna konfiguracja oferowana przez Beanstalka może być modyfikowana np. o instalację dodatkowych pakietów z yuma, skopiowanie plików wymaganych przez aplikację, wykonanie poleceń czy podmianę plików konfiguracyjnych – służy do tego plik konfiguracyjny w formacie YAML lub JSON.

OpsWorks

OpsWorks to usługa ułatwiająca wdrożenie i zarządzanie aplikacji zbudowanej z warstw (najlepiej więcej niż 3, bo dla prostych aplikacji lepiej nadaje się Elastic Beanstalk). OpsWorks używa otwartoźródłowego narzędzia zarządzania konfiguracją Chef – pozwala to pisać własne przepisy lub korzystać z przepisów społeczności. Poszczególne przepisy można podpiąć pod określone zdarzenia cyklu życia aplikacji:

  • Setup – po rozruchu instancji,
  • Configure – gdy instancja wchodzi w stan online lub wychodzi z niego (np. tutaj możemy dodać instancję do usługi równoważenia obciążenia),
  • Deploy – podczas wdrożenia aplikacji,
  • Undeploy – podczas usuwania aplikacji,
  • Shutdown – gdy instancja jest usuwana.

OpsWorks integruje się z systemem kontroli wersji i w szczególności pozwala na wycofanie wdrożenia do poprzedniej wersji w razie potrzeby.

CloudFormation

Usługa CloudFormation pozwala programistom i administratorom tworzyć i zarządzać kolekcją powiązanych zasobów AWS na najniższym możliwym poziomie i w dowolnej skali, co przekłada się na największy poziom kontroli i elastyczności w porównaniu z usługami Elastic Beanstalk i OpsWorks. Konfigurację wszystkich zasobów opisujemy deklaratywnie w pliku JSON – usługa CloudFormation sama ustala jak i w jakiej kolejności przydzielać zasoby aby otrzymać docelowe środowisko. Warto zacząć zapoznanie się z usługą od przykładowych szablonów, które można dostosować do własnych oczekiwań.

Podejście eklektyczne

Nic nie stoi na przeszkodzie aby w celu skonfigurowania i wdrożenia aplikacji rozproszonej połączyć ze sobą różne wymienione metody, np. możemy zamodelować sieć i bazy danych za pomocą CloudFormation, a resztę pracy wykonać za pomocą Elastic Beanstalk lub OpsWorks.

Zarządzanie aplikacją i stan instancji

Wcześniej wspomniano, że instancje EC2 aplikacji rozproszonej powinny być bezstanowe, a stan aplikacji powinien być przechowywany w usługach AWS. Poznajmy kilka usług które mogą nam się tu przydać.

Ustrukturyzowane dane aplikacji

Tutaj opcje są dwie: dla relacyjnych baz danych mamy RDS, dla NoSQLowych: DynamoDB.

Nieustrukturyzowane dane aplikacji

Dane binarne (np. zdjęcia, pliki PDF) nie nadają się za bardzo do przechowywania w typowych bazach danych. Amazon oferuje tu usługę S3, która zasadniczo jest NoSQLową, automatycznie skalowaną bazą typu klucz/wartość. Po odpowiednim skonfigurowaniu dane przechowywane w S3 mogą być udostępniane użytkownikom zewnętrznym za pomocą protokołu HTTP(S) bezpośrednio z serwerów S3, z pominięciem serwerów aplikacji.

Dane sesji użytkownika

Stan sesji (np. koszyk zakupowy użytkownika) powinien być dostępny nawet jeśli kolejne żądania HTTP z przeglądarki użytkownika w wyniku równoważenia obciążenia trafiają do różnych serwerów WWW a same serwery WWW są ubijane np. w reakcji na zmniejszający się ruch sieciowy. Usługa ElastiCache to bardzo szybka baza danych przechowująca rekordy w pamięci, opakowująca jedno z dwóch znanych w świecie opensource baz: Memcached albo Redis. W przypadku Redisa ElastiCache obsługuje replikację master/slave i redundancję Multi-AZ. W razie potrzeby bardziej trwałego magazynu, warto użyć DynamoDB (replikuje swoje dane w co najmniej trzech centrach danych).

Metryki systemu

Gdy w skład aplikacji rozproszonej wchodzi wiele instancji EC2 które często pojawiają się i znikają, nie wystarczy zaSSH-ować się na wybrane maszyny by ocenić stan aplikacji – konieczny staje się niezależny system monitorowania zbierający dane ze wszystkich instancji i pozwalający je sensownie analizować.

Usługa CloudWatch pozwala w sposób trwały magazynować dane dotyczące stanu aplikacji spływające z instancji. Można tu ustawić alarmy reagujące na incydenty powiadomieniem administratorów lub zainicjowaniem akcji mających poprawić stan aplikacji (np. w reakcji na zwiększony ruch sieciowy można podjąć decyzję o zwiększeniu liczby instancji serwerów WWW). CloudWatch może monitorować zachowanie wielu usług AWS, ale samo z siebie nie widzi wielu metryk dostępnych w obrębie systemu operacyjnego instancji, np. statystyki użycia pamięci czy systemu plików. Aplikacje mogą jednak definiować własne metryki, które w szczególności będą przekazywać tego typu dane.

Logi

Te same powody które uzasadniają istnienie zewnętrznej platformy monitorującej stan aplikacji, dotyczą również zbierania logów – zarówno samej aplikacji jak i niższych warstw oprogramowania (serwery WWW, system operacyjny). Usługa CloudWatch Logs składuje logi w S3 i udostępnia oprogramowanie agenta, które trzeba zainstalować na instancjach EC2. Podobnie jak w przypadku metryk systemowych, CloudWatch Logs może na bieżąco w zautomatyzowany sposób przeglądać logi i reagować po wykryciu zdefiniowanych wzorców.

Literatura

Managing Your AWS Infrastructure at Scale, B.Chavis, T.Jones, 2015.

Share and Enjoy:
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Śledzik
  • Blip
  • Blogger.com
  • Gadu-Gadu Live
  • LinkedIn
  • MySpace
  • Wykop

Zostaw komentarz

XHTML: Możesz użyć następujących tagów: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>