はじめに
この記事はBASEアドベントカレンダー8日目の記事です。
こんにちは、BASE 株式会社 BASE BANK Division でソフトウェアエンジニアをしています。
@glassmonkeyこと永野です。
最近ではAWS上にVPCから環境を作っては、壊したりしています。
今回の記事では、AWSのサービスを使ったアプリケーション開発における、開発者自身のPCにおける開発、いわゆるローカル環境での開発者体験をあげた話をします。
YELL BANKについて
私が担当しているサービスであるYELL BANKは、BASEでショップを運営しているオーナー様に「気軽な資金調達」を提供するプロダクトになります。
現在のYELL BANKのアーキテクチャは以下のように複数のシステムコンポーネントが組み合わさることで実現しています。インフラにはAWSを利用しています。
BASE株式会社 BASE BANKチーム紹介資料 - Speaker Deck
特にYELL BANKは様々な計算を常日頃を内部的に行っており、それらの算出された結果が「どう推移した?」「異常は無いか?」を意識することがサービス運営上必要です。
そこで内部的な計算結果を定期的に記録することが求められており、そのためにAmazon SQSやS3を使って簡単なログ収集基盤を作っています。
実際の施策の一例にはなりますが、過去にショップカルテなるものを作ったので良かったらご覧ください。
最近のYELL BANKにおける開発環境の課題
YELL BANKでは前述のシステム実現のために、システムコンポーネントはAmazon SQSやS3に依存したものになります。
実際にAWS上に展開されたアプリケーションだと大きな問題はないですが、開発者の手元のPCのローカル環境だとどうでしょうか?
真っ先に考えられる方法としては、開発環境のAWS環境を用意しておき、そこで開発用のIAMを発行してアクセスキー・シークレットキーを扱うという方法が考えられるのではないでしょうか?
当初は開発メンバーの規模も大きくはなかったので問題にはなってはいませんでしたが、最近は体制も代わり開発メンバーが増えたこともあり、開発用のAWS環境を共有する点がボトルネックになることが増えてきました。
基本的にIaCしているものの、開発環境用のIAMはIaCの対象外にしていたこともあり、作業が煩雑でオンボーディングでのボトルネックにもなっていました。
また、セキュリティ的にもいたずらにIAMを増やす点は好ましくないはずです。
ローカル環境用のエミュレータを用意する
チーム体制的にもローカル環境での開発がつらい状況になってきたので、ローカル環境でエミュータを立てる方向で対応しました。
今回ではLocalstackとminioを導入して解決を図りました。
LocalStackについて
LocalStackとはローカルPC上でAWS上の各サービスを再現するエミュレータサービスです。
Lambda, SQS, S3, Dynamoといったメジャーどころは一通りカバーしています。
最近めでたくv3が出ましたが、多機能で高性能です。
使い方は簡単で以下をcompose.ymlなどに追加するだけです。
環境変数などの各種設定に関しての詳細は公式ドキュメントをご確認ください。
localstack: image: localstack/localstack:3.0 healthcheck: test: [ "CMD-SHELL", "curl http://localhost:4566/_localstack/health" ] interval: 2s start_period: 20s retries: 30 timeout: 30s ports: - "4566:4566" volumes: - localstack:/var/lib/localstack environment: - USE_SINGLE_REGION=1 - PERSISTENCE=1 - TZ=Asia/Tokyo
これにより、各種コンテナからはlocalstack:4566(host上ではlocalhost:4566)に各種向き先を変えることでローカル環境上で各種AWS操作が可能になります。
例
aws s3 ls --endpoint localhost:4566
ただし、無料版と有料版でカバーしている機能に差があり、
そのなかでS3の永続化は無料版だと対応していないことがわかりました。 その他の各プランごとの機能のカバー範囲については公式のAWS Service Feature Coverageをご覧ください。
MinIO について
YELL BANKのシステムは、S3上でデータを加工して利用者に提示するといった機能が多く、s3の永続化は死活問題といえました。
そこでLocalStackとは別にs3 api互換のminioを採用しました。 主な決め手はローカルスタックと同じようにendpointを変えるだけで気軽に立ち上げることができる点でした。
MINIO_ROOT_USER
はAWS_ACCESS_KEY_IDに、MINIO_ROOT_PASSWORD
はAWS_SECRET_ACCESS_KEYに対応します。
minio: image: minio/minio:latest healthcheck: # init スクリプトが完了する前に app が起動しないよう ヘルスチェックする test: [ "CMD-SHELL", "curl http://localhost:9000/minio/health/liveh" ] interval: 2s start_period: 20s retries: 30 timeout: 30s command: ['server', '/data', '--console-address', ':9001'] ports: # 管理画面にアクセスできる - "9001:9001" - "9000:9000" environment: - MINIO_ROOT_USER=dummy-accesskey - MINIO_ROOT_PASSWORD=dummy-secretkey volumes: - ./services/infra/data/:/data
ローカルで利用するときは以下のようなコマンドでs3 コマンドを各種利用することができます。
aws s3 ls --endpoirnt localhost:9000
また9001番ポートでも管理画面が用意されており、
IDにはMINIO_ROOT_USER
で設定した値、パスワードにはMINIO_ROOT_PASSWORD
を利用することで気軽に確認が可能です。
簡単にブラウズすることができ、アップロードされたファイルの内容も以下のように確認することができます。
変更後の影響
各種アプリケーション上で、AWSの処理を呼び出しを行っている点は変更対象になります。
基本的にはAPIコールのエンドポイントを、明示的に環境変数で設定することで実現しました。
たとえば Goのアプリケーションのaws sdk-v2の場合は以下のような形です。
client := s3.NewFromConfig(cfg, func (o *svc.Options) { o.BaseEndpoint = aws.String(os.Getenv("ENDPOINT")) })
この変更に関してはオンボーディングタスクを兼ねて、新しくチームに異動してきた@gatchan0807にやっていただきました。
詳細は明日の記事の「フルサイクルエンジニアリングの第一歩を進める - BASE BANKでの新たな挑戦」で紹介されるはずです。乞うご期待!!
この対応で、当初の課題だったローカル環境の開発環境の悪さやオンボーディング時の複雑さの解消は無事に達成することができました。
最後に
クラウド技術が便利になってきた昨今ですが、ローカルの開発者体験まで含めて技術選定することはなかなか難しいように思います。
今回のケースではエミュレータで頑張る方針取りましたが、IaCを頑張って個人ごとに環境をつくるという方法も取るといった他のアプローチも考えられはします。
皆さんはどういった方法を取っていらっしゃるでしょうか?
日々の開発者体験向上や、クラウドネイティブなアプリケーション作りにもっと邁進していきたいところですが、全然人が足りていない状況です。
よかったら@glassmonkeyまでDMやカジュアル面談含めてお待ちしています!!