Amplify Gen2ならCDKで自由にカスタムできる。と思っていました。
結論から言うと、現時点でのAmplify Gen2はコンテナ(というかdockerコマンド)との相性が非常に悪いと思われます。dockerが使えないことで、PythonのLambdaをデプロイするのにも苦戦しました。
Amplify Gen2とは
Amplify Gen2は、フルスタックのTypeScript開発体験を提供するAWS Amplifyの最新バージョンです。
従来のAmplifyよりも、開発体験が進化しており、特にバックエンド開発において以下のようなことができます。
- CDKによるAWSリソースのデプロイが可能
- AWS上にサンドボックス環境を容易に構築(と削除)が可能
ということなので、Gen2ならCDKでできることは拡張可能でしかもdeployが容易だと思っていました。が、ハマりました。
やろうとしたこと
PythonのライブラリであるFastAPIで作ったAPIをLambdaにDeployしようとしました。
AmplifyはTypeScriptで、FastAPIはPythonなので言語が違いますが、Amplify Gen2はCDKを書けるので問題ないだろうと思っていました。
FastAPIをLambdaで動かすために次の2案を考えました。
- APIをコンテナ化した上で、
Lambda Web Adapter
を使ってLambda上で動くようにする。 -
Mangum
を使ってFastAPIをLambda上で動くようにした上で、CDKのaws-lambda-python-alpha
でデプロイする案
両方ともデプロイ時にdockerが必要になるのですが、AmplifyのCI/CD環境でdockerを使うことができずにAPIをデプロイすることができませんでした。
(1は当然dockerに依存しているとしても、2でも必要なのはびっくりしました。実行環境はFaaSですが、Pythonのパッケージを扱う環境を固定するためにdeploy時にdockerを使っているみたいです。)
回避策
最初はCI/CD環境でdockerコマンドを使えるようにできないか挑戦してみましたが、あきらめました。
以下の回避策により、なんとかFastAPIで作ったPythonのAPIをLambdaにDeployできました。
-
Mangum
を使ってLambda上でFastAPIを動くようにする - こちらのドキュメントを参考に必要なライブラリを集めるスクリプトを書いて、deploy前に実行する
- CDKの
lambda.Function
を使って、ソースコードと2で集めたライブラリをzipに固めてLambdaにDeployする
2の部分についてスマートではないので良い方法があれば差し替えをしたいですが、この方法ならdockerなしでPythonのLambdaをデプロイできました。
Amplify Gen1のコンテナAPIについて
Amplifyに詳しい方なら「AmplifyってGen1時代からコンテナAPIのデプロイできるよね?同じ方法でやればいいのでは?」と考えるかと思います。
私も多分できるのではないかと思います。ですが、Amplify Gen1のコンテナAPIはCodePipeline + CodeBuildを使っているのですよね。わざわざCDKでCodeBuild作ってAmplifyの環境からDeployを実行するのはちょっとツラいです。そこまでするなら最初からCDK+CodebBuildだけでいいのでは?と思ってしまいます。ということで最終手段としては考えられますができれば避けたく、今回はコンテナ自体を使わない方向に逃げました。
AmplifyのCI/CD環境について
「CI/CD環境を使うのがそんなに大変なら、とりあえず手動でDeployしちゃえばいいじゃない?ローカル環境ならDocker使えるのでしょ?」と思うかもしれません。
しかし、Amplify Gen2では本番DeployはCI/CD環境からのみ実施する思想で作られています。ローカル環境でデプロイを実行しようとすると、エラーで終了してしまいます。
$AWS_PROFILE=sandbox npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID
ampx pipeline-deploy
Command to deploy backends in a custom CI/CD pipeline. This command is not inten
ded to be used locally.
(略)
Error: It looks like this command is being run outside of a CI/CD workflow. To deploy locally use `amplify sandbox` instead.
ローカルからamplify sandbox
で作った開発用のSandbox環境を無理やり本番で使ったり、環境変数CI=true
設定してCI/CD環境に成り済ましてdeployする抜け道も考えられますが、好ましくはないですよね。
ですので、Amplify Gen2でCI/CD環境からDeployが通らないというのは、かなり致命的に困る状況になります。ローカルでの開発はできるけど、本番デプロイができないということですからね。
デプロイ時のログについて
Amplify Gen2のバックエンドは通常以下のコマンドでデプロイします。
npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID
このコマンドですが、困ったことにエラーが起きてもログが殆ど出ないです。しかも、AmplifyのCI/CDのログではバックエンドのビルドに失敗しても「Next.jsのSSRの設定を確認しよう」的なメッセージを出ます。私はエラーログが出てないこととこのメッセージに騙されてフロントエンドを作り直しました。
そういった悲劇を回避するためにバックエンドのdeployには--debug
オプションをつけておくことをおすすめします。
npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID --debug
--debug
をつけないとエラーログが出ないっておかしくないですか。。。?
Amplify Gen2で困ったことまとめ
今回Amplify Gen2を使ってみて困ったことをリストアップすると以下のようになります。
CI/CD環境でdockerコマンドが使えない
dockerコマンドが使えないのでECSやAppRunnerに活用できないのはもちろんですが、CDKは意外と他にもdockerに依存しているコンストラクトが多いので、コンテナを使ってないアプリでも思わぬところでハマります。PythonのLambdaとかがそうですね。
CI/CD環境からでないと本番デプロイができない
基本はCI/CD環境からしかデプロイしないようにする設計は賛成なのですが、なんだかんだで本番対応の時って、緊急で人がなんとかしないといけないことってありますよね。
何かあったときにローカル環境からデプロイできないのは、致命的な問題に成りかねないと思いました。
Amplify Gen2の情報が、まだ少ない
dockerコマンドが使えないって結構問題になりそうだと思うのですが、探しても全然情報が出てこなかったです。
更にいうと、Amplify Gen2のCI/CD環境のOSがAmazon Linux 2023なんですけどやっぱり情報が少ないですし、CI/CD環境を差し替えるとしてもAmplifyのカスタムイメージの情報も少ないです。つまり問題発生時の調査の難易度がかなり高いです。
結論
Amplify Gen2はCDKを書けるので拡張性が凄い!と思っていたのですが、結構罠がありそうです。ドキュメントに書いてあること以上のことには慎重になったほうが良さそうです。また、あくまでTypeScriptのフルスタック開発用のサービスなので、他の言語を使うときも注意したほうが良さそうです。
なお、今回は上手くいかなかったことを記事を書いたので後ろ向きな内容になっていますが、Amplify Gen2の開発体験自体はとても良いので、素直にTypeScriptでWebアプリを作る時はとても有用なサービスだと思っています。
追記(2024/09/03)
GitHub Actionsを使ってAmplify Gen2にコンテナでコンテナを使ったアプリをデプロイする記事を書きました。
![NCDCエンジニアブログ](https://storage.googleapis.com/zenn-user-upload/avatar/3a86a409d3.jpeg)
NCDC株式会社( ncdc.co.jp/ )のエンジニアチームです。 募集中のポジションや、採用している技術スタックの紹介などはこちらをご覧ください! github.com/ncdcdev/recruitment
Discussion
の手順でdocker使えるContainer Imageを設定してあげれば可能かもしれません。
(的外れなコメントでしたらすみません)
コメントありがとうございます。
その通りなのですが、カスタムイメージで単純にdockerコマンドを使える状態にしても Docker デーモンが起動してくれなかったです。
難易度も高いし、とりあえずやりたいことはdockerなしでできたので、一旦諦めました。。。
カスタムイメージでdindできるDockerイメージを設定しても、Amplifyのビルド設定でDockerを特権モードで動かす方法が現状ないですね...
やっぱりそうですよね。。。
dockerでイメージのビルドが必要な場合はカスタムパイプラインを使う方法でデプロイすることになると思います。
ちょうど、そのパターンを試したときの資料も公開したのでご参考に。コメントと情報ありがとうございます。
やっぱりCodePilelineとかCodeCatalystとかGitHub Actions等の他のCI/CD環境を使わないとできないということになるのですね。今度カスタムパイプラインを試してみます。
しかし、そうなると現時点でコンテナが絡む場合の技術選定をする場合、バックエンドもAmplifyでカスタムパイプラインを使うかAmplifyを使わないで素のCDKでいくと判断するか悩ましいところですね。。。