12、云任务调度与基础设施即代码:Cloud Tasks 与 Terraform 实战

云任务调度与基础设施即代码:Cloud Tasks 与 Terraform 实战

1. 使用 Cloud Tasks 客户端库调度任务

要理解调度任务时的实际操作,我们可以通过以下代码示例来了解如何使用 Cloud Tasks 客户端库将任务添加到队列中:

// tasks "cloud.google.com/go/cloudtasks/apiv2"
client, err := tasks.NewClient(context.Background())
serviceAccount, err := metadata.Email("default")
// taskspb "google.golang.org/genproto/googleapis/cloud/tasks/v2"
req := &taskspb.CreateTaskRequest{
    Parent: queueName,
    Task: &taskspb.Task{
        MessageType: &taskspb.Task_HttpRequest{
            HttpRequest: &taskspb.HttpRequest{
                Url:        URL + "/" + path,       // Destination
                HttpMethod: taskspb.HttpMethod_GET, // or POST
                // Add ID Token to Request
                AuthorizationHeader: &taskspb.HttpRequest_OidcToken{
                    OidcToken: &taskspb.OidcToken{
                        ServiceAccountEmail: serviceAccount,
                        Audience:            URL, // Scope token to URL
                    },
                },
            },
        },
        // Set a 15 minute  timeout:
        DispatchDeadline: durationpb.New(15 * time.Minute),
    },
}
// Schedule task
_, err = client.CreateTask(context.Background(), req)

上述代码展示了如何发送任务请求,其中包含一个 HTTP 请求模板 ( taskspb.HttpRequest )。这里有两个要点需要注意:一是设置了 15 分钟的调度截止时间(超时时间);二是使用 Cloud Run 服务的服务账户设置了授权头,这会指示 Cloud Tasks 创建并向发往工作器的出站请求添加 ID 令牌。

2. 自动 ID 令牌

ID 令牌是在任务执行时由 Cloud Tasks 添加的,而不是在调度任务时添加。这是合理的,因为任务可能会由于重试或设置了延迟执行而在稍后执行。ID 令牌的最大有效期为一小时。

作为内置的平台服务,Cloud Tasks 已经拥有代表任何服务账户生成 OIDC 令牌的权限,但创建任务的调用者(在本例中为 task-app 服务账户)需要具有“服务账户用户”角色。添加该角色的操作步骤如下:

gcloud iam service-accounts add-iam-policy-binding \
    task-app@$PROJECT.iam.gserviceaccount.com \
    --member serviceAccount:task-app@$PROJECT.iam.gserviceaccount.com \
    --role roles/iam.serviceAccountUser

此命令将服务账户与“服务账户用户”角色绑定,并将其添加到服务账户本身。

3. 连接工作器

最后一步是在任务应用服务上设置工作器服务的 URL。具体操作步骤如下:
1. 查找并复制工作器服务的 URL:

gcloud run services list --filter metadata.name=worker
  1. 最后一次更新任务应用服务的配置:
gcloud run services update task-app \
    --update-env-vars WORKER_URL=[WORKER_URL]
4. 测试应用

现在,打开 task-app*.run.app URL 并点击按钮,它将在工作器上调度一个任务。打开 Web 控制台,查找两个服务的日志。任务应用的日志将显示“任务已调度”,工作器的日志将显示“任务已完成”。

5. 队列配置

队列配置包含两个部分:重试配置和速率限制。下面分别进行介绍:
- 重试配置 :Cloud Tasks 会重试失败的 HTTP 请求,即那些超时或返回非 2xx 状态码的请求。重试行为是可配置的,且可能有点复杂。Cloud Tasks 如何处理任务的重试是在队列中定义的。

当请求失败时,会安排重试。重试配置由四个设置决定每次重试之间的间隔:最小退避时间、最大退避时间、最大倍增次数和最大尝试次数。具体过程如下:
- 第一次间隔是最小退避时间(示例中为 1 秒)。
- 然后进入倍增阶段,每次尝试的下一个间隔是前一个间隔的两倍。
- 在经过一定次数的尝试(由最大倍增次数设置)后,进入线性阶段。在此阶段,每次间隔增加 2^(最大倍增次数) + 最小退避时间 。在示例中,线性增加为 2^2 + 1 = 5 秒。
- 线性阶段持续到间隔超过最大退避时间设置。从那时起,间隔保持在最大退避时间(示例中为 15 秒)。
- 尝试将继续进行,直到达到最大尝试次数。

当最大尝试次数用尽时,Cloud Tasks 会忘记该任务并停止重试。如果不想出现这种情况,可以采取以下两种方法:
- 将重试尝试次数设置为无限制(这可能会导致任务一直重试下去)。
- 在数据库中跟踪完成状态,以便另一个进程可以定期决定如何处理这些任务。

  • 速率限制 :速率限制功能在调用扩展性不佳的端点时特别有用。有两个设置: maxDispatchesPerSeconds 设置最大速率, maxConcurrentDispatches 设置可以同时执行的最大任务数。默认设置为 1000,这个值非常高。虽然这可能对你适用,但你应该测试适合你情况的并发级别。高并发并不一定好,例如有 1000 个任务,如果一次运行 1000 个,可能比并发为 20 时完成得更慢。
6. 查看和更新队列配置

查看队列配置的命令如下:

gcloud tasks queues describe jobs

示例输出如下:

name: projects/.../queues/jobs
rateLimits:
  maxConcurrentDispatches: 1000
  maxDispatchesPerSecond: 500.0
retryConfig:
  maxAttempts: 100
  maxBackoff: 3600s
  maxDoublings: 16
  minBackoff: 0.100s
state: RUNNING

更新队列设置的命令如下:

gcloud tasks queues update jobs --help
7. 注意事项
  • Cloud Tasks 可能会两次交付请求 :在生产环境中,任务端点可能会被调用多次,发生这种情况的概率小于 0.001%。如果执行同一任务两次会造成严重后果,需要采取措施防止。解决方案是在创建任务时,应用还在数据库中持久化一条记录以跟踪任务状态。这允许工作器在开始时将任务标记为正在进行中,从而防止重复执行。此外,还可以使用此方法跟踪无法交付的任务,并避免将任务尝试次数设置为无限制。记得定期检查未完成的任务并进行处理。
  • 本地开发 :在开发中使用 Cloud Tasks 具有挑战性,因为没有对应的模拟器。解决方案是在开发中使用 Goroutine(后台线程)执行 HTTP 请求,因为本地机器没有限流。可以探索应用的源代码以了解更多信息,其中有一个 docker-compose.yml 文件,可让你在本地机器上运行两个服务。如果你觉得运行 Goroutine 不够好,想在开发中获得更接近生产环境的体验,可以了解一下 Cloud Tasks 模拟器(Google 不支持)。
  • 替代方案 :在 Google Cloud 上,也可以使用 Pub/Sub 作为队列来发送 HTTP 请求,但它不太适合任务调度的用例。Cloud Workflows 最近发布,如其名称所示,当你需要定义一个由多个相互依赖的任务组成的工作流时,它提供了另一种选择。
8. 基础设施即代码(IaC)概述

基础设施即代码是指使用源代码来描述整个基础设施,并使用管理工具来创建、更新或删除这些资源。下面是相关概念的定义:
| 术语 | 定义 |
| ---- | ---- |
| 基础设施 | 当你想从头开始创建整个应用程序时,需要存在并配置的所有云资源。 |
| 云资源 | 可以通过 Google Cloud API(使用 gcloud 或 Web 控制台)创建的资源,如 Cloud Run 服务、VPC 连接器、Cloud SQL 实例、Google Cloud 项目、服务账户和 IAM 策略绑定等。 |
| 基础设施即代码 | 使用源代码描述整个基础设施,并使用管理工具进行资源的创建、更新或删除。 |
| 源代码 | 根据实际使用的工具,用于基础设施即代码的源代码可以是简单的配置语言、成熟的编程语言或介于两者之间的语言。 |

使用基础设施即代码有诸多好处:
- 更易于理解和维护系统,通过阅读代码而不是查询生产系统来了解资源之间的关系。
- 可以将其放入版本控制,与团队协作构建基础设施,每个基础设施变更都可以通过拉取请求流程进行审查,促进协作并让新团队成员更快上手,使变更更容易且不那么令人担忧。
- 具有可重复性,创建新的 Google Cloud 项目时,可以使用 IaC 工具进行设置,也可以轻松拆除所有创建的资源,避免意外成本。

9. Terraform 简介

Terraform 是一个开源的基础设施即代码工具,由 HashiCorp 开发并提供增值服务。选择 Terraform 的原因如下:
- 与 Google Cloud 有很好的集成,Google 有专门的团队处理集成事宜。
- 提供声明式配置语言来描述云资源及其关系,只需描述所需状态,Terraform 会自动确定要运行的命令,从而创建、更新或删除云资源。
- 支持其他云提供商,学习的技能具有可迁移性。
- 将一切建模为资源的方式在学习时很有用。

10. 安装 Terraform

要使用相关示例,需要安装 Terraform 命令行工具。安装步骤如下:
1. 访问 terraform.io 并按照说明安装 Terraform CLI,确保安装 0.12 或更高版本。
2. 如果你使用 macOS 且是 Homebrew 用户,可以使用以下命令安装:

brew install terraform
  1. Terraform 需要使用你的凭据与 Google Cloud 通信,建议使用应用默认凭据(ADC)。可以使用以下命令创建凭据:
gcloud auth application-default login

不建议在本地机器上创建服务账户并下载其密钥文件,因为如果密钥丢失,他人可能会利用它破坏你使用 Terraform 管理的所有资源并创建新资源。例如,有团队成员将服务账户密钥文件放在源代码目录中,与 Terraform 配置文件相邻,创建存储库并将源代码推送到 GitHub 时,忘记将存储库设为私有,结果有人找到密钥文件并用于创建强大且昂贵的虚拟机进行比特币挖矿。

11. 不同的基础设施管理工作流

管理云资源有三种不同的工作流,如下所示:

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    A([手动管理]):::startend --> B(使用 gcloud 命令行或 Web 控制台进行一次性更改):::process
    C([自动化管理]):::startend --> D(使用 Ansible 等工具管理多个相似环境):::process
    E([基础设施即代码]):::startend --> F(定义云资源的期望状态,使用管理工具实现):::process
  • 手动管理 :如前面章节所示,使用 gcloud 命令行或 Web 控制台进行一次性更改,适用于复杂度较低的小型项目。
  • 自动化管理 :在管理多个相似环境(如暂存、生产和开发环境)时,自然会增加自动化以提高更改效率,像 Ansible 这样的工具可以帮助将此工作流扩展到更多环境和更大的系统。
  • 基础设施即代码 :不再考虑发送哪些命令来进行更改,而是思考定义云资源的期望状态。当需要进行更改时,编辑源代码并交给管理工具,由其决定如何将云资源调整到期望状态。
12. 何时不使用基础设施即代码

如果你觉得 IaC 令人望而却步,阻碍你开始项目,可以先不使用它。如果只需要一个服务、一个数据库和一个 Redis 实例,使用 IaC 可能不值得。但当你在团队中工作,拥有数十个或更多资源时,建议使用声明式基础设施。需要注意的是,在现有项目中开始使用 IaC 可能会有困难。有人习惯在一次性项目中使用 Web 控制台和 gcloud CLI 进行快速原型开发,但对于长期项目,建议从一开始就使用 IaC。

云任务调度与基础设施即代码:Cloud Tasks 与 Terraform 实战

13. Terraform 配置语言与资源描述

Terraform 使用声明式配置语言来描述云资源及其关系。在描述云资源时,你可以清晰地定义所需的资源状态,而无需关注具体的创建步骤。例如,以下是一个简单的 Terraform 配置示例,用于创建一个 Cloud Run 服务:

provider "google" {
  project = "your-project-id"
  region  = "your-region"
}

resource "google_cloud_run_service" "example_service" {
  name     = "example-service"
  location = "your-region"

  template {
    spec {
      containers {
        image = "gcr.io/cloudrun/hello"
      }
    }
  }
}

在这个示例中:
- provider 块指定了要使用的云提供商(这里是 Google Cloud),并设置了项目 ID 和区域。
- resource 块定义了要创建的资源类型( google_cloud_run_service )和资源名称( example_service )。
- template spec 部分进一步配置了 Cloud Run 服务的容器镜像。

14. 部署 Cloud Run 服务的 Terraform 流程

使用 Terraform 部署 Cloud Run 服务的具体步骤如下:
1. 初始化 Terraform 工作目录
在包含 Terraform 配置文件的目录中,运行以下命令初始化 Terraform 工作目录,该命令会下载所需的提供者插件:

terraform init
  1. 查看计划
    运行以下命令查看 Terraform 计划,该计划会显示将要创建、更新或删除的资源:
terraform plan

这一步可以让你在实际执行更改之前预览更改内容。
3. 应用更改
确认计划无误后,运行以下命令应用更改,Terraform 会根据配置文件创建或更新资源:

terraform apply

在执行此命令时,Terraform 会提示你确认操作,输入 yes 即可开始执行。

15. 服务器less 项目中的基础设施类型

在典型的服务器less 应用程序中,通常会涉及以下四种类型的基础设施:
| 基础设施类型 | 描述 |
| ---- | ---- |
| 托管服务配置 | 如数据库(Cloud SQL、Memorystore 等)、消息系统(Pub/Sub)和存储(Cloud Storage)的配置。 |
| Cloud Run 服务配置 | 包括资源限制、环境变量、与容器镜像的链接等。 |
| 服务账户和 IAM 访问策略 | 用于控制不同服务和资源之间的访问权限。 |
| 网络资源 | 用于与使用私有网络进行连接的服务交互,如 VPC 连接器。 |

16. Terraform 的优势与局限性

Terraform 具有以下优势:
- 声明式配置 :只需描述期望的资源状态,Terraform 会自动处理资源的创建、更新和删除,减少了手动操作的复杂性。
- 多云支持 :支持多个云提供商,学习的技能具有通用性,方便在不同云环境中迁移和使用。
- 版本控制友好 :可以将 Terraform 配置文件放入版本控制系统,方便团队协作和管理变更。

然而,Terraform 也存在一些局限性:
- 缺乏细粒度控制 :由于采用声明式方法,对于一些需要逐步滚动更新的操作(如 Cloud Run 服务的新版本部署),Terraform 可能无法提供精细的控制。
- 学习曲线 :对于初学者来说,理解 Terraform 的配置语言和资源模型可能需要一定的时间和精力。

17. 总结

通过本文,我们了解了如何使用 Cloud Tasks 客户端库调度任务,包括添加任务到队列、处理自动 ID 令牌、连接工作器、测试应用以及队列配置等方面的内容。同时,我们也深入探讨了基础设施即代码的概念,重点介绍了 Terraform 这一工具。

在云任务调度方面,我们掌握了使用 Cloud Tasks 进行任务调度的具体步骤和注意事项,如设置调度截止时间、处理重试和速率限制等。在基础设施即代码方面,我们学习了 Terraform 的安装、配置和使用,以及如何使用它来部署 Cloud Run 服务。

在实际项目中,建议根据项目的规模和复杂度选择合适的任务调度和基础设施管理方法。对于小型项目,可以先采用手动或自动化的方式进行管理;而对于大型项目或需要团队协作的项目,基础设施即代码(如 Terraform)是一个更好的选择,它可以提高项目的可维护性、可重复性和协作效率。

希望这些知识能够帮助你更好地管理云任务和基础设施,提升项目的开发和运维效率。在未来的实践中,不断探索和应用这些技术,以适应不断变化的云环境和业务需求。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值