localstack と Visual Studio Code の Remote-Containers でAWSの開発環境を構築してみる
GitHub - localstack/localstack: 💻 A fully functional local AWS cloud stack. Develop and test your cloud & Serverless apps offline!
「localstack」というAWSを仮想的にローカルマシン内のDockerで動かすものがあります。
この「localstack」で起動した仮想のAWSに S3 バケットを作り、Visual Studio Code の Remote-Containers のGolangのコードから取得できる環境をつくってみました。
localstack、Remote-Containers を使うメリットは以下があると考えています。
- locakstackを使うことで実際のAWSに触る必要がない(つまり料金もかからない、credentialsの後述のとおりダミーで可能)
- Remote-Containers を使うことで開発言語毎の環境をローカルにインストールする必要がなくなる
今回はWindows 10 Pro、Dockerはインストール済、AWS CLIについてはローカルのWindowsにインストール済という状態で始めました。
以下、今回やったことの手順となります。
1. localstackの起動、S3バケットの用意
AWSを仮想的に動かすため、localstackを起動します。とはいっても git clone して Dockerで起動するだけです。以下になります。
$ git clone https://github.com/localstack/localstack
$ cd localstack
$ docker-compose up
起動したら(ローカルの) AWS CLIにlocalstackに接続するためのcredentialsを定義します。ここに記載するcredentialsのアクセスキー・シークレットキーはダミーで大丈夫なので、今回は「dummy」という値としました。以下をAWSの「credentials」ファイルに記載します。
[localstack] aws_access_key_id = dummy aws_secret_access_key = dummy
プロファイル名は「localstack」、アクセスキーとシークレットキーは先述の通りダミーの値です。この定義を使い、AWS CLIでバケットを作成してみます。
$ aws s3 mb s3://sample-bucket --endpoint-url=http://localhost:4566 --profile=localstack $ aws s3 ls --endpoint-url=http://localhost:4566 --profile=localstack
2. Remote-Containers
Golangの開発環境を用意し、先に作ったバケットにアクセスしてみます。開発環境の用意はいくつかやり方があるかと思いますが、今回は以下の公式のサンプルを git clone して、ソースを書き替えました。
https://github.com/microsoft/vscode-remote-try-go
$ git clone https://github.com/microsoft/vscode-remote-try-go
「vscode-remote-try-go」をVisual Studio Codeで開き、Remote-Containersでコンテナとして開くと、デバッグ実行や「go run」コマンドでソースの実行ができるはずです。
今回は先に用意したlocalstackの(仮想の)AWS環境にアクセスするため、「Dockerfile」に以下を追記して環境変数を追加しました。
ENV AWS_ACCESS_KEY_ID dummy ENV AWS_SECRET_ACCESS_KEY dummy ENV AWS_ENDPOINT "http://host.docker.internal:4566"
最初の2行はAWSのアクセスキーとシークレットキーですが、こちらもダミーの値で大丈夫です。これらがないと後述のGolangのソースを実行するときに「NoCredentialProviders: no valid providers in chain. Deprecated.」というエラーとなり、AWSにアクセスできなくなるので注意してください。
3行目はlocalstackで起動したローカルのAWSに接続するためのエンドポイントです。ポートはlocalstackで起動したコンテナのものとなり、先にAWS CLIをバケットを用意したときのエンドポイントと同じとなります。「host.docker.internal」ですが、これはGolangを実行するコンテナ内からホストマシンを参照すすためのものです。「localhost」とか書いてしまうと、Golangを実行するコンテナ自身を指してしまい、「localstack」のコンテナを見ることができなくなります。
最後にGolangのソースです。AWS SDK Goを使い、バケットの一覧を取得しています。今回は「main.go」という名前にしました。
package main import ( "fmt" "log" "os" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/s3" ) func main() { sess, err := session.NewSessionWithOptions(session.Options{ Config: aws.Config{ Region: aws.String("ap-northeast-1"), Endpoint: aws.String(os.Getenv("AWS_ENDPOINT")), }, }) if err != nil { log.Fatal(err) } svc := s3.New(sess) result, err := svc.ListBuckets(nil) if err != nil { log.Fatal(err) } fmt.Println(result) }
awsのConfigの作成で、環境変数の「AWS_ENDPOINT」を参照しているのが分かるかと思います。実案件では「AWS_ENDPOINT」があれば使い、なければ使わないというような処理になるかと思います。
実行すると以下のようにAWS CLIで作成したバケット名が見れると思います。
$ go run main.go { Buckets: [{ CreationDate: 2020-10-02 09:57:33.988551 +0000 UTC, Name: "sample-bucket" }], (中略) }