AWS DAV の勉強をしていたら、Lambda を使えばとても簡単に WebAPI が作れてしまうのでは?と感じたので、ググって最初にヒットしたこちらの記事を参考に、サーバーレス WebAPI を作ろうとしたらうまくいかなかった話です。
なお、Terraform を使ったインフラ構築は特に詰まることも無かったので本記事では触れません。

LambdaとGoを使ったサーバーレスWebAPI開発実践入門 | フューチャー技術ブログ
そもそも Windows の開発環境で無理やりやっている事が原因だと考えていますが、
Dockerfile の書き方とか色々調べてて勉強になったので書き残しておきます。
記事の内容が間違っているぞということが主旨ではないです。
開発環境
- Windows 10 Home(20H2)
- WSL2
- Docker Desktop
- Visual Studio Code
- Remote - Containers 拡張
読みにくいかもしれませんが、以下にやったことを時系列順に書いていきます。
Docker コンテナ上に Golang 開発環境を作る
最初は Windows 上で作業していたのですが、Makefile 中のコマンドを Windows のコマンドに置き換える事がうまくできなかったため、 Docker コンテナ上に Golang 開発環境を作ることにしました。
こちらの記事を参考に、Dockerfile
とdocker-compose.yml
を作成。

【Go言語(Golang)】WSL2とDockerで最高のGo開発環境をつくる
フォルダ構成
.
├build
│└─Dockerfile
├cmd
├gen
├testdata
└docker-compose.yml
Dockerfile
# goバージョン
FROM golang:1.17.5-alpine
# 前提パッケージのインストール
RUN apk add --update && apk --no-cache add git curl zip unzip sudo binutils make alpine-sdk build-base
ENV GLIBC_VER=2.34-r0
# install glibc
RUN curl -sL https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub
RUN curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-${GLIBC_VER}.apk
RUN curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk
RUN apk add --no-cache glibc-${GLIBC_VER}.apk glibc-bin-${GLIBC_VER}.apk
# aws cli v2 のインストール
# https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv2-linux.html
RUN curl -sL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
RUN unzip -q awscliv2.zip
RUN sudo ./aws/install
RUN go get -u github.com/go-swagger/go-swagger/cmd/swagger
コンテナは軽量なほうがいいだろうと、ベースイメージには Alpine Linux を選択。
後々 Golang をビルドする時に『stdlib.h が足りない』と怒られるため、alpine-sdk
とbuild-base
をインストール。go get
の裏では git が動いているようなので、git
も前提パッケージとなります。
また、AWS CLI をインストールしたいが、Alpine Linux ではそのまま
sudo ./aws/install
してもうまくいかないためglibc
をインストールした上で AWS CLI をインストールしてます。
apk コマンドでインストール可能なパッケージはこちらのサイトから検索できます。
docker-compose.yml
version: "3"
services:
aws-sdk-go-container:
build: # ビルドに使うDockerファイルのパス
context: .
dockerfile: ./build/Dockerfile
container_name: aws-sdk-go-container
volumes: # ホストのAWS認証情報を共有する
- "~/.aws:/root/.aws"
# LocalStack
localstack:
image: localstack/localstack:latest
environment:
- SERVICE=dynamodb
- DEFAULT_REGION=ap-northeast-1 # リージョンを設定
ports:
- 4566:4566 # サービスへのアクセスポートは4566
volumes
ではホスト側のC:\Users\<ユーザ名>\.aws
に置かれている AWS 認証情報を、
コンテナから探しにいけるようにしています。
また元記事ではdocker run
コマンドで LocalStack を起動していますが、
せっかく開発環境をコンテナ上に構築しているので、
あわせて起動するようdocker-compose.yml
に記述します。user_handler_test.go
の dbEndpoint をhttp://localstack:4566
に書き換える事で
開発環境のコンテナから LocalStack のコンテナにアクセスできます。
curl コマンドを叩くと 502 が返ってきてお手上げに
コンテナ上でmake test
がうまくいったため、make deploy
して AWS にデプロイしました。
デプロイも成功したため、元記事の通り以下のコマンドを実行したところ、
502 InternalServerErrorException が返ってくるように。
curl -i https://${rest-api-id}.execute-api.ap-northeast-1.amazonaws.com/test/v1/users
AWS マネジメントコンソールから API Gateway の CloudWatch ログを有効化し、
ログを見てみるとno such file or directory: PathError
とのこと。
alpine のイメージで AWS Lambda 用の go バイナリをビルドしたら PathError になった話 - Qiita
ググって出てきたこちらの記事を参考に、Makefile 内のgo build
コマンドのオプションを書き換えて再デプロイ。
エラーメッセージがstring producer has not yet been implemented: apiError
に変わったけれど、
Swagger がよしなにやってくれている部分でエラーが出ているようで、写経しているレベルの初学者にはお手上げになりました。
WSL2 がホストのメモリを浪費する現象の対策
502 エラーに四苦八苦している時、PC のファンの音が大きくなり、ビルドに時間がかかるようになりました。
タスクマネージャーを開いてみると CPU、メモリ、ディスクが 100%近く張り付いています。
調べてみるとVmmem
というプロセスがメモリを浪費していました。
WSL2 によるホストのメモリ枯渇を防ぐための暫定対処 - Qiita
ググってみたところ、WSL2 の不具合のようでした。
こちらの記事を参考に暫定対処を行いましたが、メモリスワップが
発生すると SSD の I/O が 100%になるのは怖いですね。