INTEGRITY Документация

Развертывание Worker

В этом руководстве вы пошагово развернете приложение Hello World с помощью Cloudflare Workers и инфраструктуры как кода (IaC) Pulumi и познакомитесь с жизненным циклом управления ресурсами. В частности, вы создадите Worker, Route и DNS Record для доступа к приложению, а затем удалите все ресурсы.

Перед началом работы

Убедитесь, что у вас есть:

1. Инициализируйте проект

Проект Pulumi представляет собой набор файлов в отдельной папке, описывающий инфраструктуру, которую требуется создать. Папка проекта Pulumi определяется обязательным Pulumi.yaml файл. Вы будете использовать Pulumi CLI для создания и настройки нового проекта.

a. Создайте каталог

Для этого руководства используйте новый пустой каталог.

mkdir serverless-cloudflare
cd serverless-cloudflare

b. Войдите в Pulumi Cloud

Pulumi Cloud ↗ это размещённый сервис, который предоставляет безопасную и масштабируемую платформу для управления инфраструктурой как кодом. Вы будете использовать его для хранения конфигураций бэкенда Pulumi.

В командной строке нажмите Enter, чтобы войти в аккаунт Pulumi Cloud через браузер. Также вы можете указать Токен доступа Pulumi Cloud ↗.

pulumi login

c. Создайте новую программу

Программа Pulumi представляет собой код, написанный на поддерживаемый язык программирования ↗ который определяет ресурсы инфраструктуры.

Чтобы создать программу, выберите нужный язык и выполните команду pulumi команда:

pulumi new javascript --name serverless-cloudflare --yes
# wait a few seconds while the project is initialized
pulumi new typescript --name serverless-cloudflare --yes
# wait a few seconds while the project is initialized
pulumi new python --name serverless-cloudflare --yes
# wait a few seconds while the project is initialized
pulumi new go --name serverless-cloudflare --yes
# wait a few seconds while the project is initialized
pulumi new java --name serverless-cloudflare --yes
# wait a few seconds while the project is initialized
pulumi new csharp --name serverless-cloudflare --yes
# wait a few seconds while the project is initialized
pulumi new yaml --name serverless-cloudflare --yes

d. Создайте стек

Pulumi стек ↗ это экземпляр программы Pulumi. Стеки настраиваются независимо друг от друга и могут представлять разные окружения (development, staging, production) или ветки функциональности. В этом руководстве вы будете использовать dev стек.

Чтобы создать экземпляр своего dev стек, выполните:

pulumi up --yes
# wait a few seconds for the stack to be instantiated.

На данный момент вы еще не определили ни одного ресурса, поэтому стек будет пустым.

e. Сохраните настройки приложения

На этом шаге вы сохраните настройки приложения в Pulumi ESC Environment ↗, YAML-файл с конфигурациями и секретами. Доступ к ним можно получить несколькими способами, включая программу Pulumi. Все ESC Environments надёжно хранятся в вашем аккаунте Pulumi Cloud и полностью управляются через Pulumi CLI. В этом руководстве вы сохраните следующие значения:

# Give your new ESC Environment a name
E=hello-world/dev-env

# Initialize the new ESC Environment
pulumi config env init --env $E --yes
Creating environment hello-world/dev-env for stack dev...
# Replace abc123 with your Cloudflare account ID
pulumi env set $E --plaintext pulumiConfig.accountId abc123

# Replace API_TOKEN with your Cloudflare API token
pulumi env set $E --secret pulumiConfig.cloudflare:apiToken API_TOKEN

# Replace example.com with your domain
pulumi env set $E --plaintext pulumiConfig.domain example.com

f. Установите пакет Cloudflare

Чтобы определять ресурсы Cloudflare в программе Pulumi, установите пакет Cloudflare для выбранного языка программирования.

Установите пакет Cloudflare, выполнив следующую команду:

npm install @pulumi/cloudflare
added 1 package ...
npm install @pulumi/cloudflare
added 1 package ...
echo "pulumi_cloudflare>=5.38,<6.0.0" >> requirements.txt
source venv/bin/activate
pip install -r requirements.txt
...Collecting pulumi-cloudflare...
go get github.com/pulumi/pulumi-cloudflare/sdk/v3/go/cloudflare
go: downloading github.com/pulumi/pulumi-cloudflare ...

Ниже приведены инструкции для Apache Maven. Для других менеджеров проектов Java, таких как Gradle, см. официальную Репозиторий Maven ↗

  1. Откройте свой pom.xml файл.
  2. Добавьте зависимость Pulumi Cloudflare внутри <dependencies> раздел.
<dependency>
    <groupId>com.pulumi</groupId>
    <artifactId>cloudflare</artifactId>
    <version>5.38.0</version>
</dependency>
  1. Выполните:
mvn clean install
...[INFO] BUILD SUCCESS...
dotnet add package Pulumi.Cloudflare
...
info : Adding PackageReference for package 'Pulumi.Cloudflare' into project
...

Для YAML не требуется загружать никаких зависимостей. Переходите к следующему шагу.

2. Опишите ресурсы Cloudflare в коде

После установки пакета Cloudflare вы можете определить любой поддерживаемый ресурс Cloudflare ↗ в своей программе Pulumi. Далее определите Worker, Route и DNS-запись.

a. Добавьте скрипт Workers

Ресурс Workers Script ↗ представляет собой Cloudflare Worker, который можно развернуть в сети Cloudflare.

Замените содержимое файла точки входа следующим:

Имя файла: index.js

"use strict";
const pulumi = require("@pulumi/pulumi");
const cloudflare = require("@pulumi/cloudflare");

const config = new pulumi.Config();
const accountId = config.require("accountId");
const domain = config.require("domain");

const content = `export default {
  async fetch(request) {
    const options = { headers: { 'content-type': 'text/plain' } };
    return new Response("Hello World!", options);
  },
};`;

const worker = new cloudflare.WorkersScript("hello-world-worker", {
	accountId: accountId,
	name: "hello-world-worker",
	content: content,
	module: true, // ES6 module
});

Имя файла: index.ts

import * as pulumi from "@pulumi/pulumi";
import * as cloudflare from "@pulumi/cloudflare";

const config = new pulumi.Config();
const accountId = config.require("accountId");
const domain = config.require("domain");

const content = `export default {
  async fetch(request) {
    const options = { headers: { 'content-type': 'text/plain' } };
    return new Response("Hello World!", options);
  },
};`;

const worker = new cloudflare.WorkersScript("hello-world-worker", {
	accountId: accountId,
	name: "hello-world-worker",
	content: content,
	module: true, // ES6 module
});

Имя файла: __main__.py

"""Pulumi program """
import pulumi
import pulumi_cloudflare as cloudflare

CONFIG = pulumi.Config()
ACCOUNT_ID = CONFIG.get("accountId")
DOMAIN = CONFIG.require("domain")
CONTENT = """
export default {
  async fetch(request) {
    const options = { headers: { 'content-type': 'text/plain' } };
    return new Response("Hello World!", options);
  },
};
"""

worker = cloudflare.WorkersScript("hello-world-worker",
    account_id=ACCOUNT_ID,
    name="hello-world-worker",
    content=CONTENT,
    module=True  # ES6 module
)

Имя файла: main.go

package main

import (
	"github.com/pulumi/pulumi-cloudflare/sdk/v5/go/cloudflare"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		conf := config.New(ctx, "")
		accountID := conf.Get("accountId")
		domain := conf.Get("domain")
		content := `
		export default {
		  async fetch(request) {
		    const options = { headers: { 'content-type': 'text/plain' } };
		    return new Response("Hello World!", options);
		  },
		};
		`
		worker, err := cloudflare.NewWorkersScript(ctx, "hello-world-worker", &cloudflare.WorkersScriptArgs{
			AccountId: pulumi.String(accountID),
			Name:      pulumi.String("hello-world-worker"),
			Content:   pulumi.String(content),
			Module:    pulumi.Bool(true), // ES6 module
		})
		if err != nil {
			return err
		}

		return nil
	})
}

Имя файла: src/main/java/myproject/App.java

package myproject;

import com.pulumi.Pulumi;
import com.pulumi.cloudflare.WorkersScript;
import com.pulumi.cloudflare.WorkersScriptArgs;
import com.pulumi.core.Output;

public class App {
    public static void main(String[] args) {
        Pulumi.run(ctx -> {
            var content = """
              export default {
                async fetch(request) {
                  const options = { headers: { 'content-type': 'text/plain' } };
                  return new Response("Hello World!", options);
                },
              };
            """;

            var accountId = ctx.config().require("accountId");
            var domain = ctx.config().require("domain");
            var worker = new WorkersScript("hello-world-worker", WorkersScriptArgs.builder()
                .accountId(accountId)
                .name("hello-world-worker")
                .content(content)
                .module(true)
                .build());

            return;
        });
    }
}

Имя файла: Program.cs

using Pulumi;
using Cloudflare = Pulumi.Cloudflare;

return await Deployment.RunAsync(() =>
{
    var config = new Config();
    var accountId = config.Require("accountId");
    var domain = config.Require("domain");
    var content = @"
            export default {
                async fetch(request) {
                    const options = { headers: { 'content-type': 'text/plain' } };
                    return new Response(""Hello World!"", options);
                },
            };
        ";

    var worker = new Cloudflare.WorkersScript("hello-world-worker", new()
    {
        AccountId = accountId,
        Name = "hello-world-worker",
        Content = content,
        Module = true
    });
    return;
});

Имя файла: Pulumi.yaml

name: serverless-cloudflare
runtime: yaml
resources:
  worker:
    type: cloudflare:WorkersScript
    properties:
      accountId: "${accountId}"
      name: "hello-world-worker"
      content: |
        export default {
            async fetch(request) {
                const options = { headers: { 'content-type': 'text/plain' } };
                return new Response("Hello World!", options);
            },
        };
      module: true

b. Добавьте маршрут

Теперь добавьте Ресурс Workers Route ↗ в свою программу Pulumi, чтобы у скрипта Workers появилась конечная точка и он стал активным. Чтобы правильно настроить Route, вы также найдёте идентификатор зоны для своего домена.

Добавьте следующий фрагмент кода в файл точки входа после ресурс скрипта Worker:

Имя файла: index.js

const zone = cloudflare.getZone({
	accountId: accountId,
	name: domain,
});

const zoneId = zone.then((z) => z.zoneId);

const route = new cloudflare.WorkersRoute("hello-world-route", {
	zoneId: zoneId,
	pattern: "hello-world." + domain,
	scriptName: worker.name,
});

Имя файла: index.ts

const zone = cloudflare.getZone({
	accountId: accountId,
	name: domain,
});

const zoneId = zone.then((z) => z.zoneId);

const route = new cloudflare.WorkersRoute("hello-world-route", {
	zoneId: zoneId,
	pattern: "hello-world." + domain,
	scriptName: worker.name,
});

Имя файла: __main__.py

zone = cloudflare.get_zone(account_id=ACCOUNT_ID, name=DOMAIN)
zone_id = zone.zone_id
route = cloudflare.WorkersRoute("hello-world-route",
    zone_id=zone_id,
    pattern="hello-world." + DOMAIN,
    script_name=worker.name
)

Имя файла: main.go

zone, err := cloudflare.LookupZone(ctx, &cloudflare.LookupZoneArgs{
  AccountId: &accountID,
  Name:      &domain,
}, nil)
if err != nil {
  return err
}

route, err := cloudflare.NewWorkersRoute(ctx, "hello-world-route", &cloudflare.WorkersRouteArgs{
  ZoneId:     pulumi.String(zone.Id),
  Pattern:    pulumi.String("hello-world." + domain),
  ScriptName: worker.Name,
})
if err != nil {
  return err
}

Имя файла: src/main/java/myproject/App.java

final var zone = CloudflareFunctions.getZone(GetZoneArgs.builder()
  .accountId(accountId)
  .name(domain)
  .build());
var route = new WorkersRoute("hello-world-route", WorkersRouteArgs.builder()
  .zoneId(zone.applyValue(getZoneResult -> getZoneResult.id()))
  .pattern("hello-world." + domain)
  .scriptName(worker.name())
  .build());

Имя файла: Program.cs

var zone = Output.Create(Cloudflare.GetZone.InvokeAsync(new()
{
    AccountId = accountId,
    Name = domain,
}));
var route = new Cloudflare.WorkersRoute("hello-world-route", new()
{
    ZoneId = zone.Apply(z => z.Id),
    Pattern = "hello-world." + domain,
    ScriptName = worker.Name,
});

Имя файла: Pulumi.yaml

Под runtime ключ, добавьте следующий код:

# new top-level section
variables:
  zone:
    fn::invoke:
      function: cloudflare:getZone
      arguments:
        accountId: ${accountId}
        name: ${domain}

Под worker ресурс, добавьте следующий код:

route:
  type: cloudflare:WorkersRoute
  properties:
    zoneId: ${zone.id}
    pattern: "hello-world.${domain}"
    scriptName: ${worker.name}

c. Добавьте запись DNS

Теперь добавьте DNS Ресурс Record ↗ чтобы разрешить ранее настроенный Route. На следующем шаге вы также выведете URL-адрес Route, чтобы его было удобно открыть.

Добавьте следующий фрагмент кода в файл точки входа после ресурс Route:

Имя файла: index.js

const record = new cloudflare.Record("hello-world-record", {
	name: route.pattern,
	type: "A",
	content: "192.0.2.1",
	zoneId: zoneId,
	proxied: true,
});

exports.url = pulumi.interpolate`https://${record.hostname}`;

Имя файла: index.ts

const record = new cloudflare.Record("hello-world-record", {
	name: route.pattern,
	type: "A",
	content: "192.0.2.1",
	zoneId: zoneId,
	proxied: true,
});

export const url = pulumi.interpolate`https://${record.hostname}`;

Имя файла: __main__.py

record = cloudflare.Record("hello-world-record",
    name=route.pattern,
    type="A",
    content="192.0.2.1",
    zone_id=zone_id,
    proxied=True
)

url = pulumi.Output.concat("https://", record.hostname)
pulumi.export('url', url)

Имя файла: main.go

record, err := cloudflare.NewRecord(ctx, "hello-world-record", &cloudflare.RecordArgs{
  Name:    route.Pattern,
  Type:    pulumi.String("A"),
  Content: pulumi.String("192.0.2.1"),
  ZoneId:  pulumi.String(zone.Id),
  Proxied: pulumi.Bool(true),
})
if err != nil {
  return err
}

ctx.Export("url", pulumi.Sprintf("https://%s", record.Hostname))

Имя файла: src/main/java/myproject/App.java

var record = new Record("hello-world-record", RecordArgs.builder()
    .name(route.pattern())
    .type("A")
    .content("192.0.2.1")
    .zoneId(zone.applyValue(getZoneResult -> getZoneResult.id()))
    .proxied(true)
    .build());

ctx.export("url", Output.format("https://%s", record.hostname()));

Имя файла: Program.cs

Обратите внимание на обновленную инструкцию ' return ', поскольку теперь вы экспортируете значение. Убедитесь, что вы также добавили using System.Collections.Generic; в своих импортах.

var record = new Cloudflare.Record("hello-world-record", new()
{
    Name = route.Pattern,
    Type = "A",
    Content = "192.0.2.1",
    ZoneId = zone.Apply(z => z.Id),
    Proxied = true
});

return new Dictionary<string, object?>
{
    ["url"] = Output.Format($"https://{record.Hostname}")
};

Обратите внимание на новый элемент верхнего уровня outputs раздел.

  record:
    type: cloudflare:Record
    properties:
      name: ${route.pattern}
      type: A
      content: "192.0.2.1"
      zoneId: ${zone.id}
      proxied: true

outputs:
  url: "https://${record.hostname}"

d. (Необязательно) Проверьте код

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

Имя файла: index.js

"use strict";
const pulumi = require("@pulumi/pulumi");
const cloudflare = require("@pulumi/cloudflare");

const config = new pulumi.Config();
const accountId = config.require("accountId");
const domain = config.require("domain");

const content = `export default {
  async fetch(request) {
    const options = { headers: { 'content-type': 'text/plain' } };
    return new Response("Hello World!", options);
  },
};`;

const worker = new cloudflare.WorkersScript("hello-world-worker", {
	accountId: accountId,
	name: "hello-world-worker",
	content: content,
	module: true, // ES6 module
});

const zone = cloudflare.getZone({
	accountId: accountId,
	name: domain,
});

const zoneId = zone.then((z) => z.zoneId);

const route = new cloudflare.WorkersRoute("hello-world-route", {
	zoneId: zoneId,
	pattern: "hello-world." + domain,
	scriptName: worker.name,
});

const record = new cloudflare.Record("hello-world-record", {
	name: route.pattern,
	type: "A",
	content: "192.0.2.1",
	zoneId: zoneId,
	proxied: true,
});

exports.url = pulumi.interpolate`https://${record.hostname}`;

Имя файла: index.ts

import * as pulumi from "@pulumi/pulumi";
import * as cloudflare from "@pulumi/cloudflare";

const config = new pulumi.Config();
const accountId = config.require("accountId");
const domain = config.require("domain");

const content = `export default {
  async fetch(request) {
    const options = { headers: { 'content-type': 'text/plain' } };
    return new Response("Hello World!", options);
  },
};`;

const worker = new cloudflare.WorkersScript("hello-world-worker", {
	accountId: accountId,
	name: "hello-world-worker",
	content: content,
	module: true, // ES6 module
});

const zone = cloudflare.getZone({
	accountId: accountId,
	name: domain,
});

const zoneId = zone.then((z) => z.zoneId);

const route = new cloudflare.WorkersRoute("hello-world-route", {
	zoneId: zoneId,
	pattern: "hello-world." + domain,
	scriptName: worker.name,
});

const record = new cloudflare.Record("hello-world-record", {
	name: route.pattern,
	type: "A",
	content: "192.0.2.1",
	zoneId: zoneId,
	proxied: true,
});

export const url = pulumi.interpolate`https://${record.hostname}`;

Имя файла: __main__.py

"""Pulumi program """
import pulumi
import pulumi_cloudflare as cloudflare

CONFIG = pulumi.Config()
ACCOUNT_ID = CONFIG.get("accountId")
DOMAIN = CONFIG.require("domain")
CONTENT = """
export default {
  async fetch(request) {
    const options = { headers: { 'content-type': 'text/plain' } };
    return new Response("Hello World!", options);
  },
};
"""

worker = cloudflare.WorkersScript("hello-world-worker",
    account_id=ACCOUNT_ID,
    name="hello-world-worker",
    content=CONTENT,
    module=True  # ES6 module
)

zone = cloudflare.get_zone(account_id=ACCOUNT_ID, name=DOMAIN)
zone_id = zone.zone_id
route = cloudflare.WorkersRoute("hello-world-route",
    zone_id=zone_id,
    pattern="hello-world." + DOMAIN,
    script_name=worker.name
)

record = cloudflare.Record("hello-world-record",
    name=route.pattern,
    type="A",
    content="192.0.2.1",
    zone_id=zone_id,
    proxied=True
)

url = pulumi.Output.concat("https://", record.hostname)
pulumi.export('url', url)

Имя файла: main.go

package main

import (
	"github.com/pulumi/pulumi-cloudflare/sdk/v5/go/cloudflare"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		conf := config.New(ctx, "")
		accountID := conf.Get("accountId")
		domain := conf.Get("domain")
		content := `
		export default {
		  async fetch(request) {
		    const options = { headers: { 'content-type': 'text/plain' } };
		    return new Response("Hello World!", options);
		  },
		};
		`
		worker, err := cloudflare.NewWorkersScript(ctx, "hello-world-worker", &cloudflare.WorkersScriptArgs{
			AccountId: pulumi.String(accountID),
			Name:      pulumi.String("hello-world-worker"),
			Content:   pulumi.String(content),
			Module:    pulumi.Bool(true), // ES6 module
		})
		if err != nil {
			return err
		}
		zone, err := cloudflare.LookupZone(ctx, &cloudflare.LookupZoneArgs{
			AccountId: &accountID,
			Name:      &domain,
		}, nil)
		if err != nil {
			return err
		}

		route, err := cloudflare.NewWorkersRoute(ctx, "hello-world-route", &cloudflare.WorkersRouteArgs{
			ZoneId:     pulumi.String(zone.Id),
			Pattern:    pulumi.String("hello-world." + domain),
			ScriptName: worker.Name,
		})
		if err != nil {
			return err
		}

		record, err := cloudflare.NewRecord(ctx, "hello-world-record", &cloudflare.RecordArgs{
			Name:    route.Pattern,
			Type:    pulumi.String("A"),
			Content: pulumi.String("192.0.2.1"),
			ZoneId:  pulumi.String(zone.Id),
			Proxied: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}

		ctx.Export("url", pulumi.Sprintf("https://%s", record.Hostname))

		return nil
	})
}

Имя файла: src/main/java/myproject/App.java

package myproject;

import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.cloudflare.WorkersScript;
import com.pulumi.cloudflare.WorkersScriptArgs;
import com.pulumi.cloudflare.CloudflareFunctions;
import com.pulumi.cloudflare.inputs.GetZoneArgs;
import com.pulumi.cloudflare.WorkersRoute;
import com.pulumi.cloudflare.WorkersRouteArgs;
import com.pulumi.cloudflare.Record;
import com.pulumi.cloudflare.RecordArgs;

public class App {
    public static void main(String[] args) {
        Pulumi.run(ctx -> {
            var content = """
				export default {
				  async fetch(request) {
				    const options = { headers: { 'content-type': 'text/plain' } };
				    return new Response("Hello World!", options);
				  },
				};
			""";

            var accountId = ctx.config().require("accountId");
            var domain = ctx.config().require("domain");

            var worker = new WorkersScript("hello-world-worker", WorkersScriptArgs.builder()
                .accountId(accountId)
                .name("hello-world-worker")
                .content(content)
                .module(true)
                .build());
            final var zone = CloudflareFunctions.getZone(GetZoneArgs.builder()
                .accountId(accountId)
                .name(domain)
                .build());
            var route = new WorkersRoute("hello-world-route", WorkersRouteArgs.builder()
                .zoneId(zone.applyValue(getZoneResult -> getZoneResult.id()))
                .pattern("hello-world." + domain)
                .scriptName(worker.name())
                .build());
            var record = new Record("hello-world-record", RecordArgs.builder()
                .name(route.pattern())
                .type("A")
                .content("192.0.2.1")
                .zoneId(zone.applyValue(getZoneResult -> getZoneResult.id()))
                .proxied(true)
                .build());

            ctx.export("url", Output.format("https://%s", record.hostname()));
            return;
        });
    }
}

Имя файла: Program.cs

using System.Collections.Generic;
using Pulumi;
using Cloudflare = Pulumi.Cloudflare;

return await Deployment.RunAsync(() =>
{
    var config = new Config();
    var accountId = config.Require("accountId");
    var domain = config.Require("domain");
    var content = @"
            export default {
                async fetch(request) {
                    const options = { headers: { 'content-type': 'text/plain' } };
                    return new Response(""Hello World!"", options);
                },
            };
        ";

    var worker = new Cloudflare.WorkersScript("hello-world-worker", new()
    {
        AccountId = accountId,
        Name = "hello-world-worker",
        Content = content,
        Module = true
    });
    var zone = Output.Create(Cloudflare.GetZone.InvokeAsync(new()
    {
        AccountId = accountId,
        Name = domain,
    }));
    var route = new Cloudflare.WorkersRoute("hello-world-route", new()
    {
        ZoneId = zone.Apply(z => z.Id),
        Pattern = "hello-world." + domain,
        ScriptName = worker.Name,
    });

    var record = new Cloudflare.Record("hello-world-record", new()
    {
        Name = route.Pattern,
        Type = "A",
        Content = "192.0.2.1",
        ZoneId = zone.Apply(z => z.Id),
        Proxied = true
    });

    return new Dictionary<string, object?>
    {
        ["url"] = Output.Format($"https://{record.Hostname}")
    };
});

Имя файла: Pulumi.yaml

name: serverless-cloudflare
runtime: yaml
variables:
  zone:
    fn::invoke:
      function: cloudflare:getZone
      arguments:
        accountId: ${accountId}
        name: ${domain}

resources:
  worker:
    type: cloudflare:WorkersScript
    properties:
      accountId: "${accountId}"
      name: "hello-world-worker"
      content: |
        export default {
            async fetch(request) {
                const options = { headers: { 'content-type': 'text/plain' } };
                return new Response("Hello World!", options);
            },
        };
      module: true
  route:
    type: cloudflare:WorkersRoute
    properties:
      zoneId: ${zone.id}
      pattern: "hello-world.${domain}"
      scriptName: ${worker.name}
  record:
    type: cloudflare:Record
    properties:
      name: ${route.pattern}
      type: A
      content: "192.0.2.1"
      zoneId: ${zone.id}
      proxied: true

outputs:
  url: "https://${record.hostname}"

3. Разверните приложение

Теперь, когда все ресурсы Cloudflare определены, вы можете развернуть приложение Hello World в своей учетной записи Cloudflare с помощью Pulumi CLI.

Чтобы развернуть изменения, выполните:

pulumi up --yes
wait for the dev stack to become ready

4. Протестируйте Worker

Вы последовательно добавили ресурсы Cloudflare для запуска приложения Hello World и доступа к нему. Проверить приложение можно с помощью команды curl для url вывод из стека Pulumi.

curl $(pulumi stack output url)
Hello, World!

5. Очистка

На этом последнем шаге вы очистите ресурсы и стек, использованные в этом руководстве.

a. Удалите ресурсы Cloudflare

pulumi destroy

b. Удалите стек Pulumi

pulumi stack rm dev

Следующие шаги

Перейдите в Документация пакета Cloudflare ↗ чтобы изучить другие ресурсы, которые можно определить с помощью Pulumi и Cloudflare.