> Source: https://www.ymotongpoo.com/works/goblog-ja/go-cloud/


# Go Cloudによるポータブルなクラウドプログラミング

[Portable Cloud Programming with Go Cloud](https://go.dev/blog/go-cloud) by Eno Compton and Cassandra Salisbury

## はじめに

本日、GoogleのGoチームは新しいオープンソースプロジェクトである[Go Cloud](https://github.com/google/go-cloud)をリリースします。これは[オープンクラウド](https://cloud.google.com/open-cloud/)上での開発のためのライブラリとツール群です。このプロジェクトを通じて、私たちはGoをポータブルなクラウドアプリケーションを構築する開発者にとって第一の選択肢となる言語にすることを目指しています。

この記事では、私たちがこのプロジェクトを始めた理由、Go Cloudがどのように動作するかの詳細、そしてどうすれば参加できるかを説明します。

## なぜ今、ポータブルなクラウドプログラミングなのか

現在、世界中に[100万人以上](https://research.swtch.com/gophercount)のGo開発者がいると私たちは見積もっています。GoはKubernetes、Istio、Dockerをはじめとする、最も重要なクラウドインフラストラクチャプロジェクトの多くを支えています。Lyft、Capital One、Netflix、そして[その他多数](https://go.dev/wiki/GoUsers)の企業が本番環境でGoに依存しています。長年にわたり、私たちは開発者が効率性、生産性、組み込みの並行処理、そして低レイテンシを理由にクラウド開発にGoを愛用していることを見出してきました。

Goの急速な成長を支える取り組みの一環として、私たちはGoを利用しているチームにインタビューを行い、彼らが言語をどのように使っているか、そしてGoのエコシステムがさらにどう改善できるかを理解しようとしてきました。多くの組織に共通するテーマの一つが、クラウドプロバイダー間でのポータビリティの必要性です。これらのチームは、[マルチクラウド](https://en.wikipedia.org/wiki/Cloud_computing#Multicloud)や[ハイブリッドクラウド](https://en.wikipedia.org/wiki/Cloud_computing#Hybrid_cloud)環境で堅牢なアプリケーションをデプロイし、コードに大きな変更を加えることなくクラウドプロバイダー間でワークロードを移行したいと考えています。

これを実現するために、一部のチームはよりシンプルでポータブルなコードを生み出すべく、アプリケーションをプロバイダー固有の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は、Goアプリケーションを別のクラウドにデプロイする作業がシンプルになるように、クラウドプロバイダーを横断して最もよく使われるサービスに対するベンダーニュートラルな汎用APIを開発することを目指しています。Go Cloudはまた、他のオープンソースプロジェクトがプロバイダーを横断して動作するクラウドライブラリを書くための基盤にもなります。あらゆる種類やレベルの開発者からのコミュニティフィードバックが、Go Cloudにおける今後のAPIの優先順位を決める材料になります。

## どのように動作するのか

Go Cloudの中核にあるのは、ポータブルなクラウドプログラミングのための汎用API群です。ブロブストレージを使う例を見てみましょう。汎用型である[`*blob.Bucket`](https://godoc.org/github.com/google/go-cloud/blob#Bucket)を使えば、ローカルディスクからクラウドプロバイダーへファイルをコピーできます。まずは同梱されている[s3blobパッケージ](https://godoc.org/github.com/google/go-cloud/blob/s3blob)を使ってS3バケットを開くところから始めましょう。

```go
// setupBucket はAWSバケットを開きます。
func setupBucket(ctx context.Context) (*blob.Bucket, error) {
    // AWSの認証情報を取得します。
    sess, err := session.NewSession(&aws.Config{
        Region: aws.String("us-east-2"),
    })
    if err != nil {
        return nil, err
    }
    // s3://go-cloud-bucket へのハンドルを開きます。
    return s3blob.OpenBucket(ctx, sess, "go-cloud-bucket")
}
```

プログラムが `*blob.Bucket` を手に入れると、`io.Writer` を実装する `*blob.Writer` を作成できます。そこから、プログラムは `*blob.Writer` を使ってバケットにデータを書き込み、`Close` がエラーを報告しないことを確認できます。

```go
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`](https://godoc.org/github.com/google/go-cloud/blob/gcsblob#OpenBucket)を使って `*blob.Bucket` を構築することで、Google Cloud Storageを使うこともできます。

```go
// setupBucket はGCSバケットを開きます。
func setupBucket(ctx context.Context) (*blob.Bucket, error) {
    // GCSバケットを開きます。
    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
    }
    // gs://go-cloud-bucket へのハンドルを開きます。
    return gcsblob.OpenBucket(ctx, "go-cloud-bucket", c)
}
```

異なるクラウドプロバイダーでバケットにアクセスするには異なる手順が必要ですが、アプリケーションが使う結果の型はどちらも同じ `*blob.Bucket` です。これにより、アプリケーションコードはクラウド固有のコードから切り離されます。既存のGoライブラリとの相互運用性を高めるために、Go Cloudは `io.Writer`、`io.Reader`、`*sql.DB` といった確立されたインターフェースを活用しています。

クラウドサービスにアクセスするために必要なセットアップコードは、あるパターンに従う傾向があります。より基本的な抽象化からより上位の抽象化が組み立てられる、というパターンです。このコードは手で書くこともできますが、Go Cloudは**Wire**というツールを使ってこれを自動化します。Wireはクラウド固有のセットアップコードを生成してくれるツールです。[Wireのドキュメント](https://github.com/google/go-cloud/tree/master/wire)ではツールのインストール方法と使い方を説明しており、[Guestbookサンプル](https://github.com/google/go-cloud/tree/master/samples/guestbook)ではWireの実際の動作を確認できます。

## どうすれば参加でき、詳しく知ることができるか

はじめるには、[チュートリアル](https://github.com/google/go-cloud/tree/master/samples/tutorial)に沿って進め、その後実際に自分でアプリケーションを構築してみることをおすすめします。すでにAWSやGCPを使っているのであれば、既存アプリケーションの一部をGo Cloudを使うように移行できます。別のクラウドプロバイダーやオンプレミスのサービスを使っている場合は、ドライバーインターフェース（たとえば[`driver.Bucket`](https://godoc.org/github.com/google/go-cloud/blob/driver#Bucket)）を実装することでGo Cloudを拡張し、サポートを追加できます。

皆さんの経験についてのあらゆる意見を歓迎します。[Go Cloud](https://github.com/google/go-cloud)の開発はGitHub上で行われています。プルリクエストを含む貢献をお待ちしています。何を改善すべきか、プロジェクトが今後どのようなAPIをサポートすべきかについては、[イシューを立てて](https://github.com/google/go-cloud/issues/new)教えてください。プロジェクトに関する最新情報や議論については、[プロジェクトのメーリングリスト](https://groups.google.com/forum/#!forum/go-cloud)に参加してください。

このプロジェクトでは、貢献者にGoプロジェクトと同じContributor License Agreementへの署名を求めています。詳細については[コントリビューションガイドライン](https://github.com/google/go-cloud/blob/master/CONTRIBUTING.md)を参照してください。なお、Go CloudはGoの[行動規範](https://github.com/google/go-cloud/blob/master/CODE_OF_CONDUCT.md)の対象であることに注意してください。

Go Cloudについて知るために時間を割いていただきありがとうございます。私たちは、ポータブルなクラウドアプリケーションを構築する開発者にとってGoを第一の選択肢とすべく、皆さんとともに取り組んでいけることを楽しみにしています。

By Eno Compton and Cassandra Salisbury

