Пошаговая инструкция по деплою статического сайта в облако, прикрутки к нему сертификата Let’s Encrypt, домена второго уровня и настройки API-шлюза

Идея познакомиться с serverless на практике меня привлекала так же сильно как и желание потестировать с пользой один из генераторов статических сайтов.

Я присматривалась к скоростному Gatsby c пушечными стартерами — платформе open source, сделанной на React, и к облачной платформе Yandex.Cloud, где есть опция хостинга статических сайтов. К тому же надо было обновить портфолио.

C нуля и до деплоя я реализовала свои идеи: serverless + быстрый сайт + портфолио. В процессе загрузки своего приложения в облако Яндекса я познакомилась с дружелюбным и быстрорастущим коммьюнити Yandex.Cloud в Telegram и побывала на конференции Gatsby. Это еще пара мощных профитов ко всему полученному опыту.

Хочу поделиться пошаговым процессом деплоя в облако и прикрутки к облаку своего домена разными способами — к бакету и к API Gateway. Пусть мое руководство сэкономит время таким же страстным поклонникам красивых быстрых serverless-технологий и адептам JAM-подхода.

Из текста вы узнаете, как: 

  • выложить статическии? саи?т на Gatsby в Object Storage;

  • выпустить и привязать сертификат Let's Encrypt через Yandex Certificate Manager;

  • подключить Object Storage и привязать домен к API Gateway или бакету.

1. Создаем свой сайт на Gatsby

Идем на сайт Gatsby и находим раздел со стартерами. Залипание на стартерах можно оставить на потом. Первым делом устанавливаем генератор статических сайтов. 

npm install -g gatsby-cli

Выбираем стартер и клонируем его себе. Под каждым стартером есть команда со ссылкой  на репозиторий:

gatsby new my-gatsby-project https://github.com/gatsbyjs/gatsby-starter-blog

Переходим в папку проекта:

cd gatsby-starter-blog

Запускаем локальный сервер для разработки сайта:

gatsby develop 

По умолчанию Gatsby запускает локальную среду разработки на порту 8000: 

http://localhost:8000

Если история с шаблонами неинтересна, можно создать заготовку своего проекта на Gatsby.

gatsby new gatsby-site
cd gatsby-site

На этом все настройки для создания своего статического сайта на Gatsby  по готовому шаблону закончены. Можно начинать адаптировать сайт под себя. 

2. Регистрируем домен 

Вам нужен домен третьего уровня — это основная идея. Так вы избежите танцев с www-бубном, которые я исполняла, когда захотела разместить свой сайт на домене второго уровня — edibleclouds.ru.

Почему третьего? Для домена третьего уровня можно прописать CNAME DNS-запись, указывающую на URL. Кроме того, домен третьего уровня нужен для создания API-шлюза.

Если у вас уже есть готовый домен второго уровня, и вы хотите, чтобы ваш сайт работал из облака именно на нем, а еще через API-шлюз, то придется немного покружиться в шаманском танце из пунктов 11-13 данного руководства.

После того как домен создан, переходим  к работе с хранилищем через сервис Object Storage. 

3. Создаем бакет в объектном хранилище

Заходим на Yandex.Cloud и жмем Подключиться. Если вы обычный, а не федеративный пользователь, то для подключения понадобится аккаунт на Яндексе.

Мы оказываемся в личном кабинете Yandex.Cloud, где создаем свое Облако, а в нем — сервисный каталог, из которого удобно работать со всеми используемыми сервисами Yandex.Cloud. 

В консоли управления слева находим сервис Object Storage. В инструкции Как начать работать с Yandex Object Storage описано, как начать с ним работать. Объектное хранилище Yandex.Cloud совместимо с аналогичной технологией Amazon S3.  Им тоже можно управлять через  CLI и пользоваться для хостинга статических сайтов.

В самом хранилище мы создаем бакет. Делаем один, если у вас домен третьего уровня и два — если у вас домен второго уровня. Второй бакет называем по имени домена, но с приставкой www. Он будет дополнительным.

Называем бакеты в точности, как домены: бакеты не переименовываются, их можно только удалить.

Пройдемся по параметрам бакета. 

  • Макс. размер — указываем примерный вес сайта, не больше: так проще будет контролировать расходы и меньше шансов выйти за допустимый предел. Мы платим за объем, который занимают наши данные.

  • Доступ на чтение объектов — нам нужен вариант «Публичный», чтобы на клиенте корректно рендерилась верстка и отрабатывали скрипты.

  • Доступ к списку объектов и Доступ на чтение настроек — в «Ограниченном» режиме бакет будет работать как внутреннее хранилище файлов.

  • Класс хранилища — оставляем «Стандартный». Пользователи будут скачивать фаи?лы при каждом новом посещении. А значит, это тоже влияет на стоимость услуги.

Объяснение к параметрам бакета я взяла на Хабре, в примере размещения в Object Storage сайта на Angular.

Все, бакет с именем домена готов к тому, чтобы задеплоить в него локальный проект. Но наш проект сделан на Gatsby, он не собран, и просто руками перетащить файлы туда не получится. Я поизучала работу Yandex.Cloud и залила в бакет сырои? проект со всеми node_modules весом 500 МБ через командную строку:  

aws --endpoint-url=https://storage.yandexcloud.net s3 cp --recursive local_files/ 
s3://bucket-name/path_style_prefix/

За это в Yandex.Cloud улетело около 18 из 3000 рублеи?, предоставленных на пробныи? период. Ну, хорошо, что не как в эпичном кейсе ребят из калифорнийского стартапа MilkyWay, которые сожгли на тесте Google Cloud и Firebase 72K $ за два часа.

Serverless-провайдеры хороши тем, что берут плату только за те ресурсы, которые ты тратишь — это главный принцип бессерверности. Если нужно больше ресурсов, масштабирование происходит автоматически.

Для сборки и деплоя моего сайта мне пригодился плагин S3, который есть у Gatsby. Чтобы им воспользоваться, мне понадобились: сервисный аккаунт, статический ключ доступа и консольные клиенты — CLI Yandex и AWS CLI. 

Чтобы все это получить,  я прошла процедуру аутентификации через Yandex Identity and Access Management — сервис идентификации и контроля доступа, который помогает централизованно управлять правами доступа пользователей к вашим ресурсам.

4. Устанавливаем CLI Yandex.Cloud и создаем профиль

Интерфейс командной строки Yandex.Cloud нам понадобится для работы от имени сервисного аккаунта:

curl https://storage.yandexcloud.net/yandexcloud-yc/install.sh | bash

Чтобы создать профиль, получаем OAuth-токен в сервисе Яндекс.OAuth. Токен будет сохранен в конфигурации профиля, и аутентификация будет происходить автоматически.

Пошаговый процесс установки CLI и получения OAuth-токена описан в документации Yandex.Cloud, в разделе Начало работы с интерфейсом командной строки.

5. Создаем сервисный аккаунт, назначаем ему роли, проходим аутентификацию от его имени 

От имени сервисного аккаунта программы могут управлять ресурсами в Yandex.Cloud. 

Подробно о том, зачем нужны сервисные аккаунты, написано в документации Yandex.Cloud, в разделе Сервисные аккаунты.

Как аутентифицироваться от имени сервисного аккаунта написано в разделе Аутентификация от имени сервисного аккаунта.

Как назначить роли сервисному аккаунту и какие они бывают, читайте в разделе Назначение роли сервисному аккаунту.

6. Cоздаем статический ключ доступа для сервисного аккаунта в Yandex.Cloud

Статические ключи доступа — секретный ключ и идентификатор ключа — используются только в сервисных аккаунтах для аутентификации в сервисах с AWS-совместимым API, например в Object Storage. 

Как создать статический ключ доступа, читайте в документации Yandex.Cloud, в разделе Создание статических ключей доступа.

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

AWS_ACCESS_KEY_ID = 
AWS_SECRET_ACCESS_KEY =

И добавляем файл в проект.

7. Настраиваем консольный клиент к S3

Object Storage поддерживает некоторые методы HTTP API Amazon S3, поэтому тут  можно воспользоваться популярными инструментами для работы с этим сервисом. Настроим консольный клиент — AWS CLI. Нам нужна вторая версия.

Читайте раздел AWS Command Line Interface, чтобы понять, как пользоваться AWS CLI для работы с Object Storage.

7. Подключаем плагин S3

Теперь осталось подключить плагин, добавить несколько строк кода и можно деплоить проект в бакет.

Устанавливаем плагин:

npm i gatsby-plugin-s3

Добавляем код в папку plugins файла gatsby-config.js. Подставляем вместо <bucket-name> имя бакета. Обратите внимание на регион. Оставляем его именно таким, несмотря на то, что в инструкциях можно встретить указание везде прописывать ru-central1.

{
  resolve: 'gatsby-plugin-s3',
  options: {
    bucketName: '<bucket-name>',
    region: 'us-east-1',
    customAwsEndpointHostname: 'storage.yandexcloud.net'
  }
}

В package.json в секцию scripts добавляем "deploy".

{
  "scripts": {
    "deploy": "gatsby-plugin-s3 deploy --yes"
  }
}

9. Run&Deploy = Enjoy

Запускаем. Проект сбилдится и загрузится в указанный бакет.

npm run build && npm run deploy

Не обращайте внимания на вывод в консоли. Там будет указан адрес для AWS S3 независимо от того, какой хост указан в переменной customAwsEndpointHostname.

Теперь сайт открывается по адресу http://edibleclouds.ru.website.yandexcloud.net/

В разделе Статический веб-сайт в Yandex Object Storage в пунктах 4-10 описано, как настроить главную страницу и страницу ошибки.

Но наш сайт сейчас работает по HTTP. Создадим защищенный протокол.

10. Выпускаем сертификат Let’s Encrypt

Сертификат нам понадобится как для создания безопасного соединения по HTTPS, так и для API Gateway, чтобы использовать домен для обращения к API.

Создаем сертификат через сервис Certificate Manager. Инструкция по созданию лежит в разделе Создание сертификата от Let's Encrypt документации.

Для тех, у кого домен второго уровня: я создаю сертификат сразу для двух доменов — с www и без.

Добавить второй домен к уже созданному сертификату Let’s Encrypt не получится, придется проходить всю процедуру валидации, а значит и выпуска сертификата заново. Процесс проверки может занимать от шести минут до суток. С каждым разом попытки проверки становятся реже — до одного раза в шесть часов. 

Как мы видим на скриншоте, можно выбрать два способа проверки  — через HTTP или через DNS. В инструкции Как начать работать c Certificate Manager, по которой я шла, было сказано выбрать тип проверки HTTP. Но во всех других инструкциях, например в инструкции Проверка прав на домен, было написано, что можно выбрать любой тип. 

Поскольку я выбрала HTTP, то процесс запуска процедуры валидации такой же, как в разделе Проверка прав на домен.

Для HTTP-валидации нужно создать файлы для обоих доменов с названием, указанным в блоке Ссылка для размещения файла, положить туда Содержимое и добиться того, чтобы эти файлы открывались по ссылке. Обратите внимание — файлы должны быть без расширения txt в конце. Это критично для процедуры проверки. 

Как только мы убедились, что оба файла доступны по ссылке, можем переключаться на другие дела. Процедура проверки запущена. В лучшем случае через шесть минут статус из Pending сменится на Valid, а Validating — на Issued. 

11. Настраиваем доступ по HTTPS

Сертификаты готовы, и теперь мы можем настроить доступ по HTTPS к нашим бакетам и доменам. 

Идем в бакет, слева в меню находим вкладку HTTPS, жмем на нее, выбираем из списка нужный сертификат и добавляем его. 

Если делать валидацию через  DNS, то сертификат продлевается автоматически. 

Доступ к бакету по HTTPS открывается в течение получаса после выбора сертификата.

12. Подключаем домен к бакету 

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

Домен второго уровня подключить к Облаку напрямую нельзя — такие домены не направляются на другой хост при помощи изменения записи CNAME. Поэтому мы создавали два бакета и делали сертификат на каждый. Подробнее об этом читайте в документе Common DNS Operational and Configuration Errors, п.2.4.

Сейчас пришло время добавить ресурсную запись CNAME у субдомена. В моем случае это www.edibleclouds.ru. Для этого в редакторе DNS у своего регистратора прописываем: 

www CNAME edibleclouds.ru.website.yandexcloud.net

И далее направляем домен на бакет: 

а) Через IP

Способ рабочий, но не самый надежный. IP облака может измениться, сайт упадет, а вы про это даже не узнаете. По словам Джорджа из облачного чата, IP у облака не менялся уже два года, и ничего не предвещает изменений в будущем. 

Чтобы мой основной домен edibleclouds.ru смотрел в облако, нужно у регистратора поменять запись типа A, указав IP Облака вместо IP того сервера, на чьи DNS мой домен делегирован. 

Затем идем в редактор DNS своего регистратора и меняем в А-записи этот адрес на адрес Yandex.Cloud — 93.158.134.163. Все, через минут 10 домен будет смотреть в облако.

б) Через DNS у регистратора

На примере reg.ru процесс настройки собственного домена третьего уровня через DNS пошагово описан в разделе Статический веб-сайт в Yandex Object Storage документации.

В случае работы с доменом второго уровня делаем переадресацию из бакета с www на бакет с именем домена второго уровня во вкладке Веб-сайт.

13. Cоздаем API-шлюз, подключаем домен к шлюзу

В Yandex.Cloud можно создать API-шлюз и настроить свой домен третьего уровня для обращения к шлюзу. С технической точки зрения для статического сайта выгоднее и удобнее размещать сайт и прикручивать домен к Object Storage. Это дешевле и требует меньше настроек. 

Но сервис API Gateway позволяет более гибко настроить сайт и добавить в него динамику, когда это потребуется. Я подключила домен к API Gateway еще на статике, и потому рассказываю тут, как это делается.

Домен можно использовать из сервиса Certificate Manager, при этом для TLS-соединения будет использован привязанный к домену сертификат. В моем случае это домен www.edibleclouds.ru и сертификат Let’s Encrypt.

Чтобы подключить домен к шлюзу сначала мы создаем шлюз, а затем подключаем домен

Для этого я также размещаю у своего регистратора (в моем случае это nic.ru)  CNAME-запись такого вида. 

Домен в консоли должен быть в списке и в статусе Valid. Статус означает, что Yandex.Cloud может принимать трафик с вашего домена.

Проверить, что домен подключен и все работает, можно обратившись к этому домену. В логах API Gateway должен отобразиться соответствующий запрос.

Чтобы домен работал как шлюз, нам нужно настроить шлюз на бакет — интегрировать API Gateway c Object Storage. Это делается в спецификации YAML. Найдите в правом верхнем углу меню Редактировать.

Можно скопировать спецификацию отсюда. Только замените url, bucket и service_account_id на свои: 

openapi: 3.0.0
info:
 title: Test API
 version: 1.0.0
servers:
- url: https://<служебный домен>.apigw.yandexcloud.net
- url: https://www.edibleclouds.ru
paths:
 /:
   get:
     x-yc-apigateway-integration:
       type: object_storage
       bucket: ваш бакет
       object: index.html
       service_account_id: идентификатор сервисного аккаунта
 /{file+}:
   get:
     x-yc-apigateway-integration:
       type: object_storage
       bucket: ваш бакет
       object: '{file}'
       service_account_id: идентификатор сервисного аккаунта
     parameters:
     - explode: false
       in: path
       name: file
       required: true
       schema:
         type: string
       style: simple

Всё, мой сайт edibleclouds.ru, сделанный на платформе Gatsby, теперь размещён на Yandex.Cloud, и обращаться к моему API-шлюзу можно через домен www.edibleclouds.ru. Домен второго уровня edibleclouds.ru я могу настроить на API-шлюз также через A-запись у регистратора. При этом придется надеяться, что IP-адрес шлюза в ближайший год не изменится.

Чтобы настроить домен на API-шлюз, берем нужный технический домен (API Gateway или Object Storage), узнаем его IP (например, с помощью команды host %api_gw_id%.apigw.yandexcloud.net), и полученный IP указываем в значении A-записи. На этом тренировка закончена.

Используемые технологии

Для создания и размещения сайта на своем домене в облаке при помощи платформ Gatsby и Yandex.Cloud мне пригодились технологии:

·  VSCode

·  Git

·  Node.js

·  NPM

·  React

·  Python

·  Yandex Identity and Access Management

·  СLI Yandex.Cloud

·  AWS CLI

·  Яндекс.OAuth

·  Object Storage

·  Yandex Certificate Manager

·  Yandex API Gateway

А также были полезны официальные чаты Yandex.Cloud без флуда и мусора — Yandex.Cloud и Yandex Serverless Ecosystem. Это скорая помощь №1 при работе с облачной платформой Яндекса.