Am participat, la sfârșitul lui noiembrie 2018, la Amazon AWS re:Invent. Eveniment de anvergură desfășurat în Las Vegas unde, timp de o săptămână, s-au aflat mai mult de 50,000 participanți pentru a învăța, a socializa și pentru a participa la sute de sesiuni tehnice. Energia și amploarea celui mai mare eveniment de cloud din lume sunt greu de descris. Ce am aflat acolo despre cele mai importante inovații pentru dezvoltatorii de software? Veți citi în cele ce urmează. Plus câteva detalii tehnice despre funcții și nivele AWS Lambda.
Prezența angajaților Micro Focus la Amazon AWS re:Invent 2018 nu e întâmplătoare. Micro Focus oferă produse pentru gestionarea sistemelor de cloud hibride, pentru Securitate, Big Data sau DevOps, pe care le dezvoltăm, în mare parte, și în centrul R&D din Cluj-Napoca. Colaborăm cu Amazon AWS încă din 2010, iar pentru această ediție, compania noastră a fost Sponsor de Argint.
S-au anunțat mai mult de 100 de funcționalități! Dintre acestea, am selectat câteva pe care le considerăm importante pentru dezvoltatorii români de software:
Pentru a răspunde provocărilor din lumea Java, Amazon are acum o distribuție de Java OpenJDK gratuită, multiplatformă, pregătită pentru producție.
AWS are de ceva timp conectori pentru Eclipse. Începând cu re:Invent 2018, AWS oferă posibilitatea de a dezvolta, a testa și a promova în cloud aplicațiile serverless, folosind mediile de dezvoltare oferite de JetBrains sau Microsoft prin intermediul unui set de instrumente.
Reprezintă o rescriere a versiunii 1.x de SDK AWS cu adăugarea de funcționalități precum posibilitatea utilizării bibliotecilor HTTP definite de utilizator (înainte doar Apache Http Client era suportat), execuția operațiilor I/O non-blocante folosind biblioteca Netty, și paginarea automată a răspunsurilor returnate.
Permit dezvoltatorilor să gestioneze pachete de software și date comune între mai multe funcții Lambda. Codul sursă comun poate fi acum organizat în nivele care pot fi gestionate independent. De asemenea, funcțiile au acum posibilitatea de a depinde de 1-5 astfel de nivele.
Dacă utilizatorii au avut posibilitatea să dezvolte funcții AWS Lambda doar în C#, Go, Java, NodeJS sau Python, acum ei pot utiliza și Ruby. Mai mult, dezvoltatorii software pot să scrie funcții în limbajul de programare preferat. Aceasta deschide noi oportunități pentru comunitățile de programatori precum C++, Cobol, Elixir sau Erlang, pentru a adopta Lambda în proiectele lor.
Cu siguranță că anunțurile de mai sus sunt interesante, dar cum schimbă Amazon AWS lumea?
Dacă citiți acest articol de pe un laptop sau un dispozitiv mobil, aplicația pe care o folosiți pentru a citi a fost probabil dezvoltată, împachetată și livrată folosind tehnologii și procese din decada anterioară. Are un back end, un front end împachetate împreună. Ați descărcat acest pachet, l-ați instalat și… iată! Aveți acum o aplicație pe care o puteți folosi, să citiți Today Software Magazine.
Cu arhitecturile și aplicațiile serverless AWS, experiența utilizatorilor descrisă mai sus se va schimba. De exemplu, partea de back end va rula direct în cloud, sub formă de aplicație serverless, pachetele pentru instalare vor dispărea sau vor conține doar partea de front end și veți putea accesa aplicația pentru citirea acestei reviste doar deschizând un navigator Internet generic.
Serviciul AWS Lambda este unul dintre serviciile AWS serverless. Acest serviciu vă permite încărcarea și rularea codului sursă în cloud. Practic, trebuie doar să scrieți codul sursă și, în loc să-l rulați într-un server dintr-un centru de date local, rulați acest cod în AWS Cloud sub formă de funcții Lambda. Ce înseamnă aceasta pentru testarea aplicațiilor pe mai multe sisteme de operare cum ar fi Microsoft Windows și Linux ? Înseamnă reducerea semnificativă a costurilor de achiziționare de hardware, software dar și simplificarea vieții, în general.
Înainte de re:Invent 2018, capabilitățile de gestionare a codului sursă comun între mai multe funcții erau limitate. De exemplu, dacă mai multe funcții utilizau aceeași bibliotecă Jackson pentru manipularea datelor în format JSON, fiecare pachet conținea câte o copie a bibliotecii. Odată cu lansarea nivelelor, dezvoltatorii pot acum gestiona aceste biblioteci comune mult mai ușor. Practic, se definește un nivel care conține biblioteca Jackson și se definesc dependențe între funcții și acest nivel. În continuarea acestui articol, am folosit utilitare și tehnologii din ecosistemul Java, pentru a experimenta aceste aspecte. Pentru a începe dezvoltarea funcțiilor Lambda în Java și în mediul de dezvoltare IntelliJ sunt câteva cerințe inițiale precum AWS Serverless Application Model (AWS SAM).
AWS Serverless Application Model (AWS SAM) este un proiect open-source pe care îl puteți folosi pentru a dezvolta aplicații serverless pentru AWS. O aplicație serverless în contextul AWS este o combinație de funcții, nivele Lambda precum și alte resurse care sunt necesare pentru a rezolva cazuri specifice de utilizare. Este important de observat faptul că o aplicație serverless conține mai mult decât funcții și poate conține resurse precum definiții de API, baze de date sau evenimente sursă.
Una dintre componentele AWS SAM este AWS SAM CLI. Folosind utilitarul SAM CLI, puteți să generați proiecte cadru, să rulați funcții local, să împachetați și să încărcați în cloud aplicațiile serverless și așa mai departe.
Pentru a instala SAM CLI trebuie să aveți pre-instalate: utilitarul AWS CLI, Docker, Python (dacă folosiți pip) și mai trebuie să aveți acces la Internet, pentru a descărca pachetele disponibile pentru Linux, macOS sau Windows. SAM CLI poate fi folosit independent sau împreună cu IntelliJ Toolkit. Dacă plănuiți să-l folosiți independent, recomandăm cel puțin versiunea 0.8.1, pentru că în această versiune s-au adăugat și s-au fixat mai multe capabilități legate de gestionarea nivelelor Lambda. Am folosit versiunile de la 0.7.0 până la 0.10.0 pentru Windows, în timpul editării acestui articol.
O cerință inițială care ne-a atras atenția a fost Docker. SAM CLI folosește imagini și containere de tip Docker-Lambda pentru execuția funcțiilor locale. Practic, imaginile Docker-Lambda simulează aproape identic mediul de execuție a funcțiilor din AWS Cloud.
AWS Toolkit pentru IntelliJ IDEA este un conector open-source pentru mediul de dezvoltare IntelliJ IDEA. Acest conector ușurează crearea, testarea și promovarea în AWS Cloud a aplicațiilor serverless scrise în Java, Python sau alte limbaje de programare. Versiunea 1.0 al acestui conector oferă următoarele funcționalități:
Crearea unui proiect nou pentru o aplicație serverless - Permite generarea unui proiect cadru inițial pentru o aplicație serverless. Acest cadru reprezintă un bun punct de pornire cu exemple de cod sursă atât pentru funcții cât și pentru teste.
Rularea/depanarea locală a funcțiilor Lambda - Testarea locală și depanarea pas cu pas a funcțiilor Lambda prin simularea, prin SAM CLI si Docker-Lambda, a unui mediu de execuție AWS Lambda.
Navigatorul AWS - Permite vizualizarea direct din IntelliJ a funcțiilor prezente in AWS Cloud.
Execuția funcțiilor Lambda din AWS Cloud - Dezvoltatorii de software pot acum testa funcțiile Lambda din AWS Cloud direct din IntelliJ .
Pentru a instala conectorul AWS Toolkit pentru IntelliJ aveți nevoie versiunea 2018.3.1 de IntelliJ IDEA (disponibilă din decembrie, 2018) sau de o versiune ulterioară. Procesul de instalare este similar cu procesul standard de instalare a conectorilor în IntelliJ. Primul pas după instalare este configurarea conexiunii către AWS Cloud.
Fereastra de configurare a conexiunii este localizată în partea dreaptă jos a ferestrei principale IntelliJ, ceea ce noi am găsit puțin contraintuitiv. De aici, utilizatorul poate selecta dintr-o listă de regiuni, regiunea din AWS Cloud pe care o va folosi precum și detaliile de conectare. Detaliile de conectare constau în numele utilizatorului și parola necesare, în general, pentru accesul la AWS API: identificatorul cheii de acces AWS și cheia AWS secretă (AWS Access Key Id și AWS Secret Access Key).
În continuare, am dorit să investigăm funcționalitățile legate de nivele AWS Lambda, folosind AWS Toolkits pentru IntelliJ, și să răspundem la câteva întrebări:
Cum se realizează gestionarea dependențelor între funcțiile și nivelele AWS?
Cum se folosește Maven pentru împachetarea funcțiilor și nivelelor?
Pentru aceasta, am creat un proiect simplu în IntelliJ care conține două module Maven:
Un modul aws-lambda-cars-function pentru codul sursă a funcțiilor;
Figura 2 Modulele Maven și dependențele dintre acestea
Se pot folosi și alte utilitare decât Maven pentru a împacheta nivelele. Am ales acest utilitar datorită popularității sale și pentru că SAM CLI poate genera proiecte și module Maven automat rulând: sam init -runtime java sau sam init -runtime java8 Am ales să creăm manual un modul pentru nivelul Lambda. Aici am inclus câteva clase precum o clasă model Car.java:
package lrevnic.aws.lambda.model;
public class Car {
private String type;
private String color;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
Pentru a împacheta un modul care conține un nivel, recomandăm utilizarea conectorului Apache Maven Shade. Acesta oferă, printre altele, și posibilitatea împachetării claselor împreună cu dependențele lor într-un "uber-jar".
Fișierul Maven pom.xml care folosește conectorul Apache Maven Shade:
<build>
<plugins>
<!--maven-shade-plugin packages code and -->
<!--dependencies in an uber jar-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<createDependencyReducedPom>false
</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Am observat că SAM CLI generează un fișier pom.xml care folosește o versiune mai veche (3.1.1) a acestui conector, iar ultima versiune disponibilă este 3.2.1. Executând comanda mvn package am generat un fișier Java jar (aws-lambda-cars-layer-1.0.0-SNAPSHOT.jar) care conține pe lângă codul Car.java compilat și clasele din bibliotecile definite ca dependențe.
Următorul pas a fost să creăm o arhivă, pe care să o încărcăm în consola AWS. Pentru a crea o arhivă validă, care să fie recunoscută de AWS și, mai târziu, de funcțiile Lambda, documentația AWS a fost puțin neclară, dar am reușit într-un final, să creăm o arhivă care are structura de mai jos:
carLayer.zip
/java/lib/ aws-lambda-cars-layer-1.0.0-SNAPSHOT.jar
Ar fi util ca AWS să adauge o funcționalitate care verifică structura arhivelor și raportează un avertisment, dacă aceasta nu este conform cu formatul așteptat. Legat de capabilitățile consolei AWS pentru gestionarea nivelelor avem câteva observații:
Consola AWS oferă un set limitat de operații pentru gestionarea nivelelor: crearea, ștergerea, încărcarea și descărcarea unui nivel.
AWS are încorporat un mecanism pentru gestionarea versiunilor, iar utilizatorul are puțin control asupra versiunilor. Aceasta înseamnă că, de fiecare dată când o nouă arhivă este încărcată pentru un nivel, o nouă versiune se generează automat în format numeric (1,2,3 etc.). Acest comportament este similar cu gestiunea versiunilor pentru funcții. Singura diferență notabilă pe care am observat-o față de funcții este că în acest moment, sistemul de gestionare a versiunilor pentru nivele, nu suportă etichetarea versiunilor . (ex. folosirea de etichete gen PROD, DEV, $LATEST).
În Figura 5 este o reprezentare actuală a interfeței utilizator din console AWS a nivelului carLayer:
Figura 5 Consola AWS - Noua interfață utilizator pentru gestionarea nivelelor
Am implementat în continuare o funcție simplă prin crearea unei clase care implementează interfața RequestHander și definește metoda handleRequest. Obiectivul nostru, aici, a fost să luăm un text de la utilizator (ex marca unei mașini) și să-l pasăm către un obiect de tipul Car din nivelul implementat anterior.
Funcția AWS Lambda este următoarea:
package lrevnic.aws.lambda.functions;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda
.runtime.RequestHandler;
import lrevnic.aws.lambda.model.Car;
public class CarLambdaFunction implements RequestHandler<String, String?> {
private Car myCar;
public CarLambdaFunction() {
myCar = new Car();
}
public String handleRequest(String carType,
Context context) {
System.out.println("[NFS] Selected car type: "
+ carType);
myCar.setType(carType);
return context.getFunctionName();
}
}
Fișierul pom.xml (Figura 7) are dependențe către doi conectori Maven. Primul conector este AWS Lambda Core, care conține codul de bază precum RequestHandler sau Context oferite de AWS necesare implementării funcțiilor. Al doilea conector este conectorul pentru nivelul AWS.
Fișierul pom.xml pentru modulul care conține funcția Lambda:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/
XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/
POM/4.0.0 http://maven.apache.org/xsd/
maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>lrevnic</groupId>
<artifactId>aws-lambda-cars-function</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>lrevnic</groupId>
<artifactId>aws-lambda-cars-layer</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
AWS Toolkit pentru IntelliJ permite utilizatorilor depanarea funcțiilor locale și a celor localizate în AWS Cloud.
Figura 8 Depanarea funcției AWS Lambda
Prima depanare locală a funcției noastre a mers ca prin minune! Începând cu a doua depanare, am început să primim erori de compilare din cauza unor fișiere blocate de către SAM CLI. După ceva investigații, am aflat că aceasta este o problemă cunoscută pentru AWS Toolkit versiunea 1.0 și raportată aici; totuși, încă nu a fost inclusă într-o versiune oficială.
După depanare și testare, am generat un conector Maven. De această dată, structura arhivei a fost mai simplă, exact cea generată de conectorul Shade, și tot ceea ce am făcut, a fost să încărcăm arhiva (sub formă de fișier Java jar) generat în consola AWS pentru funcții. După ce am încărcat arhiva, pentru ca funcția noastră să fie recunoscută de AWS, a trebuit să specificăm în consola AWS calea către metoda handleRequest (lrevnic.aws.lambda.functions.CarLambdaFunction::handleRequest) Apoi am observat secțiunea care permite atașarea nivelelor la funcția noastră numită carFunction.
Figura 9 Noua interfața utilizator pentru funcții AWS Lambda
Fiecare funcție poate avea atașat maxim cinci nivele diferite. De asemenea, AWS specifică o limită de 250 MBs a pachetelor care conțin funcția și nivelele atașate.
Figura 10 Nivel Lambda adăugat ca și dependență
Testarea funcției în consola de AWS a fost simplă și nu am observat schimbări importante adăugate de AWS .
Acestea ar fi câteva noutăți anunțate la AWS re:Invent 2018, pentru dezvoltatorii de software, pe care le-am investigat aici: Amazon Java Correto, nivelele AWS Lambda, AWS Toolkit pentru IntelliJ și AWS Java SDK 2.0.
La Micro Focus, vom include multe dintre funcționalitățile anunțate la re:Invent în produsele noastre.
De asemenea, vom continua să experimentăm mai multe servicii AWS pe care să le prezentăm în articole viitoare din Today Software Magazine precum și la Transylvania Cloud Meetup (club de întâlniri și dezbateri regulate pe teme legate de cloud, destinat colegilor din industria locală).
Și aceasta pentru că AWS schimbă lumea și modul în care vom dezvolta software, în următoarea decadă.
de Ovidiu Mățan
de Adrian Cozac
de Ovidiu Mățan