Go 博客

使用 Go Cloud 进行便携式云编程

Eno Compton 和 Cassandra Salisbury
2018 年 7 月 24 日

引言

今天,Google 的 Go 团队发布了一个新的开源项目,Go Cloud,这是一个用于在开放云上进行开发的库和工具。通过这个项目,我们的目标是让 Go 成为构建便携式云应用程序开发者的首选语言。

本文解释了我们为什么启动这个项目,Go Cloud 的工作原理细节,以及如何参与其中。

为什么需要便携式云编程?为什么是现在?

据估计,全球已有超过一百万 Go 开发者。Go 支持许多最关键的云基础设施项目,包括 Kubernetes、Istio 和 Docker。Lyft、Capital One、Netflix 和更多等公司都在生产环境中使用 Go。多年来,我们发现开发者喜爱 Go 进行云开发,因为它的效率高、生产力强、内置并发以及低延迟。

作为我们支持 Go 快速增长工作的一部分,我们一直在采访使用 Go 的团队,以了解他们如何使用这门语言以及 Go 生态系统如何进一步改进。许多组织面临的一个共同主题是跨云提供商的可移植性需求。这些团队希望在多云混合云环境中部署健壮的应用程序,并在不显著更改代码的情况下迁移其工作负载到不同的云提供商。

为了实现这一点,一些团队尝试将他们的应用程序与特定于提供商的 API 解耦,以生成更简单、更便携的代码。然而,在短时间内发布功能的压力往往会导致团队牺牲长期可移植性的努力。因此,大多数在云中运行的 Go 应用程序都与最初的云提供商紧密耦合。

作为替代方案,团队可以使用 Go Cloud,这是一套开放的通用云 API,来编写更简单、更便携的云应用程序。Go Cloud 还为构建在这些通用 API 之上的便携式云库生态系统奠定了基础。Go Cloud 使团队能够实现其功能开发目标,同时保持多云和混合云架构的长期灵活性。Go Cloud 应用程序还可以迁移到最能满足其需求的云提供商。

什么是 Go Cloud?

我们已经识别了云应用程序常用的服务,并创建了跨云提供商的通用 API。今天,Go Cloud 发布了对对象存储、MySQL 数据库访问、运行时配置以及配置了请求日志记录、跟踪和运行状况检查的 HTTP 服务器的支持。Go Cloud 支持 Google Cloud Platform (GCP) 和 Amazon Web Services (AWS)。我们计划与云行业合作伙伴和 Go 社区合作,尽快增加对其他云提供商的支持。

Go Cloud 旨在为云提供商中最常用的服务开发供应商中立的通用 API,从而使将 Go 应用程序部署到另一个云上变得简单易行。Go Cloud 还为其他开源项目编写跨提供商的云库奠定了基础。来自各种类型、各个级别的开发者的社区反馈将指导 Go Cloud 中未来 API 的优先级。

它是如何工作的?

Go Cloud 的核心是一系列用于便携式云编程的通用 API。让我们以使用对象存储为例。您可以使用通用类型*blob.Bucket 将文件从本地磁盘复制到云提供商。让我们从使用附带的s3blob 包打开一个 S3 存储桶开始。

// setupBucket opens an AWS bucket.
func setupBucket(ctx context.Context) (*blob.Bucket, error) {
    // Obtain AWS credentials.
    sess, err := session.NewSession(&aws.Config{
        Region: aws.String("us-east-2"),
    })
    if err != nil {
        return nil, err
    }
    // Open a handle to s3://go-cloud-bucket.
    return s3blob.OpenBucket(ctx, sess, "go-cloud-bucket")
}

一旦程序获得了一个 *blob.Bucket,它就可以创建一个 *blob.Writer,该接口实现了 io.Writer。然后,程序可以使用 *blob.Writer 将数据写入存储桶,并检查 Close 是否报告了错误。

ctx := context.Background()
b, err := setupBucket(ctx)
if err != nil {
    log.Fatalf("Failed to open bucket: %v", err)
}
data, err := ioutil.ReadFile("gopher.png")
if err != nil {
    log.Fatalf("Failed to read file: %v", err)
}
w, err := b.NewWriter(ctx, "gopher.png", nil)
if err != nil {
    log.Fatalf("Failed to obtain writer: %v", err)
}
_, err = w.Write(data)
if err != nil {
    log.Fatalf("Failed to write to bucket: %v", err)
}
if err := w.Close(); err != nil {
    log.Fatalf("Failed to close: %v", err)
}

请注意,使用存储桶的逻辑并不引用 AWS S3。Go Cloud 使替换云存储成为改变用于打开 *blob.Bucket 的函数的问题。该应用程序可以通过使用gcsblob.OpenBucket 构建一个 *blob.Bucket 来使用 Google Cloud Storage,而无需更改复制文件的代码。

// setupBucket opens a GCS bucket.
func setupBucket(ctx context.Context) (*blob.Bucket, error) {
    // Open GCS bucket.
    creds, err := gcp.DefaultCredentials(ctx)
    if err != nil {
        return nil, err
    }
    c, err := gcp.NewHTTPClient(gcp.DefaultTransport(), gcp.CredentialsTokenSource(creds))
    if err != nil {
        return nil, err
    }
    // Open a handle to gs://go-cloud-bucket.
    return gcsblob.OpenBucket(ctx, "go-cloud-bucket", c)
}

虽然访问不同云提供商的存储桶需要不同的步骤,但应用程序使用的最终类型是相同的:*blob.Bucket。这可以将应用程序代码与特定于云的代码隔离。为了增加与现有 Go 库的互操作性,Go Cloud 利用了诸如 io.Writerio.Reader*sql.DB 等成熟的接口。

访问云服务所需的设置代码通常遵循一个模式:更高层级的抽象是由更低层级的抽象构建的。虽然您可以手动编写这些代码,但 Go Cloud 使用 **Wire** 自动完成此操作,Wire 是一个为您生成特定于云的设置代码的工具。Wire 文档解释了如何安装和使用该工具,而Guestbook 示例展示了 Wire 的实际应用。

如何参与和了解更多信息?

要开始,我们建议您遵循教程,然后尝试自己构建一个应用程序。如果您已经在为 AWS 或 GCP 开发,可以尝试将现有应用程序的部分内容迁移到使用 Go Cloud。如果您使用的是不同的云提供商或本地服务,可以通过实现驱动程序接口(如driver.Bucket)来扩展 Go Cloud 以支持它。

我们非常感谢您关于使用体验的任何反馈。Go Cloud 的开发在 GitHub 上进行。我们期待您的贡献,包括 pull request。提交 issue 来告诉我们哪些方面可以改进,或者项目应该支持哪些未来的 API。有关项目的更新和讨论,请加入项目邮件列表

该项目要求贡献者签署与 Go 项目相同的贡献者许可协议。请阅读贡献指南了解更多详情。请注意,Go Cloud 遵循 Go 的行为准则

感谢您花时间了解 Go Cloud。我们很期待与您一起努力,使 Go 成为构建便携式云应用程序开发者的首选语言。

下一篇文章:Go 1.11 已发布
上一篇文章:走向 Go:Go 垃圾回收器的历程
博客索引