サーバーレスWebAPI開発に入門しようとしたけどうまくいかなかった話
AWS DAVの勉強をしていたら、Lambdaを使えばとても簡単にWebAPIが作れてしまうのでは?と感じたので、 ググって最初にヒットしたこちらの記事を参考に、サーバーレスWebAPIを作ろうとしたらうまくいかなかった話です。
なお、Terraformを使ったインフラ構築は特に詰まることも無かったので本記事では触れません。
そもそも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
を作成。
cpp-learning.com
フォルダ構成
. ├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コマンドでインストール可能なパッケージはこちらのサイトから検索できます。
Alpine Linux packages
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%になるのは怖いですね。
参考
開発環境系
- dockerでgo開発環境構築
- 【Go言語(Golang)】WSL2とDockerで最高のGo開発環境をつくる|はやぶさの技術ノート
- AWS CLI v2 をdockerで使えるようにする
- Alpine ベースのコンテナイメージで AWS CLI v2 を使う - 理系学生日記
- 【Docker】docker-composeでlocalstackのコンテナを立てる | IT土方の奮闘記
Alpine Linux系
- Alpine Linuxのapkコマンドでインストール可能なパッケージを検索する方法 | ゲンゾウ用ポストイット
- 【Golang】Alpine Docker で実行すると error: stdlib.h: No such file or directory. "stdlib.h" が足りないと言われる - Qiita
- alpineのイメージでAWS Lambda用のgoバイナリをビルドしたらPathErrorになった話 - Qiita