sam build で容量の大きなファイルや大量のファイルをプロジェクトルートに配置した場合に Setting DockerBuildArgs で時間がかかる際の対処方法

困っていた内容

Lambda向けのコンテナイメージ を AWS SAM を利用してデプロイしようとしておりますが、比較的コード量の少ない Dockerfile でも、sam build に数分の実行時間がかかります。 そのため、ビルド時間を短縮する方法をご教示ください。

なお、ローカルマシンには、以下のようなディレクトリ構造でプロジェクトのルートディレクトリに容量の大きいファイルや大量のファイルがあります。

$ tree
.
├── README.md
├── __init__.py
├── events
│   └── event.json
├── foo_1.txt
|
-- 誌面の都合上、省略。実際は、大量のファイルがある --
|
├── foo_XX.txt
├── hello_world
│   ├── Dockerfile
│   ├── __init__.py
│   ├── app.py
│   └── requirements.txt
├── template.yaml
└── tests
    ├── __init__.py
    └── unit
        ├── __init__.py
        └── test_handler.py

以下が、sam build を実行した際のコマンドの結果です。
「2022-04-08 17:33:37,063 | Setting DockerBuildArgs: {} for HelloWorldFunction function」の箇所で時間がかかってしまいます。

$ sam build --debug
2022-04-08 17:33:36,538 | Telemetry endpoint configured to be https://aws-serverless-tools-telemetry.us-west-2.amazonaws.com/metrics

--- 省略 ---

2022-04-08 17:33:37,055 | Building codeuri: /Users/**************/docker/nakano-sam-test runtime: None metadata: {'Dockerfile': 'Dockerfile', 'DockerContext': '/Users/**************/docker/nakano-sam-test/hello_world', 'DockerTag': 'python3.9-v1'} architecture: x86_64 functions: ['HelloWorldFunction']
2022-04-08 17:33:37,055 | Building to following folder /Users/**************/docker/nakano-sam-test/.aws-sam/build/HelloWorldFunction
2022-04-08 17:33:37,055 | Building image for HelloWorldFunction function
2022-04-08 17:33:37,063 | Setting DockerBuildArgs: {} for HelloWorldFunction function
Step 1/4 : FROM public.ecr.aws/lambda/python:3.9
3.9: Pulling from lambda/python
e6842361273f: Already exists
0a074f8b3d7a: Pull complete
df68587c4258: Pull complete
1418415b0a5d: Pull complete
f2796bda02b6: Pull complete
8c16de5f53b2: Pull complete
Status: Downloaded newer image for public.ecr.aws/lambda/python:3.9 ---> 2df2e3c405fe
Step 2/4 : COPY app.py requirements.txt ./
 ---> ef3029fffcba
Step 3/4 : RUN python3.9 -m pip install -r requirements.txt -t .
 ---> Running in 3bf7eae77c13
Collecting requests
  Downloading requests-2.27.1-py2.py3-none-any.whl (63 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 63.1/63.1 KB 991.8 kB/s eta 0:00:00
Collecting charset-normalizer~=2.0.0
  Downloading charset_normalizer-2.0.12-py3-none-any.whl (39 kB)
Collecting idna=2.5
  Downloading idna-3.3-py3-none-any.whl (61 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.2/61.2 KB 2.5 MB/s eta 0:00:00
Collecting certifi>=2017.4.17
  Downloading certifi-2021.10.8-py2.py3-none-any.whl (149 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 149.2/149.2 KB 1.8 MB/s eta 0:00:00
Collecting urllib3=1.21.1
  Downloading urllib3-1.26.9-py2.py3-none-any.whl (138 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 139.0/139.0 KB 2.1 MB/s eta 0:00:00
Installing collected packages: certifi, urllib3, idna, charset-normalizer, requests
Successfully installed certifi-2021.10.8 charset-normalizer-2.0.12 idna-3.3 requests-2.27.1 urllib3-1.26.9
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
 ---> c93dfe84bd5e
Step 4/4 : CMD ["app.lambda_handler"]
 ---> Running in 737adb584ca4
 ---> c93bd4799df1
Successfully built c93bd4799df1
Successfully tagged helloworldfunction:python3.9-v1

2022-04-08 17:34:00,912 | No Parameters detected in the template
2022-04-08 17:34:00,927 | There is no customer defined id or cdk path defined for resource HelloWorldFunction, so we will use the resource logical id as the resource id
2022-04-08 17:34:00,927 | There is no customer defined id or cdk path defined for resource ServerlessRestApi, so we will use the resource logical id as the resource id
2022-04-08 17:34:00,928 | There is no customer defined id or cdk path defined for resource HelloWorldFunction, so we will use the resource logical id as the resource id

Build Succeeded

どう対応すればいいの?

.dockerignoreにコンテナイメージのビルドに必須ではないファイルを含めないよう記載ください。

どういう動作なの?

sam build が遅い原因としては、コンテナイメージのビルド時に Docker Daemon へのビルドコンテキストの送信に時間がかかっていることが原因です。

Docker でコンテナイメージのビルドを行う際、ビルド対象のディレクトリ配下のファイルが「ビルドコンテキスト」として Docker Daemon へ送信され、Docker Daemon にてコンテナイメージのビルドが行われるという動作になります。
また、ビルドコンテキスト送信の際、ビルド対象ディレクトリ配下に大量のファイルやサイズの大きいファイルが含まれていると、送信に時間がかかリます。

解決方法

以下の例のように、.dockerignoreをプロジェクトのルートディレクトリに配置します。 ビルドに不要なファイルである foo_XXX.txt のファイルを Docker Daemon へ送信されないように追記します。

$ vim .dockerignore
foo* # こちらを、追記

再度、ビルドを実行すると、Setting DockerBuildArgs の箇所が高速化されるか確認します。

$ sam build --debug
2022-04-08 17:38:53,278 | Telemetry endpoint configured to be https://aws-serverless-tools-telemetry.us-west-2.amazonaws.com/metrics

--- 省略 ---

2022-04-08 17:38:53,915 | Building codeuri: /Users/****************/docker/nakano-sam-test runtime: None metadata: {'Dockerfile': 'Dockerfile', 'DockerContext': '/Users/****************/docker/nakano-sam-test/hello_world', 'DockerTag': 'python3.9-v1'} architecture: x86_64 functions: ['HelloWorldFunction']
2022-04-08 17:38:53,916 | Building to following folder /Users/****************/docker/nakano-sam-test/.aws-sam/build/HelloWorldFunction
2022-04-08 17:38:53,916 | Building image for HelloWorldFunction function
2022-04-08 17:38:53,921 | Setting DockerBuildArgs: {} for HelloWorldFunction function
Step 1/4 : FROM public.ecr.aws/lambda/python:3.9
 ---> 2df2e3c405fe
Step 2/4 : COPY app.py requirements.txt ./
 ---> Using cache
 ---> ef3029fffcba
Step 3/4 : RUN python3.9 -m pip install -r requirements.txt -t .
 ---> Using cache
 ---> c93dfe84bd5e
Step 4/4 : CMD ["app.lambda_handler"]
 ---> Using cache
 ---> c93bd4799df1
Successfully built c93bd4799df1
Successfully tagged helloworldfunction:python3.9-v1

2022-04-08 17:38:54,246 | No Parameters detected in the template
2022-04-08 17:38:54,260 | There is no customer defined id or cdk path defined for resource HelloWorldFunction, so we will use the resource logical id as the resource id
2022-04-08 17:38:54,261 | There is no customer defined id or cdk path defined for resource ServerlessRestApi, so we will use the resource logical id as the resource id
2022-04-08 17:38:54,261 | There is no customer defined id or cdk path defined for resource HelloWorldFunction, so we will use the resource logical id as the resource id

Build Succeeded

上記の例では、30 秒ほどかかっていたビルド時間が 1 秒程度に短縮されました。

参考資料