Featured image of post Как устроен этот сайт

Как устроен этот сайт

От git push до страницы в браузере, и почему хостинг на Яндекс Облаке обходится в ноль рублей

Небольшая статья о том как устроен этот блог под капотом. Есть приватный git-репозиторий с текстовыми файлами и бакет в Яндекс облаке. Сайт статический, то есть каждая страница лежит в хранилище готовым HTML-файлом, и когда читатель её открывает, хранилище просто отдаёт то, что там уже есть.

Собирает страницы Hugo, генератор статических сайтов на Go.

Что происходит по шагам

Шаг 1. Я пишу статью. Создаю папку в content/post, кладу туда index.md и картинки.

Шаг 2. Смотрю, что получилось. Команда hugo server -D поднимает копию сайта на localhost с горячей перезагрузкой.

Шаг 3. Делаю коммит и пуш в main. На этом моё ручное участие заканчивается.

Шаг 4. GitHub Actions поднимает чистую виртуалку и выкачивает на неё репозиторий вместе с темой.

Шаг 5. Ставится Hugo и собирается сайт. Команда hugo --minify превращает markdown в HTML и по дороге сжимает разметку, результат складывается в папку public.

Шаг 6. Результат синхронизируется с бакетом. Заливаются только изменившиеся файлы, а флаг --delete подчищает в хранилище то, чего больше нет в сборке, иначе удалённая статья продолжала бы открываться по старому адресу.

Шаг 7. Статья размещена на сайте.

Пайплайн

Всё описано в одном файле .github/workflows/deploy.yaml, триггером служит любой пуш в ветку main:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
name: Deploy
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive
          fetch-depth: 0
      - uses: peaceiris/actions-hugo@v3
        with:
          hugo-version: 'latest'
          extended: true
      - run: hugo --minify
      - env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_DEFAULT_REGION: ru-central1
        run: |
          aws s3 sync ./public s3://iplotnikov.com \
            --endpoint-url=https://storage.yandexcloud.net --delete

Прогон пайплайна в GitHub Actions

Весь прогон занимает около десяти секунд, ключи доступа лежат в секретах GitHub и принадлежат в Яндекс облаке сервисному аккаунту с ролью storage.editor, который умеет только читать и писать объекты в этом хранилище и больше ничего, так что при утечке ключа ущерб ограничен содержимым одного бакета.

Домен и сертификат

Доменом управляет Yandex Cloud DNS, то есть зона iplotnikov.com целиком живёт в облаке и обслуживается серверами ns1.yandexcloud.net и ns2.yandexcloud.net.

HTTPS обеспечивает сертификат от Let’s Encrypt, выпущенный через Yandex Certificate Manager и привязанный к бакету. Сертификаты Let’s Encrypt живут 90 дней, Certificate Manager запрашивает обновление за 30 дней до истечения и раскатывает новую версию на все привязанные ресурсы.

Из чего складывается счёт

В Object Storage никакой абонентской платы за сам факт существования бакета нет, счётчик крутится только тогда, когда данные лежат или их кто-то читает. Хранение считается пропорционально времени, вплоть до часов и мегабайт, операции делятся на типы по методам S3 API (загрузка объекта PUT, скачивание GET, получение метаданных HEAD), и оплачивается фактическое их количество, а удаление объектов не тарифицируется вообще. Входящий трафик тоже бесплатен, так что деплой ничего не стоит сам по себе.

Поверх этого работает бесплатный лимит, не тарифицируются первый гигабайт хранения, первые десять тысяч операций записи и сто тысяч операций чтения, а также первые сто гигабайт исходящего трафика в месяц. Блог с несколькими десятками мегабайт статики и парой тысяч посещений в такие рамки укладывается целиком, поэтому в детализации напротив всех строк Object Storage стоит ноль: и хранение, и одиннадцать тысяч операций GET, и сто двадцать операций PUT от последних деплоев, и весь исходящий трафик.

Детализация потребления за месяц

И получается что хостинг сайта раскатанный таким образом не стоит ничего. Все 44 рубля в счёте это Cloud DNS, где 41,95 рубля приходится на саму DNS-зону, которая тарифицируется по часам её существования, и ещё 82 копейки на публичные запросы к ней. Сертификат от Let’s Encrypt в Certificate Manager отдельных денег тоже не стоит.

Интересно посмотреть, что будет при росте. Ставки в стандартном хранилище такие: примерно 2,4 рубля за гигабайт хранения в месяц, 46 копеек за десять тысяч операций GET и около 1,7 рубля за гигабайт исходящего трафика сверх бесплатных ста. Если читателей станет в десять раз больше, операции вылезут за лимит на одиннадцать тысяч штук, и счёт вырастет на пятьдесят копеек. При стократном росте, то есть больше миллиона запросов в месяц, добавится сорок шесть рублей.

Сколько стоила бы виртуалка

Для сравнения я собрал в калькуляторе Yandex Cloud самую минимальную конфигурацию, два ядра с гарантированной долей 5%, 0.5 гб памяти, 5 гб диска и публичный IP-адрес. Вышло 612 рублей в месяц, и это сверх тех же 42 рублей за DNS, которые никуда не денутся. Почти 200 рублей из этой суммы приходится не на вычислительные ресурсы, а на публичный IP-адрес, ещё 17 на диск. Если довести машину до вменяемого состояния, скажем до 20% доли ядра и двух гигабайт памяти, счёт уходит в район полутора тысяч.

Разница тут не в том, что виртуалки у Яндекса такие дорогие, а в модели оплаты, в случае с Compute Cloud придётся платить за зарезервированные ресурсы. Ядра, память, диск и адрес будут капать в счёт круглые сутки независимо от того, зашёл на сайт хоть кто-нибудь или нет. Больше того, диск и IP тарифицируются даже когда машина выключена, так что 200 рублей в месяц набегают на полностью простаивающем сервере. Блог, который читают полтора человека в день, простаивает практически всё время, но платить приходится за все двадцать четыре часа.

Пришёл читатель и скачал 100 файлов, значит в счёт попали 100 операций GET и несколько сотен килобайт трафика. Не пришёл никто, значит и потребления нет. А поскольку блог такого размера целиком помещается в бесплатный лимит, фактический счёт за хостинг равен нулю, тогда как виртуалка выставляла бы свои шестьсот рублей каждый месяц независимо ни от чего.

Расчёт минимальной виртуальной машины в калькуляторе Yandex Cloud

Плюс к деньгам сюда добавляется всё, за что не приходится платить временем: не надо накатывать обновления безопасности, следить за сертификатами, чинить упавший nginx и держать в голове, что на машине вообще-то крутится веб-сервер, который по всем законам подлости обязательно рано или поздно отвалится.

Создано при помощи Hugo
Тема Stack, дизайн Jimmy