ちょっと話題の記事

Go言語のマルチクラウド開発ライブラリ「Go Cloud」のAWS対応を試す

Go言語のマルチクラウド開発のためのライブラリとツールである「Go Cloud」のAWS対応を試してみました。
2018.09.10

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

AWS事業本部プロダクト開発グループのshoito(しょいと)です。

Go言語のマルチクラウド開発のためのライブラリとツールである「Go Cloud」のAWS対応を試してみました。

なお、2018年9月10日時点では、プロジェクトのステータスはまだアルファであり、APIには破壊的変更がありえるので、プロダクションには適していません。

https://github.com/google/go-cloud#project-status

検証環境

  • macOS High Sierra 10.13.2
  • Docker Community Edition 18.06.1-ce-mac73 (26764)
  • Terraform v0.11.8
  • Go 1.11 darwin/amd64
  • AWS CLI 1.16.1
  • Google Cloud SDK 215.0.0

Go Cloudとは

Go Cloudは、Go言語でポータブルなクラウドアプリケーションが開発できるように、クラウドプロバイダ間で使用頻度の高いサービスの汎用APIの開発を目指しています。 Go Cloudは、そのためのライブラリやツールを提供してくれます。

具体的には、S3のようなオブジェクトストレージ、RDB(MySQL)、リクエストログ、トレースのための汎用APIなどです。 2018年9月7日時点では、AWSとGCPの一部サービスに対応しています。

Package cloud contains a library and tools for open cloud development in Go. https://godoc.org/github.com/google/go-cloud

Go Cloudのインストール

https://github.com/google/go-cloud のREADMEを参考に進めます。 まず、以下のように go-cloudwirego get します。

$ go get github.com/google/go-cloud
$ go get github.com/google/go-cloud/wire/cmd/wire

wire はコードジェネレータであり、使用するクラウドプロバイダのSDKのみインポートするコードを生成します。

samples/guestbook にある wire_gen.go が生成されるコード例です。 コードの詳細はThe Go Blogの Portable Cloud Programming with Go Cloud が参考になります。

今回デプロイしたサンプル

今回は samples/guestbook をビルドし、AWSとGCPの環境にデプロイしてみました。 https://github.com/google/go-cloud/tree/master/samples/guestbook

samples/guestbook はAWS、GCP、ローカルの環境で実行できるゲストブックアプリケーションです。

google/go-cloudリポジトリでは、サンプルアプリケーションとして、 samples/tutorialsamples/guestbooksamples/wire を提供しています。

サンプルのビルド&デプロイのための前提条件

Go、Go Cloud、Wire以外には、以下のインストールが必要です。

  • Docker
  • Terraform
  • AWS CLI(AWSにデプロイする場合)
  • Google Cloud SDK(GCPにデプロイする場合)

まずはローカル環境で動作確認

samples/guestbook のREADMEを参考にローカル環境で動作確認をします。

$ cd ~/go/src/github.com/google/go-cloud/samples/guestbook
$ GO111MODULE=on go build

Go 1.11から試験的に導入されているModulesにより、go buildを実行する際に、自動的に依存ライブラリをダウンロードしてビルドしてくれます。

ビルド後は、ローカルでMySQLサーバコンテナを起動します。

$ GO111MODULE=on go run localdb/main.go

次に別のターミナルでゲストブックのサーバプログラムを起動します。

$ echo 'Hello, World!' > motd.txt
$ ./guestbook -env=local -bucket=blobs -motd_var=motd.txt

これでローカルで起動したので http://localhost:8080/ にブラウザからアクセスすると、ゲストブックアプリケーションが表示されます。

なお、 motd.txt は管理者用のメッセージとして使用されています。

AWS環境にデプロイして試してみる

次に、今回の目的であるAWS環境へのデプロイを試します。 こちらもローカル環境で試した際と同様にREADMEの手順を参考にします。

まずはAWS CLIとSSHの下準備。 既に他で実施済みであれば不要です。

$ aws configure
$ ssh-add

サンプルではAWS MarketplaceにあるDebian提供のAMIにデプロイするため、AMD64ビットベースのLinux向けにビルドします。

$ GO111MODULE=on GOOS=linux GOARCH=amd64 go build

次に、terraformでAWS環境にデプロイするのですが、ここではREADMEとは別に terraform apply 時のリージョンを region=us-west-1 (米国西部 (北カリフォルニア))から region=ap-northeast-1 (東京)へ変更しています。

ssh_public_key は後でEC2インスタンスにssh接続し、サーバプログラムを起動するために必要となります。

$ cd aws
$ terraform init
$ terraform apply -var region=ap-northeast-1 -var ssh_public_key="$(cat ~/.ssh/id_rsa.pub)"

AWS Marketplaceで Debian GNU/Linux 9 (Stretch) の利用に同意していない場合、以下のようなエラーが発生し、デプロイに失敗してしまうので、メッセージに記載のURLにブラウザからアクセスして同意後、上記の terraform apply を再度実行します。

* aws_instance.guestbook: 1 error(s) occurred:

* aws_instance.guestbook: Error launching source instance: OptInRequired: In order to use this AWS Marketplace product you need to accept terms and subscribe. To do so please visit https://aws.amazon.com/marketplace/pp?sku=55q52qvgjfpdj2fpfy9mb1lo4
    status code: 401, request id: XXXX-XXXX-XXXX-XXXX-XXXX

Terraform does not automatically rollback in the face of errors.
Instead, your Terraform state file has been partially updated with
any resources that successfully completed. Please address the error
above and apply again to incrementally change your infrastructure.

terraform apply によるデプロイが完了すると、以下のように構築されたS3バケットやRDS、EC2インスタンスの情報などが出力されます。

Apply complete! Resources: 13 added, 0 changed, 0 destroyed.

Outputs:

bucket = guestbook[timestamp]
database_host = guestbook[timestamp][redacted].[region].rds.amazonaws.com
database_root_password = <sensitive>
instance_host = [redacted]
paramstore_var = /guestbook/motd
region = [region]

次にinstance_host(EC2)に接続して、サーバプログラムを実行します。 -bucket, -db_hostterraform apply の出力結果で適宜置き換えてください。

local$ ssh "admin@$( terraform output instance_host )"
server$ AWS_REGION=ap-northeast-1 ./guestbook -env=aws \
  -bucket=guestbook[timestamp] \
  -db_host=guestbook[timestamp][redacted].[region].rds.amazonaws.com \
  -motd_var=/guestbook/motd

これでデプロイ&起動が完了したので、ブラウザで http://INSTANCE_HOST:8080/ を開きます。

しかし、ローカル環境と同様にゲストブックアプリケーションが開くと期待していたのですが、手元で試したところ正常に動きませんでした。
サーバのログを見ると以下のようなログが出力されており、必要なDBユーザーが作られていませんでした。

2018/09/07 14:48:43 main page SQL error: Error 1045: Access denied for user 'guestbook'@'' (using password: YES)

samples/guestbook/roles.sql にユーザー作成用のSQLがあるので、そちらを実行すると、正常にゲストブックアプリケーションが動きました。

最後に

今回はGo CloudのAWS対応を samples/guestbook を実際にビルド&デプロイして確認しました。
samples/guestbook/main.go を見ると分かるのですが、AWS環境依存のコードはありません。 Go Cloudが aws-sdk-go のAPIをラップし、汎用APIを提供することでクラウド環境に依存しない方法で記述できます。
GCP環境へのデプロイもAWS環境と同様にREADMEを参考に試したので、別の機会にまとめます。

AWSとGCPで、それぞれ多くのサービスを提供しているので、どこまで汎用APIを提供できるのか、またAzureなど他のクラウド環境への対応がどうなっていくのか、Go Cloudの動きはウォッチしておこうと思います。

参考資料