コンテナ内のPython環境(モジュール)をLambdaレイヤーで使用できるようにzip化する

2026/01/01

Python
Lambda
Docker
AWS

コンテナ内のPython環境(モジュール)をLambdaレイヤーで使用できるようにzip化する方法をまとめました。

1. 実行環境

1.1 ディレクトリ構成

.
├── Dockerfile
├── README.md
├── app
│   ├── lambda
│   │   └── `Lambdaで実行するPythonファイル`
│   └── layer
├── docker-compose.yml
└── requirements.txt

1.2 Dockerfile

Dockerfile
# --------------------------------------------------
# ベースイメージ
# --------------------------------------------------
FROM python:3
USER root

# --------------------------------------------------
# システムパッケージの更新とロケール設定
# --------------------------------------------------
RUN apt-get update
RUN apt-get -y install locales && \
    localedef -f UTF-8 -i ja_JP ja_JP.UTF-8

# --------------------------------------------------
# 環境変数の設定
# --------------------------------------------------
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm

# --------------------------------------------------
# 開発ツールとPythonパッケージマネージャーの更新
# --------------------------------------------------
RUN apt-get install -y vim less zip \
    && pip install --upgrade pip \
    && pip install --upgrade setuptools

# --------------------------------------------------
# 依存関係のインストール
# --------------------------------------------------
COPY requirements.txt workspace/
RUN pip install -r workspace/requirements.txt```

1.3 docker-compose.yml

docker-compose.yml
# --------------------------------------------------
# Docker Compose バージョン
# --------------------------------------------------
version: "3"

# --------------------------------------------------
# サービス定義
# --------------------------------------------------
services:
  # --------------------------------------------------
  # アプリケーションサービス
  # --------------------------------------------------
  app:
    # Dockerfileからイメージをビルド
    build: .
    
    # コンテナ名
    container_name: app
    
    # 作業ディレクトリ
    working_dir: /workspace/app/
    
    # ボリュームマウント設定(ホストのカレントディレクトリをコンテナの/workspaceにマウント)
    volumes:
      - ./:/workspace/
    
    # インタラクティブな端末を有効化
    tty: true

2. コンテナ内のPython環境(モジュール)をzip化

2.1 シェルスクリプトの作成

create_layer.sh
#!/bin/bash

# エラーが発生したら停止
set -e

# コンテナ名 (docker-compose.ymlのcontainer_nameと一致させる)
CONTAINER="app"

# パス設定
# コンテナ内の一時作業ディレクトリ
WORK_DIR="/tmp/lambda_layer_work"
# Lambda Layerの構造要件に合わせて 'python' ディレクトリを作成
LAYER_DIR="${WORK_DIR}/python"
# requirements.txtのパス (コンテナ内の絶対パス)
REQUIREMENTS="/workspace/requirements.txt"
# 作成するzipファイルの名前
ZIP_NAME="python.zip"
# 出力先ディレクトリ
OUTPUT_DIR="app/layer"

echo "=== Lambda Layer Creation Start ==="
echo "Target Container: ${CONTAINER}"

# 1. コンテナ内でパッケージのインストールとzip化
echo "[1/3] Installing packages and zipping in container..."
docker exec ${CONTAINER} bash -c "
    echo 'Cleaning up old files...'
    rm -rf ${WORK_DIR}
    mkdir -p ${LAYER_DIR}
    
    echo 'Installing requirements...'
    # -t オプションで指定ディレクトリにインストール
    pip install -r ${REQUIREMENTS} -t ${LAYER_DIR}
    
    echo 'Zipping files...'
    cd ${WORK_DIR}
    zip -r ${ZIP_NAME} python
"

# 2. ホストへのコピー
echo "[2/3] Copying zip file to host..."
# 出力ディレクトリの作成
if [ ! -d "${OUTPUT_DIR}" ]; then
    mkdir -p "${OUTPUT_DIR}"
fi

# 既存のファイルがあれば削除
if [ -f "${OUTPUT_DIR}/${ZIP_NAME}" ]; then
    rm "${OUTPUT_DIR}/${ZIP_NAME}"
fi
docker cp ${CONTAINER}:${WORK_DIR}/${ZIP_NAME} ./${OUTPUT_DIR}/${ZIP_NAME}

# 3. クリーンアップ
echo "[3/3] Cleaning up container temporary files..."
docker exec ${CONTAINER} rm -rf ${WORK_DIR}

echo "=== Success! ==="
echo "Created: ${ZIP_NAME}"

2.2 シェルスクリプトの実行

> source create_layer.sh

=== Lambda Layer Creation Start ===
Target Container: app
[1/3] Installing packages and zipping in container...
Cleaning up old files...
Installing requirements...
Collecting pymysql (from -r /workspace/requirements.txt (line 1))
  Using cached pymysql-1.1.2-py3-none-any.whl.metadata (4.3 kB)
Using cached pymysql-1.1.2-py3-none-any.whl (45 kB)
Installing collected packages: pymysql
Successfully installed pymysql-1.1.2
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv. Use the --root-user-action option if you know what you are doing and want to suppress this warning.
Zipping files...
  adding: python/ (stored 0%)
  adding: python/pymysql/ (stored 0%)
  adding: python/pymysql/__pycache__/ (stored 0%)
  adding: python/pymysql/__pycache__/_auth.cpython-314.pyc (deflated 55%)
  adding: python/pymysql/__pycache__/converters.cpython-314.pyc (deflated 57%)
  adding: python/pymysql/__pycache__/connections.cpython-314.pyc (deflated 57%)
  adding: python/pymysql/__pycache__/times.cpython-314.pyc (deflated 45%)
  adding: python/pymysql/__pycache__/charset.cpython-314.pyc (deflated 76%)
  adding: python/pymysql/__pycache__/__init__.cpython-314.pyc (deflated 45%)
  adding: python/pymysql/__pycache__/err.cpython-314.pyc (deflated 57%)
  adding: python/pymysql/__pycache__/optionfile.cpython-314.pyc (deflated 39%)
  adding: python/pymysql/__pycache__/cursors.cpython-314.pyc (deflated 56%)
  adding: python/pymysql/__pycache__/protocol.cpython-314.pyc (deflated 59%)
  adding: python/pymysql/charset.py (deflated 82%)
  adding: python/pymysql/optionfile.py (deflated 58%)
  adding: python/pymysql/connections.py (deflated 75%)
  adding: python/pymysql/times.py (deflated 58%)
  adding: python/pymysql/_auth.py (deflated 69%)
  adding: python/pymysql/converters.py (deflated 73%)
  adding: python/pymysql/__init__.py (deflated 60%)
  adding: python/pymysql/constants/ (stored 0%)
  adding: python/pymysql/constants/__pycache__/ (stored 0%)
  adding: python/pymysql/constants/__pycache__/CR.cpython-314.pyc (deflated 50%)
  adding: python/pymysql/constants/__pycache__/FLAG.cpython-314.pyc (deflated 18%)
  adding: python/pymysql/constants/__pycache__/FIELD_TYPE.cpython-314.pyc (deflated 26%)
  adding: python/pymysql/constants/__pycache__/SERVER_STATUS.cpython-314.pyc (deflated 32%)
  adding: python/pymysql/constants/__pycache__/__init__.cpython-314.pyc (deflated 20%)
  adding: python/pymysql/constants/__pycache__/COMMAND.cpython-314.pyc (deflated 36%)
  adding: python/pymysql/constants/__pycache__/CLIENT.cpython-314.pyc (deflated 31%)
  adding: python/pymysql/constants/__pycache__/ER.cpython-314.pyc (deflated 55%)
  adding: python/pymysql/constants/CLIENT.py (deflated 51%)
  adding: python/pymysql/constants/SERVER_STATUS.py (deflated 50%)
  adding: python/pymysql/constants/FIELD_TYPE.py (deflated 45%)
  adding: python/pymysql/constants/COMMAND.py (deflated 57%)
  adding: python/pymysql/constants/__init__.py (stored 0%)
  adding: python/pymysql/constants/CR.py (deflated 63%)
  adding: python/pymysql/constants/ER.py (deflated 63%)
  adding: python/pymysql/constants/FLAG.py (deflated 31%)
  adding: python/pymysql/protocol.py (deflated 72%)
  adding: python/pymysql/err.py (deflated 61%)
  adding: python/pymysql/cursors.py (deflated 72%)
  adding: python/pymysql-1.1.2.dist-info/ (stored 0%)
  adding: python/pymysql-1.1.2.dist-info/METADATA (deflated 57%)
  adding: python/pymysql-1.1.2.dist-info/REQUESTED (stored 0%)
  adding: python/pymysql-1.1.2.dist-info/WHEEL (stored 0%)
  adding: python/pymysql-1.1.2.dist-info/INSTALLER (stored 0%)
  adding: python/pymysql-1.1.2.dist-info/top_level.txt (stored 0%)
  adding: python/pymysql-1.1.2.dist-info/licenses/ (stored 0%)
  adding: python/pymysql-1.1.2.dist-info/licenses/LICENSE (deflated 41%)
  adding: python/pymysql-1.1.2.dist-info/RECORD (deflated 58%)
[2/3] Copying zip file to host...
Successfully copied 134kB to /Users/tairaman/GitHub/torecasi/remove-unnecessary-records/app/layer/python.zip
[3/3] Cleaning up container temporary files...
=== Success! ===
Created: python.zip