Open10

package.json を投げたらそれを npm i するのにどのくらいの時間がかかるかを返却する Lambda を作りたい件

amay077amay077

本当にやりたいことは別だけどわかりやすい例として題記のような仮の目的を設定。

要点は、

  • AWS Lambda を使いたい(EC2 や CodePipeline などではなく)
  • Lambda 内で npm コマンドを実行したい
  • Lambda 関数自体のランタイムも node にしたい

である。

amay077amay077

雑に、

index.js

const { execSync } = require("child_process");
exports.handler = async (event) => {
    execSync('npm i', { cwd: '/tmp' });
    
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello, World!'),
    };
    return response;
};

なんて関数を Lambda で実行したら、次のようなエラーが出た。

npm ERR! enoent ENOENT: no such file or directory, mkdir '/home/sbx_userXXXX'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent

npm ERR! Log files were not written due to an error writing to the directory: /home/sbx_userXXXX/.npm/_logs

Lambda の実行環境は /tmp 以外は Readonly であるが、npm i のログファイルを /home に書き出そうとするのでエラーになっていると理解した。

amay077amay077

上記の例を参考に、npm i を実行する Docker コンテナを作成してローカルでの動作を確認後、Lambda 側にデプロイして実行したところ、上記と同じエラーが発生。

npm ERR! enoent ENOENT: no such file or directory, mkdir '/home/sbx_userXXXX'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent

npm ERR! Log files were not written due to an error writing to the directory: /home/sbx_userXXXX/.npm/_logs

ローカルでは動作していたが、Lambda でコンテナ実行するとコンテナ内なのに /tmp 以外は Readonly になるっぽい。

まあ分かる。

amay077amay077

ついでにもう一つ Lambda 固有の挙動を発見。

docker build 時にコンテナの /tmp に必要なファイルをコピーしておこうと、次のような Dockerfile を使用していた。

Dockerfile

FROM public.ecr.aws/lambda/nodejs:18

COPY ./main /var/task/
COPY ./temp/package.json /tmp/package.json

CMD ["index.handler"]

ローカルのコンテナでは /tmp/package.json は確かに存在するのだけど、 Lambda にデプロイすると /tmp/package.json が NOT FOUND になっている。

どうやら関数実行時に /tmp が消去されているように見える。
これがコールドスタートのみか、ホットスタートでも行われるかは不明。

amay077amay077

Dockerfile に

RUN npm config set cache /tmp/.npm

を追記してみたけどダメ。

amay077amay077

execSync の第2引数に

{ 
    env: {
      ...process.env, // 現在の環境変数を維持
      npm_config_cache: '/tmp/.npm'
    }
}

を指定したらいけたっぽい。