Marek Gach21.3.2018Zpět

Upload a ořez obrázků: Část 2. - AWS backend

Kolega Lukáš popsal v článku Upload a ořez obrázků s ReactJS: Část 1. - Klient jak se pomocí React/Redux obslouží upload a ořez obrázků. Tento článek se zabývá pohledem ze strany backendu. Implementovali jsme řešení, využívající Amazon Web Services.

Amazon je jeden z hlavních hráčů na poli cloud computing služeb, spolu s Microsoft Azure a Google Cloud. Velmi pěkné srovnání dalších, alternativních providerů najdete v článku na clutch.co. Amazon nabízí značně široké portfolio služeb od zpracování videa a big data až po VPS. Běží na něm různě složité architektury od jednoduchých projektů po kompozice se stovkami virtuálních strojů. S AWS tedy velikost projektu není rozhodující faktor. V Kurzoru používáme AWS zejména tam, kde od počátku víme o požadavku na vysokou škálovatelnost a dostupnost projektu kvůli rostoucímu trafficu.

Pro účely uploadu a ořezu použijeme 3 základní služby v rámci AWS. S3 - Simple Storage Service pro ukládání souborů na server. Dále, API Gateway pro vytvoření funkčního REST API. A v neposlední řadě, Lambda functions napsané v node.js pro samotnou aplikační logiku.

Naše architektura v AWS: Jak to funguje?

Na obrázku níže je celý proces popsán, včetně propojení jednotlivých částí.

 

AWS Structure
Obrázek: Jak jsou spolu jednotlivé části AWS propojeny.

Nyní se podívejme detailně na jednotlivé části.

Jak vytvořit a nastavit S3

Začneme vytvořením nového bucketu v S3, určeného pro uploadované soubory. Vše co potřebujete je nastavit policy document, který spravuje práva přístupu do S3. Nejsnazší cestou pro naše účely je povolit komukoliv čtení souborů (protože jsou určené k veřejnému zobrazení na webu), ale k samotnému zápisu (uploadu) je třeba mít odkaz na požadovaný soubor.

Více najdete v jednoduchém tutorialu přímo od Amazonu.

S3 Setup
Obrázek: Nastavení S3

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "PublicReadGetObject",
			"Effect": "Allow",
			"Principal": "*",
			"Action": "s3:GetObject",
			"Resource": "arn:aws:s3:::kurzor.article.example/*"
		}
	]
}

TIP: Bylo by samozřejmě lepší pro bezpečnost vytvořit unikátní adresář pro každého uživatele v bucketu, k čemuž by se oprávnili přes rozhraní Identity Access Management (IAM). Každý uživatel by se pak autentizoval přes svoje přihlašovací údaje a to by mu povolilo přístup k jeho obrázkům. Samozřejmě jde o řešení časově složitější.

ApiGateway

ApiGateway slouží k vytvoření REST API které pak volá jednotlivé Lambda funkce. Nastavení API se zadává formou jednoduchého rozhraní:

ApiGateway settings
Obrázek: Příklad definice endpointu pro POST požadavek

Opět bych vás rád nasměroval na dokumentaci, která byla pečlivě připravena ze strany Amazonu.

TIP: Buďte opatrní s CORS – ApiGateway umožňuje velmi detailně ladit HTTP hlavičky vašich odpovědí. Čili, víte-li že budete mít API na jiné doméně, než je front-end, nezapomeňte v předstihu nastavit hlavičky Access-Control-Allow-Origin.

Ořez s využitím Lambda funkcí

Samotný ořez je řešen přes Lambda funkci. Jde o výpočetní platformu v rámci AWS, kde se vám účtuje čas vykonávání kódu. Funkce můžete psát v Node.js, Pythonu, Javě, .NET, Go nebo C#. My volíme pro node.js pro jeho příbuznost s front-end Javascriptem.

Pro detailní náhled do světa Lambda funkcí vás odkážeme na dokumentaci, která je opět k dispozici od Amazonu.

Pro samotný ořez pak použijeme knihovnu gm - GraphicsMagick for node.js . gm obsahuje efektivní sadu nástrojů a knihoven pro práci s více než 88 obrazovými formáty (GIF, JPEG, JPEG-2000, PNG, PDF, PNM, TIFF, ...).

Advanced Settings
Obrázek: Nastavení memory limit a timeoutu Lambda funkce. Tímto definujete pro Lambda funkce omezující podmínky.

Samotné Lambda funkce

Pojďme tedy kódovat. Konečně! 

Níže jsou části naší implementace zpracovávatelské Lambda funkce. Nezobrazujeme kompletní kód, protože naše řešení bylo napsáno na míru konkrétnímu projektu. Doporučujeme vám postupovat podobně: rozběhat minimální funkcionalitu na bázi našich funkcí níže, a pak ji upravit s ohledem na váš projekt.

Stažení obrázku z S3

(Pozn.: upload obrázku na S3 se řeší v rámci knihovny AWS na front-end části samostatným requestem, viz první díl).

Následující funkce stáhne obrázek z S3:

function getFileFromS3 (bucket, key, callback ) {
    s3.getObject({
        Bucket: bucket,
        Key: key
    }, function (err, data) {
        if(err) {
            // ošetření chyby
            callback (false);
        } else {
            callback (data);
        }
    });
}

Parametry:

  • bucket - název S3 bucketu ze kterého stahujeme
  • key - název obrázku
  • callback - "pokračující" funkce

Ořez

Zde pracujeme s crop parametry - tedy počátečními souřadnicemi, výškou a šířkou oblasti, kterou chceme oříznout, v daném obrázku. Zajímavé je, že v knihovně gm lze dokonce oříznout i animovaný GIF (vyzkoušeno).

function (context, image, width, height, x, y, callback)
    gm(image)
        .crop(width, height, x, y);
        .toBuffer(format,function (err, buffer) {
            if (err){
                callback (false);
            } else {
                callback (buffer);
            }
        });
}

Parametry:

  • image - vstupní obrázek
  • width, height - šířka a výška ořezového rozměru
  • x, y - souřadnice počátečního bodu ořezu
  • callback - "pokračující" funkce po dokončení ořezu

Uložení obrázku zpět do S3

Následující funkce uloží obrázek zpět do S3. Řízení přístupu přes ACL je nastaveno jako public (jakmile je URL konkrétního souboru známa, je dostupný komukoliv).

function putObject (bucket, buffer, ext) {
    var key = 'test.jpg'; // vytvoření unikátního názvu
    s3.putObject ({
        ACL: 'public-read',
        Bucket: bucket,
        Key: key,
        Body: buffer
    }, function(err, data) {
        // ošetření chyby
    });
}

Celý proces ilustrovaně

Full Illustration
Obrázek: Celý proces ilustrovaně

Ošetření chyb

Lambda funkce a odvozeně také API Gateway by měly být schopné plně vyřešit jakýkoliv chybový stav, který při zpracování nastane. Příklady:

  • Download obrázku z S3 selže,
  • Lambda funkci dojde paměť kvůli velikosti obrázku,

  • Uploadovaný obrázek je poškozený nebo v neznámém formátu.

V API Gateway, jak už bylo zmíněno v předchozí kapitole, je již nastaven REST endpoint /crop pro metodu POST. Data, která Lambda funkce využije, jsou součástí requestu.

Odpověď na toto volání je v přesně definovaném formátu (v našem případě JSON), a obsahuje plnou URL odkazující na finální obrázek v S3 bucketu. V takovém případě je HTTP kód odpovědi 200. Jiné případy, nejčastěji pak chyby, vrací HTTP 5xx. Pokud je nutné verifikovat uživatelskou identitu pro Lambda funkci (uživatel musí být zalogován v aplikaci), API Gateway musí mít patřičně upravené nastavení, a v takovém případě se chyba ověření vrací jako HTTP 401 nebo 403.

Závěrem

Doufáme že tento náhled do našeho řešení vám pomůže pochopit, jak nastavit jednoduchou službu na bázi AWS a jak se dostanete od HTTP requestu až k samotné implementaci logiky.

Samozřejmě, budeme rádi když do řešení vnesete svoje vylepšení a nové podněty. Například, nahradit současný způsob řetězení funkcí pomocí parametru callback modelem Promises. Necháme to na vás a vašem experimentování!

Marek Gach
gach@kurzor.net
+420 725 475 981
Marek má v Kurzoru hlavní slovo ve vývoji.

Seriál: Upload a ořez obrázků - React/AWS

Upload a ořez obrázků: Část 1. - Klient v Reactu

Hlavní důvod vzniku článku je dát vám jednoduchou kuchařku k tomu, jak upravovat obrázky v ReactJS - a ušetřit váš čas při vyhledávání na Google / Stack Overflow.

Lukáš Hudec24.3.2017