ソースコードから理解する技術-UnderSourceCode

手を動かす(プログラムを組む)ことで技術を理解するブログ

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"
    }],
  (中略)
}