AWS - dostarczanie treści za pomocą CloudFront06.VII.2017

Spis treści

  1. Czym jest CloudFront
  2. Przygotowanie do konfiguracji CloudFront
  3. Przygotowanie S3
  4. Konfiguracja CloudFront
  5. Test treści dynamicznych
  6. Treści statyczne serwowane z S3
  7. Problemy z komunikacją
  8. Pliki logów

Czym jest CloudFront

AWS CloudFront wygląda jak dość rozbudowany CDN (Content Delivery Network). Pozwala nie tylko na dostarczanie treści statycznych najbliżej, pod względem położenia na kuli ziemskiej, użytkownika (czyli to co potrafi standardowy CDN) ale również można w niego niejako wpleść treści dostarczane dynamicznie.

Wszystkie treści pobierane są zawsze z serwera źródłowego (origin server) i na podstawie ustawień w nagłówkach 'Cache-Control' w odpowiedzi od serwera, którą uzyska CloudFront, przechowywane są przez wskazany czas w lokalizacjach brzegowych. Zatem dla poniższych ustawień CloudFront zachowa się:

Więcej informacji na temat nagłówka Cache-Control znajduje się w dokumentacji MDN: Cache-Control.

Przygotowanie do konfiguracji CloudFront

Stawiamy serwer WWW np. na EC2 (instrukcja w AWS:Hello EC2 lub dowolny inny). Do tego przykładu posłuży pusty serwer na Ubuntu z NodeJs na pokładzie. Po zalogowaniu do serwera uruchamiamy plik server.js z poniższą zawartością. Wszystkie wyniki jego działania będą przedstawiane na konsoli.

// \> nodejs server.js 80
//
var http = require('http');

var app = http.createServer(function(req,res) {

    // zeby Chrome ciagle nie pytal
    if ('/favicon.ico' === req.url) {
        res.statusCode = 404;
        res.end();
        return;
    }

    if ('/' === req.url || '/initgo' === req.url) {
        // dane prywatne bez buforowania
        res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
        // dane statyczne-publiczne
        //res.setHeader('Cache-Control', 'public, max-age=60');
    }

    var now = (new Date()).toISOString();
    console.log(`${now} >>`, `url:${req.url}`);

    res.statusCode = 200;
    res.end('Teraz mamy: ' + now);
    // Teraz mamy: 2017-07-06T17:36:01.640Z
});

app.listen(process.argv[2] || 1337);

Przygotowanie S3

W AWS S3 tworzymy nowy pojemnik (jeśli do tej pory nie istniał) jakasnazwa.s3.amazonaws.com a w nim poniższą strukturę katalogów.

Klikamy prawym na katalog cf-static/ i wybieramy opcję Make public tak aby wszystkie elementy w tym katalogu były dostępne publicznie. Inaczej CloudFront nie będzie ich w stanie przekazać użytkownikowi końcowemu.

Jeśli w metadanych pliku pol.png ustawimy klucz Cache-Control to zostanie on wybrany zamiast ustawienia domyślnego w Default TTL.

Konfiguracja CloudFront

Aby usługa CloudFront przekazywała serwerowi informację o państwie z którego pochodzi żądanie należy wskazać aby do zapytań był dołączany nagłówek CloudFront-Viewer-Country.

Test treści dynamicznych

Wyniki dla wejścia na stronę http://cf.pieszynski.com/ z adresów w Polsce i USA.

Ścieżka widziana przez serwer - /initgo - wynika z ustawienia domyślnego Default Root Object. Docelowo pewnie znalazłby się tam wpis index.html.

ubuntu@ip:~$ nodejs server.js
2017-07-06T17:26:44.680Z >> url:/initgo, headers: {
  'user-agent': 'Amazon CloudFront',
  'x-forwarded-for': 'xxx.PL.IP.xxx',
  'cloudfront-viewer-country': 'PL',
  'x-pp-front': 'EC2_v1'
  }
2017-07-06T17:27:37.736Z >> url:/initgo, headers: {
  'user-agent': 'Amazon CloudFront',
  'x-forwarded-for': 'yyy.US.IP.yyy',
  'cloudfront-viewer-country': 'US',
  'x-pp-front': 'EC2_v1' 
  }

Za każdym razem nagłówek X-Cache ma wartość Miss from cloudfront czyli zawartość musiała być odświeżona z serwera źródłowego a na konsoli serwera WWW pojawiają się wpisy dla każdego wywołania.

HTTP/1.1 200 OK
Content-Length: 36
Connection: keep-alive
Cache-Control: no-cache, no-store, must-revalidate
X-Cache: Miss from cloudfront
Via: 1.1 zzz.cloudfront.net (CloudFront)

Treści statyczne serwowane z S3

W tym przypadku należy zwrócić uwagę, że po skonfigurowaniu Path Pattern na sta/* CloudFront będzie używał podkatalogu cf-static/ z wskazanego pojemnika dodając do niego CAŁĄ ścieżkę z adresu URL. Czyli dla adresu http://cf.pieszynski.com/sta/pol2.png plik musi znajdować się w katalogu bezwzględnym w S3 cf-static/sta/pol2.png a nie cf-static/pol2.png!

Wyniki dla wejścia na stronę http://cf.pieszynski.com/sta/pol2.png.

HTTP/1.1 200 OK
Content-Type: image/png
ETag: "e0012d..."
Server: AmazonS3
X-Cache: Miss from cloudfront

HTTP/1.1 304 Not Modified
ETag: "e0012d..."
Server: AmazonS3
Age: 59
X-Cache: Hit from cloudfront

HTTP/1.1 304 Not Modified
ETag: "e0012d..."
Server: AmazonS3
X-Cache: RefreshHit from cloudfront

Problemy z komunikacją

Gdy CloudFront dostarcza dane z serwera WWW a ten w pewnym momencie przestanie odpowiadać to CloudFront serwuje dane z bufora przez kolejne pięć minut nie odpytując w tym czasie ani razu serwera WWW (niezależnie od tego co było ustawione w Cache-Control). Więcej informacji na ten temat w dokumentacji: How CloudFront Processes and Caches HTTP 4xx and 5xx Status Codes from Your Origin

Pliki logów

#Version: 1.0
#Fields: date time x-edge-location sc-bytes c-ip cs-method cs(Host) cs-uri-stem sc-status cs(Referer) cs(User-Agent) cs-uri-query cs(Cookie) x-edge-result-type x-edge-request-id x-host-header cs-protocol cs-bytes time-taken x-forwarded-for ssl-protocol ssl-cipher x-edge-response-result-type cs-protocol-version
2017-07-06  17:35:55    WAW50   361 xxx.xxx.xxx.xxx GET dxxxxxxx.cloudfront.net /   200 -   Mozilla/    -   -   Miss    ==  cf.pieszynski.com   http    407 0.088   -   -   -   Miss    HTTP/1.1
2017-07-06  17:35:59    WAW50   361 xxx.xxx.xxx.xxx GET dxxxxxxx.cloudfront.net /   200 -   Mozilla/    -   -   Miss    ==  cf.pieszynski.com   http    433 0.053   -   -   -   Miss    HTTP/1.1
2017-07-06  17:36:01    WAW50   361 xxx.xxx.xxx.xxx GET dxxxxxxx.cloudfront.net /   200 -   Mozilla/    -   -   Miss    ==  cf.pieszynski.com   http    433 0.114   -   -   -   Miss    HTTP/1.1