Генераторы статических сайтов становятся де-факто способом создания и развертывания веб-приложений, не требующих рендеринга на стороне сервера. Это приложения со страницами, которым не требуется фактический веб-сервер для динамической обработки контента. Типы страниц, которым действительно нужен сервер, часто защищены стеной аутентификации. Могут быть и другие сайты, где динамический контент создается на сервере для SEO.

Hugo, Gatsby и NextJS - одни из самых популярных решений в этой сфере. Все они создают выходные данные, состоящие из набора файлов (HTML, CSS, JavaScript, изображения) в папке, и затем мы можем предоставлять их пользователям с помощью обычного сервера (NGINX, Apache и т. Д.) Или, предпочтительно, через CDN (Content Delivery Network), поскольку для этого нам не понадобится бизнес-логика сервера. Только файловое хранилище, которое CDN будет использовать в качестве источника.

Наряду с этими артефактами для некоторых статических SPA, особенно приложений, разработанных с помощью react-router, может потребоваться дополнительная настройка. Этого можно добиться, перенаправив все пути в один файл. Этого можно добиться с помощью балансировщика нагрузки или даже с помощью самих Cloudflare Workers.

Во всех этих случаях нам все еще нужно где-то хранить наши файлы. AWS с использованием корзины S3 и распространения Cloudfront исторически был отличным вариантом. Цель этого поста - продемонстрировать другое решение. Развертывайте напрямую в Cloudflare Workers, используя их последнее хранилище данных Workers KV.

Я должен отметить, что первоначальная цель Cloudflare Worker - довести вычислительные возможности до периферии. Бессерверная платформа. Развертывание статических сайтов - еще один вариант использования, поддерживаемый благодаря наличию магазина Workers KV.

Что такое рабочий

Cloudflare Worker - это фрагмент кода JavaScript, который запускается каждый раз, когда вы получаете доступ к определенному маршруту на веб-сайте, проксируемом Cloudflare. Код выполняется по каждому запросу до попадания в кеш Cloudflare. Это означает, что ответы Worker не кэшируются (хотя запросы, сделанные Worker к другим веб-службам, могут кэшироваться с соответствующими заголовками кеширования).

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

Ниже приводится базовый рабочий:

Настроить домен / маршрут / воркер

Давайте развернем этого первого рабочего. Во-первых, вам нужен настроенный домен на Cloudflare. У меня уже есть outsrc.dev на моей панели.

В разделе DNS добавьте тип реестра A для поддомена www, указывающего на 192.2.0.1. Этот IP-адрес был предложен, поскольку никто не сможет разрешить его. Наш работник в любом случае перехватит все запросы.

Затем мы можем создать воркера на вкладке worker.

На панели Рабочие создайте нового рабочего, измените имя (я использовал hello-worker) и нажмите Сохранить и развернуть. Все рабочие могут быть автоматически развернуты в демонстрационном рабочем пространстве, в моем случае это https://hello-worker.outsrc.workers.dev/

После развертывания мы можем настроить маршрутизацию для запуска этого воркера в нашем основном домене outsrc.dev, возможно, даже на одном пути маршрута. Для этого нам нужно перейти на главную панель управления учетной записью и выбрать вкладку Рабочие.

Добавьте Route с помощью www.outsrc.dev/hello и выберите недавно развернутый hello-worker Worker.

Теперь мы можем получить прямой доступ к этому URL: https://www.outsrc.dev/hello

$ http https://www.outsrc.dev/hello
HTTP/1.1 200 OK
CF-RAY: 55d4285c0f45d4ed-MIA
Connection: keep-alive
Content-Length: 11
Content-Type: text/plain;charset=UTF-8
Date: Thu, 30 Jan 2020 14:32:51 GMT
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
Set-Cookie: __cfduid=dbd7b5387c4e90a370fdc89ed5e908f701580394771; expires=Sat, 29-Feb-20 14:32:51 GMT; path=/; domain=.outsrc.dev; HttpOnly; SameSite=Lax
Vary: Accept-Encoding
hello world

Инструменты

Создание / изменение кода Worker вручную может оказаться сложным, особенно если учесть, что нам может потребоваться автоматизировать все шаги по развертыванию веб-приложения.

Откройте Wrangler, инструмент командной строки Cloudflare Worker. Https://developers.cloudflare.com/workers/tooling/wrangler/

$ npm i @cloudflare/wrangler -g

После установки нам нужно настроить аутентификацию перед загрузкой / развертыванием того же базового Hello Worker с парой команд. Перейдите по адресу https://dash.cloudflare.com/profile/api-tokens, чтобы создать токен API для инструмента Wrangler. (Используйте шаблон Cloudflare Worker для разрешений)

$ wrangler config
wrangler config
💁  To find your API token, go to https://dash.cloudflare.com/profile/api-tokens
 and create it using the "Edit Cloudflare Workers" template
💁  If you are trying to use your Global API Key instead of an API Token
 (Not Recommended), run "wrangler config --api-key".
Enter API token: 

После настройки мы можем создать нового рабочего с помощью инструмента командной строки wrangler.

$ wrangler generate hello-worker https://github.com/cloudflare/worker-template

Этот шаблон воркера представляет собой простой JavaScript Hello Worker. Наряду с содержимым шаблона у нас также будет файл wrangler.toml с настройками, которые нам нужно обновить, например:

  • account_id: идентификатор вашей учетной записи, вы можете найти его на главной панели управления.
  • zone_id: каждая зона DNS в Cloudflare имеет собственный идентификатор, который также отображается на панели управления.
  • route: откуда можно будет получить доступ к Worker (например, www.outsrc.dev/hello)
  • worker_dev: верно | false. Он развернет ваш Worker в промежуточной среде. Обычно в форме: https://<worker_name>.<account_name>.worker.dev

Как только настройки будут на месте:

$ wrangler publish
💁  JavaScript project found. Skipping unnecessary build!
✨  Successfully published your script to www.outsrc.dev/hello

Рабочие КВ Магазин

Workers KV - это глобальное хранилище данных типа "ключ-значение" с малой задержкой. Он поддерживает исключительно большие объемы чтения с малой задержкой, что позволяет создавать высокодинамичные API-интерфейсы и веб-сайты, которые реагируют так же быстро, как и кэшированный статический файл.

С помощью этой функции мы можем:

  • Храните наши статические ресурсы HTML, CSS, изображения и файлы JavaScript на краю
  • Измените код нашего Worker'а, чтобы он возвращал правильный файл в соответствии с путем. (Это уже поддерживается в API JavaScript для Workers KV)
  • Используйте wrangler, чтобы автоматизировать весь процесс.

Давай сделаем это.

Создание статического веб-сайта

Подойдет любой генератор статических сайтов. Нам нужно только иметь возможность иметь статическую папку вывода сборки, и мы развернем ее в Worker KV и в Worker script, который будет извлекать из хранилища и обслуживать его.

В качестве отправной точки будет использоваться репо https://github.com/outsrc/template-frontend. Это репо основано на NextJS и уже включает команду для статического экспорта веб-приложения (создается папка out)

$ git clone [email protected]:outsrc/template-frontend.git static-app
$ cd static-app
$ yarn install
$ yarn export

Давайте добавим wrangler в качестве зависимости для разработки и настроим развертывание через wrangler.toml

$ yarn add --dev @cloudflare/wrangler
$ wrangler init --site hello-worker
⬇️ Installing cargo-generate...
🔧   Creating project called `workers-site`...
✨   Done! New project created /Users/ernestofreyre/Documents/nodeprojects/static-app/workers-site
✨  Succesfully scaffolded workers site
✨  Succesfully created a `wrangler.toml`

Это добавит:

  • worker-site папка: содержит все необходимые зависимости и index.js файл, который содержит наше статическое приложение Worker для внешнего интерфейса.
  • wrangler.toml файл: Настройки для развертывания Worker

Нам не нужно изменять папку worker-site (на данный момент), но wrangler.toml нуждается в некоторых обновлениях (выделено жирным шрифтом).

name = "hello-worker"
type = "webpack"
account_id = "<YOUR ACCOUNT ID>"
workers_dev = true
[site]
bucket = "./out"
entry-point = "workers-site"

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

$ wrangler publish
🌀  Created namespace for Workers Site "__hello-worker-workers_sites_assets"
💁  Uploading...
✨  Success
added 2 packages from 2 contributors and audited 2 packages in 0.395s
found 0 vulnerabilities
⬇️ Installing wranglerjs...
⬇️ Installing wasm-pack...
✨  Built successfully, built project size is 11 KiB.
✨  Successfully published your script to https://hello-worker.outsrc.workers.dev

Вот и все. Получите доступ к URL-адресу, отображаемому внизу, и вы увидите, что наше статическое приложение работает отлично (и очень быстро, я должен сказать)

Развернуть в производство

Это в нашем собственном домене. Нам нужно изменить wrangler.toml файл, чтобы включить в него раздел среды.

name = "hello-worker"
type = "webpack"
account_id = "<YOUR ACCOUNT ID>"
workers_dev = true
[site]
bucket = "./out"
entry-point = "workers-site"
[env.production]
zone_id = "<YOUR ZONE ID>"
route = "www.outsrc.dev/*"

Теперь мы можем:

$ wrangler publish --env production
🌀  Created namespace for Workers Site "__hello-worker-production-workers_sites_assets"
💁  Uploading...
✨  Success
⬇️ Installing wranglerjs...
⬇️ Installing wasm-pack...
✨  Built successfully, built project size is 11 KiB.
✨  Successfully published your script to www.outsrc.dev/*

Дальнейшее развертывание

Представьте, что мы создаем и развертываем все наши коммиты в хранилище Worker KV, используя хэш коммита в качестве префикса пути. (Пример: /8982c33e/index.html) Затем мы можем перенаправить весь запрос в режиме реального времени в любую папку фиксации, которую захотим. Это означает, что развертывание в производственной среде и откат можно выполнить мгновенно, изменив одно значение в хранилище KV. Также Canary Deplows (группа пользователей получит версию приложения)

Сначала создайте новое пространство имен Worker KV с именем CONTROL:

$ wrangler kv:namespace create "CONTROL"
🌀  Creating namespace with title "hello-worker-CONTROL"
✨  Success: WorkersKvNamespace {
    id: "22e976....",
    title: "hello-worker-CONTROL",
}
✨  Add the following to your wrangler.toml:
kv-namespaces = [ 
  { binding = "CONTROL", id = "22e976...." } 
]

Нам нужно поместить полужирный раздел поверх wrangler.toml файла:

name = "hello-worker"
type = "webpack"
account_id = "<YOUR ACCOUNT ID>"
workers_dev = true
kv-namespaces = [ 
  { binding = "CONTROL", id = "22e976...." } 
]
[site]
bucket = "./out"
entry-point = "workers-site"
[env.production]
zone_id = "<YOUR ZONE ID>"
route = "www.outsrc.dev/*"
kv-namespaces = [ 
  { binding = "CONTROL", id = "22e976...." } 
]

Поскольку наше приложение NextJS регенерирует папку статического вывода каждый раз, когда мы делаем yarn export, нам нужно соответственно перемещать файлы. Кроме того, инструмент командной строки wrangler не сохраняет старые файлы от предыдущих развертываний. Нам нужно собрать их все в одну папку. (Было бы неплохо, если бы wrangler разрешил нам хранить старые файлы в хранилище). Создайте папку сборок, куда мы будем копировать все наши статические сборки.

$ mkdir builds

И измените сценарии развертывания, чтобы сначала переименовать папку out в имя текущего хэша фиксации и переместить ее в папку builds:

{
  "name": "template-frontend",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "clean": "rimraf .next && rimraf out",
    "dev": "next",
    "build": "next build",
    "start": "next start",
    "export": "yarn clean && yarn build && next export",
    "test": "echo \"Error: no test specified\" && exit 1",
    "lint": "standard",
    "format": "prettier-standard --format",
    "pre-deploy": "mv out `git rev-parse HEAD | cut -c 1-8` && mv `git rev-parse HEAD | cut -c 1-8` builds",
    "deploy:production": "yarn export && yarn pre-deploy && wrangler publish --env production"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "next": "~9.2.0",
    "react": "^16.12.0",
    "react-dom": "^16.12.0"
  },
  "devDependencies": {
    "@cloudflare/wrangler": "^1.6.0",
    "@types/node": "^12.12.7",
    "@types/react": "^16.9.11",
    "prettier-standard": "^15.0.1",
    "rimraf": "^3.0.0",
    "standard": "^14.3.1",
    "typescript": "^3.7.2"
  }
}

Последние изменения, которые нам нужны, находятся в файле worker-site/index.js. Для каждого запроса сначала получайте хэш фиксации, который мы хотим обслуживать, и переназначайте запрос в эту папку, содержащую наши активы. Используя значение из пространства имен CONTROL, которое мы только что установили.

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

$ yarn deploy:production
yarn run v1.21.1
$ yarn export && yarn pre-deploy && wrangler publish --env production
$ yarn clean && yarn build && next export
$ rimraf .next && rimraf out
$ next build
Creating an optimized production build
Compiled successfully.
Automatically optimizing pages
Page                            Size     First Load
┌ ○ /                           595 B       75.5 kB
└ ○ /about                      583 B       75.5 kB
+ shared by all                 68.8 kB
  ├ static/_buildManifest.js    188 B
  ├ static/pages/_app.js        944 B
  ├ chunks/commons.9ed1b2.js    21.7 kB
  ├ chunks/framework.94bc9f.js  40.5 kB
  ├ runtime/main.99b7a8.js      4.69 kB
  └ runtime/webpack.b65cab.js   746 B
λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerProps)
○  (Static)  automatically rendered as static HTML (uses no initial props)
●  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)
> using build directory: /Users/ernestofreyre/Documents/nodeprojects/static-app/.next
  copying "static build" directory
  launching 15 workers
Exporting (3/3)
Export successful
$ mv out `git rev-parse HEAD | cut -c 1-8` && mv `git rev-parse HEAD | cut -c 1-8` builds
🌀  Using namespace for Workers Site "__hello-worker-production-workers_sites_assets"
💁  Uploading...
✨  Success
⬇️ Installing wranglerjs...
⬇️ Installing wasm-pack...
✨  Built successfully, built project size is 11 KiB.
✨  Successfully published your script to www.outsrc.dev/*
✨  Done in 16.53s.

Мы просто пропустили установку значения show_commit в пространстве имен CONTROL.

$ wrangler kv:key put --binding=CONTROL "show_commit" "0b0b0ef4"
✨  Success

Теперь, каждый раз, когда мы фиксируем и развертываем в производственной среде, приложение будет построено и развернуто в магазине KV. Команда для обновления используемого коммита:

$ wrangler kv:key put --binding=CONTROL "show_commit" "<COMMITHASH>"

Для отката просто требуется та же команда с хешем фиксации, который мы хотим откатить. Мгновенно.

Выводы

  • Вашему веб-приложению требуется CDN, Cloudflare CDN - проверенное решение.
  • Cloudflare Workers + Cloudflare Workers KV позволяет развертывать веб-приложения, созданные на основе статических сайтов, непосредственно на периферии.
  • Также могут поддерживаться более сложные варианты использования: различные базовые пути, улучшенные схемы безопасности.
  • Вы можете настроить конвейер CI / CD для непрерывного развертывания в хранилище Worker KV и решить позже, когда переводить пользователей на последние версии или выполнять откат при обнаружении ошибок.

Удачного взлома…