aws lambda + python3.9 + selenium （python 旧バージョンで止まった人向け）

# 対象者

* aws lambda + python3.9 で Layers に headlesschrome + selenium を使って動かなかった渋い経験がある人（127 エラーに泣いた日々）
* 現在 python3.7 で動かしているけど、いつ AWS から見限られるかでおびえている人

※ python の書き方や、aws lambda の使い方云々については取り上げてません（参考記事だけは残してます）

# 前置き（どうでもいい人はスキップ）

ふとしたきっかけはこちらの記事

https://aws.amazon.com/jp/blogs/news/new-for-aws-lambda-container-image-support/

この記事を見た時、Docker のことはよくわかっていないけれど、Docker イメージ（OS+必要なアプリケーションや実行ファイルをまとめたもの）を作って ECR に配置すると、Lambda で使えるようになったよ！ということらしい

その時は、いまいちピンと来てなかったが、、、
ある日ネットサーフィンしていると以下に出会う

https://github.com/umihico/docker-selenium-lambda/

脳内再生（docker を使うと chrome + chromedriver あと必要なライブラリも docker イメージにぶち込んで動かしたら動くようになったんだZE！）

頭の片隅にはあったけど、先人の方が実績を作ってくれたというならば、試すしかないということで試した結果をこちらにまとめました

これを読んで実践すると、、、あなたはこうなるだろう

それ解決できるようになったよ Docker ならね

# 説明下手の説明より参考記事をくれ！

人の記事を読むうえで、必要な情報の取捨選択はとても重要になると思っている
特にこういう記事を書くときお酒飲みながら書いている以上、参考になるかは怪しい部分があったりする

そうなると記事を参考にするより元ネタを追ったほうが手っ取り早いと思ったので、参考になった記事を真っ先に乗せておきます

Docker で試すきっかけをくれた git serverless.yml は残念ながら取り組んでない

https://github.com/umihico/docker-selenium-lambda/

Dockerfile をコピペするだけで大体うまくいくような気がする不思議

https://gallery.ecr.aws/lambda/python

とはいえ、使いたい python のバージョンはあると思うので、使いたいものを選ぶと良い
費用対効果であれば、arm64 だけど chrome が提供されていないので、 chromium + chromedriver でエキサイティングしたい人には向いているのかもしれない（※試してないので適当書いてます）

https://qiita.com/fukamiAO/items/57b7f425d24a6c91b04f

Docker でプロセス停止ってどうすりゃいいの？で検索した記事
読もうとしたけど、Docker Desktop の ごみ箱アイコンで停止できたのでパソコンを電源ボタン長押しで停止する外道になりました

https://qiita.com/kano1234/items/6aabe6ab24e4ad54612c

Dockerfile を作って、ローカル環境で作るようにしたけどその後どうすりゃええねん
ってなった時にフローを理解できた記事、「Amazon ECRにpush」が困りどころを救ってくれました

# lambda python 3.7 -> 3.9 移行やってくよ！

ではでは本題はこちらから始めます（ごめんなさい結構飲んだ上で、飲みながら書いてます）

## 開発環境

* windows10
    * インストールしているOfficeが古すぎて移行できない
* aws-cli ver 2 以降
    * ver1 だとコマンドが動かないので注意、流し見した記事にバージョンのこと書いて無くてコマンドなくて困った
* Docker 4.2.x だと最近結構ヤバめの不具合でたのでアップデートしてね
    * とりあえず今の最新バージョンで良いと思う
* VSCode
    * Power Shell とか必須

## 結論

今まで、レイヤーにヘッダーレスchrome置いて、aws コンソールからファイル修正みたいなことはできなくなる

ローカルファイルでファイルを編集、Docker イメージを作成、ECR に登録
ECR に登録した Docker イメージを Lambda でキックするような形になる

とはいえ、Amazon Linux 2 だとどうにもこうにもできないから仕方がないのかな、、、（いい方法があれば教えてほしい）

## Dockerfile の準備

ベースはこちらを参考にしながら以下のようなファイルにしました

https://github.com/umihico/docker-selenium-lambda/


```
FROM public.ecr.aws/lambda/python@sha256:b8fb2628d7622a94b53c041d4c0cd14e001fbf97452c528fe9421fe7dae35aba as build
RUN yum install -y unzip && \
    curl -Lo "/tmp/chromedriver.zip" "https://chromedriver.storage.googleapis.com/97.0.4692.71/chromedriver_linux64.zip" && \
    curl -Lo "/tmp/chrome-linux.zip" "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Linux_x64%2F938549%2Fchrome-linux.zip?alt=media" && \
    unzip /tmp/chromedriver.zip -d /opt/ && \
    unzip /tmp/chrome-linux.zip -d /opt/

FROM public.ecr.aws/lambda/python@sha256:b8fb2628d7622a94b53c041d4c0cd14e001fbf97452c528fe9421fe7dae35aba
RUN yum install atk cups-libs gtk3 libXcomposite alsa-lib \
    libXcursor libXdamage libXext libXi libXrandr libXScrnSaver \
    libXtst pango at-spi2-atk libXt xorg-x11-server-Xvfb \
    xorg-x11-xauth dbus-glib dbus-glib-devel -y
COPY app.py requirements.txt hogefuga.json ${LAMBDA_TASK_ROOT}/
RUN pip install --requirement requirements.txt

ENV HOGE=fuga

COPY --from=build /opt/chrome-linux /opt/chrome
COPY --from=build /opt/chromedriver /opt/
CMD [ "app.lambda_handler" ]
```

違いは requirements.txt を使って環境を構築したかったので、その前に LAMBDA_TASK_ROOT に必要なファイルをコピーしたこと

過去に実装した lambda でディレクトリ直下にファイルを置いているケースだと、LAMBDA_TASK_ROOT にファイルをコピーしないと実行できなくなるので注意してね！

AWS で環境変数を設定している場合、うまく読み込まなくなるので、とりあえず動かす程度で良いならば ENV で指定すると回避できる。 ただ、 docker-compose とかもっと良い手段があるらしい
が、どうすればいいかいまいちピンとこない（ご教授いただけるととてもうれしいです）

## ソースファイルの修正

ヘッドレス chrome の時に指定していたオプションと、chrome 用のオプションに若干の違いがあるので、その誤差を埋める必要がある

https://github.com/umihico/docker-selenium-lambda/

※ 上記を参考にDockerfileを作った場合は、chrome や chromedriver のパスも直さないと動かないので注意

## Dockerfile を使ってローカル環境で動作確認

```
docker build -t ${PJ名} .

docker run -p 9000:8080 ${PJ名}
```

起動した後はコマンドプロンプトとかで以下の URL にアクセスすれば
ローカル環境でLambda の動作確認ができる（-d 以降のパラメータは実装依存なので単純にキックしたときの例を残してます）

```
curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d "{}"
```

## 成果物を ECR に登録する

ローカル環境で動作確認ができた後、Docker イメージを ECR に登録する必要がある
aws cli の最初の準備方法は忘れてしまったので割愛(ぐぐれば多分色々情報は出てくると思います)

ECR のリポジトリを作るのは以下のコマンドを実行します

```
aws ecr create-repository --repository-name ${PJ名}
```

実行が完了したときの、registryId、repositoryUri はこの後の操作で重要になるので、コピーして残しておいてください

ECR で Push するには Docker にログインする必要がある（らしいです）
ログイン方法は以下のコマンドを、PowerShell で用います

```
aws --region ap-northeast-1 ecr get-login-password | docker login --password-stdin --username AWS ${registryId}.dkr.ecr.ap-northeast-1.amazonaws.com
```

やっていることは単純でパイプ前のコマンドでパスワードを取得して、「--password-stdin」でパイプの内容をパスワードとして扱っているだけ、考えずに実行でも大体何とかなりそう

次にどのイメージを push するかの選択は以下のコマンドで Docker イメージの一覧を表示します

```
docker images
```

で見てもわかんねーよ！ってなるのであれば Doker で実行中に以下の画像のように

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532289/75011813-ae3f-0aae-6515-0ca8f33a6343.png)

Docker Desktop で稼働中の IMAGE ID を見るのも手段としてはありだと思います

```
docker tag ${↑のID} ${repositoryUri}
docker push ${repositoryUri}
```
あとはタグを切って、push するだけで良いみたい（Git みたいな感じですね）

## Lambda の指定方法

文章を書こうとしたけど、画像ありで以下の記事が存在していたので割愛（車輪の再発明はやりたくない）

https://qiita.com/kano1234/items/6aabe6ab24e4ad54612c

むしろこちらを参考すると Selenium 以外はだいたい解決できると思います

# 最後に

さて、、、書いてみましたが参考になりましたでしょうか？

今北産業だと

* aws-cli は ver2 をインストールする
* Docker イメージを ECR に push する
* Docker イメージを利用して Lambda 作ってキックする

上記でおしまい

これであなたも「それ解決できるようになったよ Docker ならね」ってドヤれますね( ･´ｰ･｀)