• 作成:

AWS CDKのaws-lambda-nodejsパッケージが壊れていたので修正しました

概要

aws-lambda-nodejs module · AWS CDK のデフォルト設定での動作が壊れていたので、修正して fix(lambda-nodejs): docker build is not working by ncaq · Pull Request #10885 · aws/aws-cdk というpull requestを送ってmergeされました。

aws-lambda-nodejsは便利

aws-lambda-nodejs module · AWS CDK と言うモジュールがあります。

これの便利さは以下の記事を読めば分かると思います。

でもexperimentalなので問題点がよく出ます

これを使って素直にサンプル通りにビルドしようとすると、

[Status 1] stdout:


stderr: #1 [internal] load .dockerignore
#1 transferring context: 2B done
#1 DONE 0.1s

#2 [internal] load build definition from Dockerfile
#2 transferring dockerfile: 811B done
#2 DONE 0.1s

#3 [internal] load metadata for docker.io/amazon/aws-sam-cli-build-image-no...
#3 DONE 2.7s

#4 [1/5] FROM docker.io/amazon/aws-sam-cli-build-image-nodejs12.x@sha256:fd...
#4 resolve docker.io/amazon/aws-sam-cli-build-image-nodejs12.x@sha256:fd8d0d72d475db2e2cd25dbabae010cb03da2ac7c47074a1962f8cec5ff395d2 done
#4 sha256:932c0da721ace91d31730420a6106649bffff46a633002aab5c86405089e1ea0 4.08kB / 4.08kB done
#4 sha256:fd280bd26b5c57f8f55451d35c7a2278370c17cebefc35cbc72c09e6997350a9 450.31MB / 450.31MB 58.5s done
#4 sha256:13e333e103330c43835c043b0b3271cb9b933fe12296ae7fe53de31af3d838cc 31.98MB / 31.98MB 9.8s done
#4 sha256:30c88e52574c409a7fdaafe60fc48eac7f81d08164f302addc89d15f9566eb66 68.72MB / 68.72MB 16.0s done
#4 sha256:fd8d0d72d475db2e2cd25dbabae010cb03da2ac7c47074a1962f8cec5ff395d2 2.42kB / 2.42kB done
#4 sha256:e0a2e909705a2bb5c57b6ae40a0cc9d99b7ff37dd901f9aca543e5b02763639c 155B / 155B 10.1s done
#4 sha256:ffcf5ac6a651db9a20f20aab8e3220edbb6f9e9879c63f25695681dba927fc20 105.67kB / 105.67kB 10.5s done
#4 sha256:17ae4e491f0d0ff9930880edac90c025ca24b49238228074c5b162982005b54a 59.55kB / 59.55kB 10.8s done
#4 extracting sha256:fd280bd26b5c57f8f55451d35c7a2278370c17cebefc35cbc72c09e6997350a9 18.7s done
#4 extracting sha256:13e333e103330c43835c043b0b3271cb9b933fe12296ae7fe53de31af3d838cc 1.5s done
#4 extracting sha256:30c88e52574c409a7fdaafe60fc48eac7f81d08164f302addc89d15f9566eb66 2.2s done
#4 extracting sha256:e0a2e909705a2bb5c57b6ae40a0cc9d99b7ff37dd901f9aca543e5b02763639c 0.5s done
#4 extracting sha256:ffcf5ac6a651db9a20f20aab8e3220edbb6f9e9879c63f25695681dba927fc20 0.0s done
#4 extracting sha256:17ae4e491f0d0ff9930880edac90c025ca24b49238228074c5b162982005b54a 0.1s done
#4 DONE 85.6s

#5 [2/5] RUN npm install --global yarn
#5 1.175
#5 1.175 > yarn@1.22.10 preinstall /var/lang/lib/node_modules/yarn
#5 1.175 > :; (node ./preinstall.js > /dev/null 2>&1 || true)
#5 1.175
#5 1.245 npm ERR! code ELIFECYCLE
#5 1.245 npm ERR! syscall spawn sh
#5 1.245 npm ERR! file sh
#5 1.245 npm ERR! path sh
#5 1.245 npm ERR! errno EACCES
#5 1.246 npm ERR! yarn@1.22.10 preinstall: `:; (node ./preinstall.js > /dev/null 2>&1 || true)`
#5 1.246 npm ERR! spawn sh EACCES
#5 1.246 npm ERR!
#5 1.246 npm ERR! Failed at the yarn@1.22.10 preinstall script.
#5 1.246 npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
#5 1.254
#5 1.254 npm ERR! A complete log of this run can be found in:
#5 1.254 npm ERR!     /root/.npm/_logs/2020-10-15T04_21_28_090Z-debug.log
#5 ERROR: executor failed running [/bin/sh -c npm install --global yarn]: runc did not terminate sucessfully
------
 > [2/5] RUN npm install --global yarn:
------
failed to solve with frontend dockerfile.v0: failed to build LLB: executor failed running [/bin/sh -c npm install --global yarn]: runc did not terminate sucessfully
Subprocess exited with error 1

と言うエラーに見舞われます。

これの回避方法は存在していて、ローカルにParcelをインストールしていればDockerを使わずにビルドすることが出来ます。

しかし最近、 Error: Cannot read property 'hashReferences' of undefined · Issue #4145 · parcel-bundler/parcel と言うまだ解決がデプロイされてない問題が出てきまして、一々ビルドするたびに.parcel-cacheを消す必要がありました。

キャッシュを使わない設定もあるようですが、あまりにもワークアラウンド過ぎるので嫌ですね。

修正することにしました。

修正します

とりあえずissueを建てて今日中に修正するから待っててと書いておきました。

[aws-lambda-nodejs] docker build is not working · Issue #10881 · aws/aws-cdk

Dockerでのビルドが失敗する原因を調査した所、以下の問題があるようです。

For future reference, you can (should) pin your version rather than use whatever the latest is on npm (by using yarn@1.22.6, etc) - it's a good practice anyway regardless of the conditions, as you never know which bug could slip by us. You can also use the yarn-path setting to ensure that upgrades go through the appropriate review processes (including CI).

https://github.com/yarnpkg/yarn/issues/8358#issuecomment-700011305

と言うことなので、固定化するのが良いと思いました。

1.22.5なら動作するのでこれに固定することを提案します。

npm install --global yarn@1.22.5

最新版を使わない問題はありますが、

Fwiw we don't plan to add any more features to Yarn 1, as all of our resources have shifted to Yarn 2. The past few commits have been aimed toward making the transition a bit easier, in particular thanks to the Corepack initiative which we hope will make it easier to use Yarn (both 1 & 2) by removing the need to manually install them.

https://github.com/yarnpkg/yarn/issues/8358#issuecomment-700018785

と言うことらしいので、 1の最新版に拘る必要性はあまりないでしょう。

将来的に2がリリースされた時にDockerfileが壊れることを防ぐことも出来ます。

これにより次のビルド段階に進みますが、

docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"bash\": executable file not found in $PATH": unknown.

と言うエラーをもらいました。

実装内容を見るとbashがパスに存在せず、 shがテスト内容なのにも関わらずbashを使っているので、 shに書き換えました。

docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"sh\": executable file not found in $PATH": unknown.

しかし、同じ問題が出るので問題はbashではありませんでした。まあテストケースがおかしいのは事実なのでそれはそれとしてテストコードの方を修正します。

non-root userが存在しないのではと言う疑惑が持ち上がってきました。存在しませんでした。

じゃあuseraddで追加するだけですね。と思ったらuseraddが存在しないんですけど。じゃあyumで追加するだけですね。 yumが存在しないんですけど。 dnfに切り替わってたりしませんね。 /sbin/useraddにちゃんとありました。良かった。

non root user作ってもPATH通ってないですね。 PATHが通らないので docker run --rm -u 1000:1000 -it parcel /usr/bin/bash してみたら、

docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"/usr/bin/bash\": stat /usr/bin/bash: permission denied": unknown.

とか言われました。ひょえー/の実行権限がroot限定になってますね。権限周りを変更したくはないですがやむを得ません。

修正は簡単でしたけど動作テストなどがとても面倒でした

これで修正はちゃっちゃっと終わったんですが、実際のプロダクトで修正されてるか確認しないと送るのは気が引けるなあと思って試すことになりました。

しかし、パッケージがコンポーネントごとに分かれまくっててビルドやlinkがメチャクチャ面倒です。ちょっとでもライブラリのバージョンが異なるとエラーになるので一部だけlinkするわけにもいきませんし。

linkするためにはそのパッケージをビルドする必要があるのですが、全部ビルドしようとするとdotnetとか要求してきて手に負えませんね。たくさんの言語へのバインディングがありますからね… 一回全部リンクして試そうと試みましたが挫折しました。 Dockerでのビルドは失敗しました。

仕方がないのでメチャクチャ実アプリケーションのスタックの内容を削ってlink数を減らしてテストしました。どうやら動いているようです。

なのでpull requestをopenしました。

fix(lambda-nodejs): docker build is not working by ncaq · Pull Request #10885 · aws/aws-cdk

原因の特定と修正自体は簡単な作業でしたが、コントリビュートガイドに従うのと実際のアプリケーションでテストするのがメチャクチャ大変でした…

何故パッケージがすごい分かれてるんでしょうね? どうせバージョンがマイナーですら違うとエラーになるならば分けなくても良いと思うのですが。

モノレポにしてでもパッケージを分ける理由はビルド時間の短縮がありますが、結局バージョンが微妙に違うとエラーになってしまうので全てビルドする必要が生まれます。

依存関係が小さくなると言うメリットもTypeScriptベースなので、最終的にはツリーシェイキングなどで使わないコードは消失しますし、そもそもAWS CDKは手元でYAML吐くのが主目的なのでプロダクションコードにバンドルされるわけではないので、パッケージサイズを気にしなくても良さそうに思えます。

lernaをちゃんと制御すれば簡単に試せたりするのでしょうか?

とにかくちょっと修正するだけの私にとっては開発が大変でした。

モノレポはつらいと言う私の言語を問わず共通している認識がまた強化されてしまいましたね。