はじめに
最近AWS Amplifyにハマっているのですが、Pythonを使ったLambda関数を追加した際に、デプロイがうまくいかなかったので、その解決方法を共有します。
※画面は2023/12/04 時点のものです。
今回の問題
さて、今回の問題について最初に説明しておきます。
後述の手順「2.動作確認環境の作成」の最後で確認できますが、AmplifyプロジェクトにPythonを使ったLambdaを追加した後、AmplifyのCI/CD機能で自動ビルド&デプロイを実行すると、下記のエラーが発生します。
1 2 3 4 |
python3 found but version Python 3.7.15 is less than the minimum required version. You must have python >= 3.8 installed and available on your PATH as "python3" or "python". It can be installed from https://www.python.org/downloads You must have pipenv installed and available on your PATH as "pipenv". It can be installed by running "pip3 install --user pipenv". You must have virtualenv installed and available on your PATH as "venv". It can be installed by running "pip3 install venv". |
このエラーは、エラーメッセージで記載の通り、Pythonのバージョン問題に関するものです。
こちらの記事にも記載されていますが、
Amplify CLIで amplify add function してランタイムにPythonを選択すると、
内部的にはPython 3.8が選択されるようです。
一方、CI/CDで使用するAmazon Linux2でインストールされるPythonは3.7.4のため、
バージョンの不一致が起こってしまいます。
ことが原因のようです。
記事よりも若干バージョンが上がって、3.7.15になってますが、問題は同じです。
ただ、記事通りにPython3.8をインストールすれば良い話と思いきや、今回作成したLambdaはPython3.11であるため、そうもいきません。
解決方針
イメージとしては下図の通りです。
<現状イメージ>
<解決イメージ>
上図の通り、Cloud9でDockerイメージを作成し、カスタムビルドイメージとしてAmazon ECRのパブリックリポジトリに公開しています。
その後、Amplifyがカスタムビルドイメージを使ってビルド環境を構築し、Python3.11のLambdaを自動デプロイします。
解決手順
1.前提
今回は下記の前提で進めます。
- ローカルにNode.jsをインストールしている(npxコマンドが使える状態であること)
- ローカルにgitをインストールしている
- ローカルにamplify cliをインストールしている
- ローカルで自身の環境にあったamplify configureを行っている
- テスト用アプリのクライアントはReactで実装する
2.動作確認環境の作成
まずは必要な環境を作成します。
既に環境を作成済みの場合は飛ばして構いませんが、お手元の環境と異なる可能性がありますので、ご注意ください。
なお、基本的なAWSリソース作成手順は本記事の主旨から外れるため省略します。
公式手順や他の技術記事を参照してください。
- 【AWSコンソール】CodeCommitリポジトリを作成する
- 【ローカルのコマンドプロンプト】リポジトリをクローンする
- 【ローカルのコマンドプロンプト】下記コマンドでReactアプリプロジェクトを作成する
12cd クローンしたディレクトリnpx create-react-app .
- 【ローカルのコマンドプロンプト】下記コマンドでAmplifyプロジェクトを初期化する
1amplify init
実行時の設定は適宜行ってください。あくまで参考として、今回私は次のように設定しました。
12345678910? Enter a name for the project Amplifyプロジェクト名? Enter a name for the environment dev? Choose your default editor: Visual Studio Code? Choose the type of app that you're building javascriptPlease tell us about your project? What javascript framework are you using react? Source Directory Path: src? Distribution Directory Path: build? Build Command: npm.cmd run-script build? Start Command: npm.cmd run-script start - 【ローカルのコマンドプロンプト】下記コマンドでAmplifyプロジェクトにLambdaを追加
1amplify add function
こちらについてもランタイムが「Python」であること以外は適宜設定を行ってください。
先ほどと同様に参考として、今回私は次のように設定しました。123456789101112131415? Select which capability you want to add: Lambda function (serverless function)? Provide an AWS Lambda function name: Lambda関数名? Choose the runtime that you want to use: PythonOnly one template found - using Hello World by default.Available advanced settings:- Resource access permissions- Scheduled recurring invocation- Lambda layers configuration- Environment variables configuration- Secret values configuration? Do you want to configure advanced settings? No? Do you want to edit the local lambda function now? NoSuccessfully added resource Lambda関数名 locally. - 【ローカル】次の2つのファイルを修正する
※前述の通りAmplifyのLambdaはデフォルトがPython3.8となっています。
その設定を変更するため、Amplifyが自動生成した設定ファイルを編集します。<./amplify/backend/function/Lambda関数名/Lambda関数名-cloudformation-template.json>
123(省略)"Runtime": "python3.11", // 元は「python3.8」等になっている(省略)
<./amplify/backend/function/Lambda関数名/Pipfile>123(省略)[requires]python_version = "3.11" // 元は「3.8」等になっている - 【ローカルのコマンドプロンプト】下記コマンドでAmplifyプロジェクトの設定を反映する
1amplify push
- 【ローカルのコマンドプロンプト】CodeCommitリポジトリにソースコードをpushする
- 【AWSコンソール】Amplifyプロジェクトの設定を開き、CodeCommitの対象リポジトリおよびブランチを接続する
※IAMロールがない場合は適宜作成してください。
- 【AWSコンソール】接続後、自動CI/CDが実行され、今回のお目当てであるエラーが発生することを確認する
3.カスタムビルドイメージの作成
ようやく問題にたどり着けたので、解決方法の手順に移ります。
まずはカスタムビルドイメージを作成します。
今回はローカルの容量を圧迫したくなかったのと他に手元に良い環境がなかったため、Cloud9を新しく作成しました。
- 【AWSコンソール】ECRにてパブリックリポジトリを作成する
※作成後、「プッシュコマンドの表示」ボタンをクリックするとビルドやプッシュのコマンドが表示されます。
後の手順で使用するため、手元に控えておいてください。なお、このコマンドは後からでも参照可能です。
- 【AWSコンソール】Cloud9を作成(インスタンスタイプはm5.largeを指定)
- 【Cloud9】Dockerfileを作成
※カスタムビルドイメージの要件は公式ページにまとめられていますので、カスタマイズする際は参考にしてください。
※公式のGitHub issuesにあったのですが、Alpine LinuxはAmplifyのカスタムビルドイメージに対応していないようです。自動ビルド時に何のログも表示されずにエラーとなります。
おとなしく、Debianをベースにしましょう。(今回はDebian12のbookwormベースで実施)
※同じく公式のGitHub issuesより、Node.jsのバージョンが15以上だと自動ビルド時にエラーが発生するようです。それを回避するため、DockerfileにてNode.jsのバージョンを14に指定しています。<Dockerfile>
1234567891011121314151617181920212223242526# Python3.11をベースにするFROM python:3.11.6-bookwormRUN apt update && apt dist-upgrade -y# curlとgitとOpenSSHをインストールRUN apt-get install -y curl gitRUN apt-get install -y openssh-server# AWS Amplifyのカスタムビルドイメージ用の設定# Node.jsとnpmをインストールENV VERSION_NODE 14RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bashRUN /bin/bash -c ". ~/.nvm/nvm.sh && \nvm install ${VERSION_NODE} && nvm use ${VERSION_NODE} && chown -R root:root /root/.nvm && \nvm alias default ${VERSION_NODE} && nvm cache clear"# aws-cliをインストールRUN apt-get install -y awscli# node.jsのamplify-cliをインストールRUN /bin/bash -c ". ~/.nvm/nvm.sh && nvm use ${VERSION_NODE} && \npm install -g @aws-amplify/cli"# PythonランタイムのLambdaに必要なライブラリのインストールRUN pip3 install -U pipenv - 【Cloud9】下記コマンドでDockerイメージをビルドし、ECRにプッシュする
※ビルドコマンドはパブリックリポジトリを作成した際にAWSコンソールに表示されます。1234docker build -t パブリックリポジトリ名 .docker tag パブリックリポジトリ名:latest public.ecr.aws/xxxxxxx/パブリックリポジトリ名:latestaws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/xxxxxxxdocker push public.ecr.aws/xxxxxxx/パブリックリポジトリ名:latest - 【AWSコンソール】Amplifyプロジェクトのコンソール画面から、ビルド設定にてamplify.ymlを一か所修正する
※「npm ci」のままだとエラーになります。恐らくNode.jsのバージョンが低いことが原因。今後要解消。1234567(省略)frontend:phases:preBuild:commands:- npm install # 元は「npm ci」(省略) - 【AWSコンソール】Amplifyプロジェクトのコンソール画面から、ビルド設定にてカスタムビルドイメージを利用する設定を追加する
※カスタムビルドイメージのURIは「public.ecr.aws/xxxxxxx/パブリックリポジトリ名:latest」
- 【AWSコンソール】Amplifyプロジェクトのコンソール画面から、ビルド履歴にて「このバージョンを再デプロイ」をクリックする
- 【AWSコンソール】自動ビルド&デプロイが正常に終了することを確認する
おわりに
また、今回はCloud9を使用しましたが、ローカルのDockerでも同様に実現できると思います。
ただ、AmplifyもCloud9も手軽に試せる環境がパッと作れていいですね!今後もドンドン活用していきたいです。
以上、参考になれば幸いです。
執筆者プロフィール
- 社内の開発プロジェクトの技術支援や、Javaにおける社内標準フレームワークの開発を担当しています。Spring BootとTDDに手を出しつつ、LINE Botとかもいじったりしています。最近はマイクロサービスを勉強しつつ、クラウドアプリケーションを開発できるエンジニアの育成にも力を入れてます!