Збираємо та налаштовуємо свій CDN

Мережі доставки контенту (CDN) використовуються на сайтах та додатках в основному для прискорення завантаження статичних елементів. Це відбувається за рахунок кешування файлів на CDN-серверах, розташованих у різних географічних регіонах. Запитавши дані через CDN, користувач отримує їх із найближчого сервера.

Принцип роботи та функціонал у всіх мереж доставки контенту приблизно однаковий. Отримавши запит на завантаження файлу, CDN сервер одноразово бере його з оригінального сервера і віддає користувачеві, водночас кешуючи у себе заданий проміжок часу. На всі наступні запити відповідь надається з кеша. У всіх CDN є опції попереднього завантаження файлів, очищення кешу, налаштування терміну його зберігання та багато іншого.

Буває, що через ті чи інші причини потрібно організувати власну мережу доставки контенту, і тоді — нехай буде в допомогу нам інструкція зі збирання чергового велосипеда.

Збираємо та налаштовуємо свій CDN
Джерело: Infographic vector created by pikisuperstar - www.freepik.com

Коли потрібний власний CDN

Розглянемо випадки, коли запуск власного CDN має сенс:

  • коли є бажання заощадити, а поточні витрати навіть за використання недорогих CDN начебто BunnyCDN становлять кілька сотень доларів на місяць
  • якщо хочемо отримати постійний кеш або кеш без сусідів по серверу та каналу
  • у потрібному вам регіоні у CDN сервісів немає точок присутності
  • потрібні особливі налаштування доставки контенту
  • хочемо прискорити доставку динамічного контенту, розмістивши ближче до користувачів продакшн сервера
  • є побоювання, що сторонній сервіс CDN може неправомірно збирати або використовувати інформацію про поведінку користувачів (привіт сервісам без GDPR-compliant) або займатися іншими неправомірними діями

Найчастіше доцільніше використовувати існуючі готові рішення.

Що потрібно для запуску

Дивно, якщо ви маєте свою автономну систему (AS). З нею можна призначити однаковий IP кільком серверам і за цією інструкцією на рівні мережі направляти користувачів до найближчого. Варто сказати, що навіть з блоком адрес /24 є можливість побудувати мережу доставки контенту. Деякі сервери-провайдери дозволяють зробити анонс для використання у всіх доступних регіонах.

Якщо ви не щасливий власник блоку IP адрес, то для запуску простого CDN вам знадобляться:

  • доменне ім'я або субдомен
  • мінімум два сервери у різних регіонах. Сервер може бути як виділений, і віртуальний
  • geoDNS інструмент. З його допомогою користувач, звернувшись до домену, буде направлено на найближчий сервер

Реєструємо домен та замовляємо сервери

З реєстрацією домену все просто – реєструємо у будь-якій зоні у будь-якого реєстратора. Також для CDN можна використовувати субдомен, наприклад щось на зразок cdn.ім'ядомена.com. Власне, у нашому прикладі ми так і вчинимо.

Що стосується замовлення серверів — їх варто орендувати в регіонах і країнах, де знаходиться ваша аудиторія користувачів. Якщо проект інтерконтинентальний, то зручно вибирати хостинг-провайдерів, які пропонують одразу сервери по всьому світу. Приклади: OVH, Leaseweb и 100Тб - для виділених серверів, Вультр и DigitalOcean - Для віртуальних хмарних *.

Для нашого приватного CDN замовимо 3 віртуальні сервери на різних континентах. У Вультр на сервері за $5/міс ми отримаємо 25GB SSD місця та 1TB трафіку. Під час встановлення виберемо останній Debian. Наші сервери:

Збираємо та налаштовуємо свій CDN Франкфурт, ip: 199.247.18.199

Збираємо та налаштовуємо свій CDN Чикаго, ip: 149.28.121.123

Збираємо та налаштовуємо свій CDN Сінгапур, ip: 157.230.240.216

* Vultr та DigitalOcean обіцяють $100 кредиту користувачам, зареєстрованим за посиланнями у статті, відразу після додавання способу оплати. Автор також від такого отримує невеликий комплімент, що для нього зараз дуже значуще. Будь ласка, поставтеся з розумінням.

Налаштовуємо geoDNS

Щоб користувач при зверненні до домену або субдомену CDN направлявся на потрібний (найближчий) сервер, нам знадобиться DNS сервер з функцією geoDNS.

Принцип та порядок роботи geoDNS наступний:

  1. Визначає IP клієнта, який надіслав DNS запит або IP рекурсивного DNS-сервера, який використовується при обробці клієнтського запиту. Такими рекурсивними серверами зазвичай є DNS провайдерів.
  2. IP клієнта дізнається його країну або регіон. Для цього використовуються бази GeoIP, яких сьогодні безліч. Є непогані безкоштовні варіанти.
  3. Залежно від розташування клієнта віддає йому IP-адресу найближчого CDN сервера.

DNS сервер з функцією geoDNS можна зібрати самостійно, але краще використовувати готові рішення з мережею DNS-серверів по всьому світу та Anycast з коробки:

  • СlouDNS від $9.95/міс, тариф GeoDNS, за замовчуванням є один DNS Failover
  • Зілоре від $25/міс, включено DNS Failover
  • Амазонський маршрут 53 від $35/міс за чистих 50м гео-запитів. DNS Failover тарифікується окремо
  • DNS стало легко від $125/міс, є 10 DNS Failover
  • Cloudflare, функція Geo Steering доступна в Enterprise тарифах

При замовленні geoDNS слід звертати увагу на кількість включених до тарифу запитів та враховувати, що реальна кількість звернень до домену може в рази перевершити очікування. Мільйони павуків, сканнерів, спамерів та іншої нечисті працюють невпинно.

Практично у всіх DNS-сервісів у вартість включено незамінну для побудови CDN послугу - DNS Failover. З її допомогою можна налаштувати моніторинг роботи своїх серверів та у разі відсутності ознак життя автоматично замінювати в DNS-відповідях адресу неробочого сервера на резервну.

Для побудови нашого CDN скористаємося CloudDNS, тариф GeoDNS.

Додамо в особистому кабінеті нову DNS-зону, вказавши свій домен. Якщо CDN будуватимемо на субдомені, а головний домен вже використовується, то відразу після додавання зони не забудьте додати існуючі робочі DNS-записи. Наступна дія – створення для CDN домену/субдомену кількох A-записів, кожна з яких буде застосовуватися для заданого нами регіону. Як регіони можна вказати континенти або країни, для США та Канади доступні субрегіони.

У нашому випадку CDN буде піднято на субдомені cdn.sayt.in. Додавши зону sayt.in, створимо для субдомену перший A-запис і направимо всю Північну Америку на сервер в Чикаго:

Збираємо та налаштовуємо свій CDN
Повторимо дію для інших регіонів, не забувши створити один запис для регіонів за промовчанням. Ось що вийде в результаті:

Збираємо та налаштовуємо свій CDN

Останній дефолтний запис на скріншоті означає, що всі незадані регіони (а це Європа, Африка, користувачі супутникового інтернету тощо) направлятимуться на сервер у Франкфурті.

На цьому базове налаштування DNS завершено. Залишилося зайти на сайт реєстратора домену і замінити поточні домени NS на ті, що видав ClouDNS. І поки NS-и оновлюватимуться ми підготуємо сервера.

Встановлення SSL сертифікатів

Наш CDN буде працювати за HTTPS, тому якщо у вас вже є SSL сертифікати для домену або субдомену, завантажте їх на всі сервери, наприклад в директорію /etc/ssl/вашдомен/

Якщо немає сертифікатів, можна отримати безкоштовний від Let's Encrypt. Для цього чудово підійде ACME Shell script. Клієнт зручний та простий у налаштуванні, а головне – дозволяє проводити валідацію домену/субдомену за DNS через API від ClouDNS.

Ми поставимо acme.sh тільки на одному із серверів - європейському 199.247.18.199, з нього сертифікати копіюватимуться на всі інші. Для встановлення виконаємо:

root@cdn:~# wget -O - https://get.acme.sh | bash; source ~/.bashrc

Під час встановлення скрипту буде створено CRON завдання для подальшого оновлення сертифікатів без нашої участі.

Перевірка домену під час видачі сертифіката буде проводитися за DNS з використанням API, тому в особистому кабінеті ClouDNS у меню Reseller API потрібно створити нового API користувача та задати пароль. Отриманий auth-id з паролем пропишемо у файлі ~/.acme.sh/dnsapi/dns_cloudns.sh (Не плутати з файлом dns_clouddns.sh). Ось рядки, які потрібно розкоментувати та відредагувати:

CLOUDNS_AUTH_ID=<auth-id>
CLOUDNS_AUTH_PASSWORD="<пароль>"

Тепер запитаємо отримання SSL сертифіката для cdn.sayt.in

root@cdn:~# acme.sh --issue --dns dns_cloudns -d cdn.sayt.in --reloadcmd "service nginx reload"

У параметрах на майбутнє ми вказали команду для автоматичного перезавантаження конфігурації веб-сервера після кожного оновлення терміну дії сертифіката надалі.

Весь процес отримання сертифіката може тривати до 2 хвилин, не переривайте його. Якщо виникне помилка валідації домену, спробуйте ще раз запустити команду. Наприкінці ми побачимо, куди були завантажені сертифікати:

Збираємо та налаштовуємо свій CDN

Запам'ятаймо ці шляхи, їх потрібно буде вказати при копіюванні сертифіката на інші сервери, а також у налаштуваннях веб-сервера. На помилку перезавантаження конфігів Nginx не звертаємо уваги - на повністю налаштованому сервері при оновленні сертифікатів її не буде.

Все, що нам залишилося за SSL, - це скопіювати отриманий сертифікат на два інші сервери зі збереженням шляху до файлів. Створимо на кожному з них такі ж директорії та зробимо копію:

root@cdn:~# mkdir -p /root/.acme.sh/cdn.sayt.in/
root@cdn:~# scp -r [email protected]:/root/.acme.sh/cdn.sayt.in/* /root/.acme.sh/cdn.sayt.in/

Щоб оновлення сертифікатів було регулярним створимо на обох серверах щоденне CRON завдання з командою:

scp -r [email protected]:/root/.acme.sh/cdn.sayt.in/* /root/.acme.sh/cdn.sayt.in/ && service nginx reload

При цьому доступ до віддаленого сервера-джерела повинен бути налаштований за ключом, тобто. без введення пароля. Не забудьте це зробити.

Встановлення та налаштування Nginx

Для віддачі статичного контенту ми будемо використовувати Nginx, налаштований у режимі кешируючого proxy-сервера. Обновимо списки пакетів та встановимо його на всіх трьох серверах:

root@cdn:~# apt update
root@cdn:~# apt install nginx

Замість дефолтного використовуємо конфіг із спойлера нижче:
nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 4096;
    multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    types_hash_max_size 2048;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log off;
    error_log /var/log/nginx/error.log;

    gzip on;
    gzip_disable "msie6";
    gzip_comp_level 6;
    gzip_proxied any;
    gzip_vary on;
    gzip_types text/plain application/javascript text/javascript text/css application/json application/xml text/xml application/rss+xml;
    gunzip on;            

    proxy_temp_path    /var/cache/tmp;
    proxy_cache_path   /var/cache/cdn levels=1:2 keys_zone=cdn:64m max_size=20g inactive=7d;
    proxy_cache_bypass $http_x_update;

server {
  listen 443 ssl;
  server_name cdn.sayt.in;

  ssl_certificate /root/.acme.sh/cdn.sayt.in/cdn.sayt.in.cer;
  ssl_certificate_key /root/.acme.sh/cdn.sayt.in/cdn.sayt.in.key;

  location / {
    proxy_cache cdn;
    proxy_cache_key $uri$is_args$args;
    proxy_cache_valid 90d;
    proxy_pass https://sayt.in;
    }
  }
}

У конфізі відредагуємо:

  • Максимальна кількість — розмір кешу, який не перевищує доступне на диску місце
  • неактивний час зберігання закешованих даних, до яких ніхто не звертався
  • ssl_certificate и ssl_certificate_key — шляхи до файлів SSL сертифіката та ключа
  • proxy_cache_valid - Час зберігання закешованих даних
  • proxy_pass — адреса оригінального сервера, з якого CDN запитуватиме файли для кешування. У нашому прикладі це sayt.in

Як бачимо все просто. Складність лише може виникнути у налаштуванні часу кешування через схожість директив неактивний и proxy_cache_valid. Розберемо їх у нашому прикладі. Ось що відбувається при inactive=7d и proxy_cache_valid 90d:

  • якщо запит не повториться протягом 7 днів, дані видаляться з кеша після закінчення цього періоду
  • якщо запит буде повторюватися хоча б раз на 7 днів, то дані в кеші будуть вважатися застарілими через 90 днів і при черговому запиті Nginx оновить їх, взявши з оригінального сервера

Закінчивши правити nginx.conf, перезавантажимо конфігурацію:

root@cdn:~# service nginx reload

Наш CDN повністю готовий. За $15/міс. ми отримали точки присутності на трьох континентах та 3 Тб трафіку: по 1 Тб у кожній локації.

Перевіряємо роботу CDN

Подивимося на пінги до нашого CDN із різних географічних локацій. Для цього підійдуть будь-які пінг-сервіси.

Точка запуску
хост
IP
Avg time, мсек

Німеччина Берлін
cdn.sayt.in
199.247.18.199
9.6

Нідерланди, Амстердам
cdn.sayt.in
199.247.18.199
10.1

Франція Париж
cdn.sayt.in
199.247.18.199
16.3

Великобританія, Лондон
cdn.sayt.in
199.247.18.199
14.9

Канада, Торонто
cdn.sayt.in
149.28.121.123
16.2

США, Сан-Франциско
cdn.sayt.in
149.28.121.123
52.7

США, Даллас
cdn.sayt.in
149.28.121.123
23.1

США, Чикаго
cdn.sayt.in
149.28.121.123
2.6

США, Нью-Йорк
cdn.sayt.in
149.28.121.123
19.8

Сінгапур
cdn.sayt.in
157.230.240.216
1.7

Японія, Токіо
cdn.sayt.in
157.230.240.216
74.8

Австралія, Сідней
cdn.sayt.in
157.230.240.216
95.9

Результати добрі. Розмістимо тепер докорінно основного сайту тестову картинку test.jpg та перевіримо швидкість її завантаження через CDN. Сказано, - зроблено. Контент віддається швидко.

Напишемо невеликий скрипт на випадок, якщо захочемо на CDN-точці очистити кеш.
purge.sh

#!/bin/bash
if [ -z "$1" ]
then
    echo "Purging all cache"
    rm -rf /var/cache/cdn/*
else
    echo "Purging $1"
    FILE=`echo -n "$1" | md5sum | awk '{print $1}'`
    FULLPATH=/var/cache/cdn/${FILE:31:1}/${FILE:29:2}/${FILE}
    rm -f "${FULLPATH}"
fi

Для видалення всього кешу досить просто запустити його, окремий файл можна почистити так:

root@cdn:~# ./purge.sh /test.jpg

замість висновків

Насамкінець хочу дати кілька корисних порад, щоб одразу переступити через граблі, які свого часу зробили хвору голову мені:

  • Для підвищення відмовостійкості CDN рекомендується налаштувати DNS Failover, який допоможе швидко змінити A запис у разі поломки сервера. Це робиться на панелі керування DNS записами домену
  • Сайти з широким географічним охопленням, без сумніву, вимагають великої кількості точок CDN, але давайте без фанатизму. Швидше за все, користувач не помітить суттєвої різниці в порівнянні з платним CDN, якщо ви розмістите сервера в 6-7 місцях: Європа, Північна Америка (схід), Північна Америка (захід), Сінгапур, Австралія, Гонконг або Японія.
  • Іноді хостери не дозволяють використовувати орендовані сервери для цілей CDN. Тому, якщо ви раптом вирішите розгорнути мережу доставки контенту як сервіс, не забудьте прочитати правила конкретного хостинг-провайдера
  • Вивчіть карту підводних комунікацій, щоб уявляти, як пов'язані континенти та враховувати це при побудові мережі доставки контенту
  • Спробуйте перевірити пінги з різних місць до ваших серверів. Так можна побачити найближчі до CDN-точок регіони та правильніше налаштувати GeoDNS
  • Залежно від завдань не зайвим буде доналаштувати Nginx під конкретні вимоги кешування та з урахуванням навантаження на сервер. У цьому мені дуже допомогли статті про кеш Nginx. тут та прискорення роботи при великих навантаженнях: тут и тут

Джерело: habr.com