跳转到内容
搜索文档

部署 Worker

最后更新 查看 MarkdownAgent 设置

在本教程中,你将按照分步说明,使用 Cloudflare Workers 和 Pulumi 基础设施即代码(IaC)部署 Hello World 应用程序,以熟悉资源管理生命周期。具体而言,你将创建一个 Worker、一个 Route 和一个 DNS 记录来访问应用程序,然后清理所有资源。

开始之前

确保你拥有:

  • 一个 Cloudflare 账户和 API 令牌,具有在本教程中编辑资源的权限。如有需要,请在继续之前注册 Cloudflare 账户。你的令牌必须具有以下权限:
    • Account-Workers Scripts-Edit 权限
    • Zone-Workers Route-Edit 权限
    • Zone-DNS-Edit 权限
  • 一个 Pulumi Cloud 账户。你可以注册永久免费的个人版
  • 在你的机器上安装了 Pulumi CLI
  • 配置了一种 Pulumi 支持的编程语言。(TypeScript、JavaScript、Python、Go、.NET、Java 或使用 YAML)
  • 一个由 Cloudflare 管理的域名。完成添加网站教程将你现有的域名接入 Cloudflare。

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. 创建 Stack

Pulumi Stack 是 Pulumi 程序的实例。Stack 可以独立配置,可以代表不同的环境(开发、暂存、生产)或功能分支。在本教程中,你将使用 dev Stack。

要实例化你的 dev Stack,请运行:

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

此时你尚未定义任何资源,因此你将拥有一个空的 Stack。

e. 保存你的应用程序设置

在此步骤中,你将把应用程序设置存储在 Pulumi ESC Environment 中,这是一个包含配置和密钥的 YAML 文件。这些可以通过多种方式访问,包括 Pulumi 程序。所有 ESC Environment 都安全地存储在你的 Pulumi Cloud 账户中,可以通过 Pulumi CLI 完全管理。在本教程中,你将存储以下值:

  • 你的 Cloudflare 账户 ID
  • 有效的 Cloudflare API 令牌
  • 一个域名。例如,example.com
# 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 repository

  1. 打开你的 pom.xml 文件。
  2. <dependencies> 部分内添加 Pulumi Cloudflare 依赖项。
<dependency>
    <groupId>com.pulumi</groupId>
    <artifactId>cloudflare</artifactId>
    <version>5.38.0</version>
</dependency>
  1. Run:
mvn clean install
...[INFO] BUILD SUCCESS...
dotnet add package Pulumi.Cloudflare
...
info : Adding PackageReference for package 'Pulumi.Cloudflare' into project
...

YAML 没有需要下载的依赖项。请跳过此步骤。

2. 在代码中定义 Cloudflare 资源

安装 Cloudflare 包后,你现在可以在 Pulumi 程序中定义任何支持的 Cloudflare 资源。接下来,定义 Worker、Route 和 DNS 记录。

a. 添加 Workers 脚本

Workers Script 资源表示可部署到 Cloudflare 网络的 Cloudflare Worker。

将你的入口文件内容替换为以下内容:

Filename: 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
});

Filename: 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
});

Filename: __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
)

Filename: 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
	})
}

Filename: 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;
        });
    }
}

Filename: 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;
});

Filename: 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. 添加 Route

你现在将向 Pulumi 程序添加一个 Workers Route 资源,以便 Workers 脚本有一个端点并处于活动状态。为了正确配置 Route,你还需要查找域名的 Zone ID。

在 Worker 脚本资源之后,将以下代码片段添加到你的入口文件中:

Filename: 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,
});

Filename: 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,
});

Filename: __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
)

Filename: 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
}

Filename: 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());

Filename: 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,
});

Filename: 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。在下一步中,你还将输出 Route URL,以便轻松访问。

在 Route 资源之后,将以下代码片段添加到你的入口文件中:

Filename: 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}`;

Filename: 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}`;

Filename: __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)

Filename: 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))

Filename: 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()));

Filename: 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.(可选)验证你的代码

确认所有更改与以下完整解决方案匹配:

Filename: 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}`;

Filename: 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}`;

Filename: __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)

Filename: 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
	})
}

Filename: 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;
        });
    }
}

Filename: 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}")
    };
});

Filename: 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 资源,可以使用 Pulumi CLI 将 Hello World 应用程序部署到你的 Cloudflare 账户。

要部署更改,请运行:

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

4. 测试 Worker

你逐步添加了 Cloudflare 资源来运行和访问 Hello World 应用程序。你可以通过对 Pulumi Stack 的 url 输出执行 curl 来测试你的应用程序。

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

5. 清理

在最后一步,你将清理本教程中使用的资源和 Stack。

a. 删除 Cloudflare 资源

pulumi destroy

b. 删除 Pulumi Stack

pulumi stack rm dev

后续步骤

访问 Cloudflare 包文档以探索可以使用 Pulumi 和 Cloudflare 定义的其他资源。

这篇文档对您有帮助吗?