← Containers / containers
Начало работы
В этом руководстве вы развернёте Worker, который сможет выполнять запросы к одному или нескольким Container в ответ на запросы конечных пользователей. В этом примере каждый контейнер запускает небольшой веб-сервер, написанный на Go.
Этот пример Worker даёт представление о простом использовании Container и служит отправной точкой для более сложных сценариев.
Предварительные требования
Убедитесь, что Docker запущен локально
В этом руководстве мы соберём и отправим образ контейнера вместе с кодом Worker. По умолчанию этот процесс использует Docker ↗ чтобы сделать это.
Docker должен быть запущен локально при выполнении wrangler deploy. Большинству пользователей проще всего установить Docker, следуя документация по установке Docker Desktop ↗. Другие инструменты, такие как Colima ↗ тоже может подойти.
Проверить, что Docker работает корректно, можно с помощью команды docker info команду в терминале. Если Docker запущен, команда выполнится успешно. Если Docker не запущен,
команда docker info зависнет или вернёт ошибку с сообщением "Cannot connect to the Docker daemon".
Разверните свой первый Container
Выполните следующую команду, чтобы создать и развернуть новый Worker с контейнером из стартового шаблона:
npm create cloudflare@latest -- --template=cloudflare/templates/containers-templateЧтобы развернуть изменение кода Worker или Container, выполните следующую команду с помощью Wrangler CLI:
npx wrangler deployПри развёртывании Wrangler загружает ваш Worker, собирает и отправляет образ контейнера с помощью Docker, а затем обновляет экземпляры контейнеров в сети Cloudflare. Первая сборка и отправка обычно занимают больше всего времени. Последующие развёртывания повторно использовать кэшированные слои образа ↗.
Проверьте статус деплоя
После деплоя выведите список контейнеров вашего аккаунта и их статусы:
npx wrangler containers listПросмотр списка образов в Cloudflare Registry:
npx wrangler containers images listВыполнение запросов к Containers
Откройте URL вашего Worker. Он должен выглядеть примерно так: https://hello-containers.<YOUR_WORKERS_SUBDOMAIN>.workers.dev.
- Запросы к
/container/1или/container/2маршрутизируются к определённым контейнерам. Каждый путь после/container/сопоставляется с уникальным контейнером. - Запросы к
/lbраспределяют нагрузку между тремя случайно выбранными контейнерами.
Прочитайте тело ответа, чтобы узнать, какой экземпляр обработал запрос. Если Worker отвечает, но маршруты контейнера всё ещё возвращают ошибку, подождите завершения подготовки, а затем проверьте Containers ↗ логи в дашборде.
Разбор кода
Теперь, когда вы развернули свой первый контейнер, разберёмся, что происходит в коде Worker, в конфигурационном файле, в коде контейнера и как маршрутизируются запросы.
Конфигурация
Ваш конфигурационный файл Wrangler определяет конфигурацию как для вашего Worker, так и для контейнера:
{
"containers": [
{
"max_instances": 10,
"class_name": "MyContainer",
"image": "./Dockerfile",
},
],
"durable_objects": {
"bindings": [
{
"name": "MY_CONTAINER",
"class_name": "MyContainer",
},
],
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["MyContainer"],
},
],
}[[containers]]
max_instances = 10
class_name = "MyContainer"
image = "./Dockerfile"
[[durable_objects.bindings]]
name = "MY_CONTAINER"
class_name = "MyContainer"
[[migrations]]
tag = "v1"
new_sqlite_classes = [ "MyContainer" ]Важные моменты об этой конфигурации:
imageуказывает на Dockerfile, на каталог, содержащий Dockerfile, или на полную ссылку на образ, напримерregistry.cloudflare.com/<YOUR_ACCOUNT_ID>/<IMAGE>:<TAG>.class_nameдолжен быть Имя класса Durable Object.max_instancesзадаёт максимальное количество одновременно работающих экземпляров контейнера, которые будут запущены.- Durable Object должен использовать
new_sqlite_classesа неnew_classes.
Образ Container
Образ вашего контейнера должен быть способен выполняться на linux/amd64 архитектуру, но в остальном имеет мало ограничений.
В только что развёрнутом примере используется простой сервер на Golang, который отвечает на запросы на порту 8080 с помощью MESSAGE переменную окружения, которая будет задана в Worker, и автоматически создаваемая
переменная окружения CLOUDFLARE_DEPLOYMENT_ID.
func handler(w http.ResponseWriter, r *http.Request) {
message := os.Getenv("MESSAGE")
instanceId := os.Getenv("CLOUDFLARE_DEPLOYMENT_ID")
fmt.Fprintf(w, "Hi, I'm a container and this is my message: %s, and my instance ID is: %s", message, instanceId)
}код Worker
Конфигурация Container
Первое замечание MyContainer который расширяет Container ↗ класс:
export class MyContainer extends Container {
defaultPort = 8080;
sleepAfter = '10s';
envVars = {
MESSAGE: 'I was passed in via the container class!',
};
override onStart() {
console.log('Container successfully started');
}
override onStop() {
console.log('Container successfully shut down');
}
override onError(error: unknown) {
console.log('Container error:', error);
}
}Здесь задаётся базовая конфигурация контейнера:
defaultPortзадаёт порт, которыйfetchиcontainerFetchметоды будут использовать для взаимодействия с контейнером. Это также блокирует запросы, пока контейнер не начнёт прослушивать этот порт.sleepAfterзадаёт тайм-аут, по истечении которого контейнер переходит в спящий режим после периода бездействия.envVarsзадаёт переменные окружения, которые будут переданы контейнеру при его запуске.onStart,onStop, а такжеonErrorявляются хуками, которые запускаются соответственно при старте, остановке или ошибке контейнера.
Container класс сам расширяет DurableObject, поэтому ваш подкласс имеет доступ ко всему API Durable Object. Durable Object отвечает за маршрутизацию, жизненный цикл и постоянное хранение состояния, а процесс контейнера запускает ваш образ внутри Linux VM. Это значит, что вы можете использовать this.ctx.storage для постоянного хранения данных, которые сохраняются при перезапуске контейнера и находятся в непосредственной близости от самого контейнера.
См. Справочник по классу Container и низкоуровневый API Container для Durable Object для дополнительных сведений.
Маршрутизация к Containers
Когда запрос поступает в Cloudflare, вашего Worker fetch обработчик вызывается. Это код, который обрабатывает входящий запрос. Обработчик fetch в примере кода запускает контейнеры двумя способами на разных маршрутах:
-
Выполнение запросов к
/container/передаёт запросы новому контейнеру для каждого пути. Это происходит за счёт запуска нового экземпляра Container. Вы можете заметить, что первый запрос к новому пути обрабатывается дольше, чем последующие, потому что новый контейнер ещё загружается.if (pathname.startsWith("/container")) { const container = env.MY_CONTAINER.getByName(pathname); return await container.fetch(request); } -
Выполнение запросов к
/lbбудет распределять запросы между несколькими контейнерами. Для этого используется простойgetRandomвспомогательный метод, который случайным образом выбирает ID из заданного числа экземпляров (в данном случае 3), а затем направляет запрос к выбранному экземпляру Container. Вы можете заменить эту логику любой другой логикой маршрутизации или балансировки нагрузки:if (pathname.startsWith("/lb")) { const container = await getRandom(env.MY_CONTAINER, 3); return await container.fetch(request); }
Это позволяет использовать Containers несколькими способами:
- Если вам просто нужно отправлять запросы к множеству взаимозаменяемых контейнеров без сохранения состояния, используйте балансировку нагрузки.
- Если у вас есть сервисы с сохранением состояния или вам нужны индивидуально адресуемые контейнеры, вам следует запрашивать конкретные экземпляры Container.
- Если вы выполняете кратковременные задачи, хотите получить точный контроль над жизненным циклом контейнера, хотите параметризовать entrypoint контейнера или переменные окружения, или хотите объединить в цепочку несколько вызовов контейнера, вам следует запрашивать конкретные экземпляры Container.
Просмотр Containers в своём Dashboard
Дашборд Containers ↗ показывает полезную информацию о ваших контейнерах, включая:
- Состояние и работоспособность
- Метрики
- Журналы
После запуска Worker перейдите в дашборд Containers, выбрав Workers & Pages > Containers на боковой панели дашборда.
Дальнейшие шаги
Что ещё можно сделать:
- Измените образ, изменив Dockerfile и выполнив
wrangler deploy - См. Развертывание Containers для Workers Builds и поведения при развёртывании
- Просмотрите примеры другие шаблоны использования
- Проверьте Часто задаваемые вопросы о поведении платформы и ограничениях