Windows＆Docker開発環境で作ったImageをそのままAWS Lambdaにのせる方法

## はじめに

この記事では、ローカル環境（Windows＆VSCode＆Docker開発環境＆Python）で開発したImageをそのままAWS Lambdaで動かせるようにする方法を載せています。
例として、S3にファイルをアップロードすることを目指します。
Windows環境で確認しています。
未確認ですが、前提条件以外の部分は多分Macでも同じかと思ってます。

## 背景
- ローカル環境のWindows環境＆Pythonで動いても、それをAWS Lamdbaにのせるのが大変。それに無事にAWS Lamdbaにのせることが出来ても、改修しにくい。
⇒　ローカルで出来たことをLambdaにそのまま反映したい！！
- プログラムによってはzipしてAWS Lambda Layer作らないといけないのが大変
⇒　Layerとか作りたくない！！

そんなわけで、希望が叶う手順を作りました。
環境を作るまではちょっと大変です。

## 目次
- [環境](#環境)
- [前提条件](#前提条件)
- [参考サイト](#参考サイト)
- [構成図](#構成図)
- [フォルダ構成](#フォルダ構成)
- [VSCode拡張機能](#vscode拡張機能)
- [手順](#手順)
    - 1：[GitHubよりcloneする](#1githubよりcloneする)
    - 2：[AWSでS3＆ECRを作成する](#2awsでs3ecrを作成する)
    - 3：[ローカル環境でS3にファイルをアップロードする](#3ローカル環境でs3にファイルをアップロードする)
    - 4：[Docker ImageをECRにpushする](#4docker-imageをecrにpushする)
    - 5：[Lambda作成＆実行](#5lambda作成実行)
    - 6：[修正を反映してみる](#6修正を反映してみる)
- [プログラム解説](#プログラム解説)
- [料金](#料金)
- [まとめ](#まとめ)

## 環境
- ローカル
    |  |  |
    |--------|--------|
    | OS  | Windows11  |
    | Docker  | Dockerデスクトップ  |
    | 開発ツール  | Visual Studio Code  |
    | 言語  | Python3.8 |

- クラウド：AWS
    - Amazon Simple Storage Service (S3) 
    - AWS Lambda
    - Amazon Elastic Container Registry(ECR)

## 前提条件
- Dockerがインストール済みであること（参考サイト①）
- VSCodeがインストール済みであること（参考サイト②）
- Gitがインストール済みであること（参考サイト②）
- VSCodeでdev containaerを設定済みであること（参考サイト③）
- AWS IAMユーザにS3とLambdaとECRへの権限が付与されていること（参考サイト④）
- AWS CLI認証情報を設定済みであること（参考サイト⑤）

## 参考サイト
　私は下記のサイトを参考に環境構築しました。
　分かりやすくて大変有難かったです！！
| NO | 環境構築 | 参考サイト | URL |
|--------|--------|--------|--------|
| ①| Windows＆Dockerデスクトップ  | 【Docker Desktop】Windowsにインストール（WSL2）  | [こちら](https://chigusa-web.com/blog/windows%E3%81%ABdocker%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%97%E3%81%A6python%E7%92%B0%E5%A2%83%E3%82%92%E6%A7%8B%E7%AF%89/) |
| ②| VSCode＆Dev Containers | 【VS Code】Dockerコンテナの環境でリモート開発【Win/Mac】  | [こちら](https://chigusa-web.com/blog/vs-code%e3%81%a7docker%e3%81%aepython%e7%92%b0%e5%a2%83%e3%81%a7%e3%83%aa%e3%83%a2%e3%83%bc%e3%83%88%e9%96%8b%e7%99%ba/)  |
| ③| VSCode＆Dev Containers  | VS CodeでDocker開発コンテナを便利に使おう  | [こちら](https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0) 
| ④| AWS IAM アクセス許可 | IAM ID のアクセス許可の追加および削除  | [こちら](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/access_policies_manage-attach-detach.html)  |
| ⑤| AWS CLI  | AWS CLI の最新バージョンを使用してインストールまたは更新を行う  | [こちら](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html)  |

## 構成図
- オレンジ色の線はshellで実行
- 青色の線は手動実行
![構成図.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/11dacf43-aed6-5377-5c93-c828b34d65c7.jpeg)

## VSCode拡張機能
下記を入れておく
![VSCode拡張.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/0cfb3b58-25d9-d041-bde1-cd8bb9c72738.png)

## フォルダ構成
プロジェクトルート(D:\src\docker_lambda_s3)
├── .devcontainer
│   ├── devcontainer.json
│   └── settings.json
├── app
│   ├──__init__.py
│   ├── lambda_function.py
│   ├── log_manager.py
│   └── s3_uploader.py
├── .dockerignore
├── .env(.env_sampleをリネーム)
├── .gitignore
├── awscli.sh
├── docker-compose.yml
├── Dockerfile
├── README.md
└── requirements.txt

## GitHub
https://github.com/sasayakado/docker_lambda_s3

## 手順
### 1.GitHubよりcloneする
1.  cloneする
    ```bash:Git Bush 
    git clone git@github.com:sasayakado/docker_lambda_s3.git
    ```
2. VSCodeで開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/6e99661c-ada9-ba41-bb26-38048bb8cbe4.png)

3. .env_sampleを.envにreneame

4. .envに自分の環境変数を設定
    
    ```sh:.env
    AWS_ACCESS_KEY=★1
    AWS_SECRET_ACCESS_KEY=★2
    AWS_ACCOUNT_ID=★3
    AWS_DEFAULT_REGION=★4
    LOG_FILE=★5
    BUCKET_NAME=★6
    IMAGE_TAG=★7
    DOCKER_IMAGE_NAME=★8
    DOCKER_CONTAINER_NAME=★9
    LAMBDA_FUNC_NAME=★10
    ```
| ★ | 変数 | 設定内容 | 
|--------|--------|--------|
| 1|AWS_ACCESS_KEY  | AWS IAMより取得して設定  | 
| 2|AWS_SECRET_ACCESS_KEY  | AWS IAMより取得して設定  | 
| 3|AWS_ACCOUNT_ID  | AWS右上を参照。黄色のハイフンは除いた部分。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/1f4d7ac0-8406-04b7-2430-c77f5f8d140b.png)|
| 4|AWS_DEFAULT_REGION  |リージョン。東京なら「ap-northeast-1」  |
| 5|LOG_FILE  |S3に保存するファイルの後ろの名前と拡張子。好きにつけてＯＫ。例1：LOG_FILE=.log・例2：LOG_FILE=_s3.log | 
| 6|BUCKET_NAME  |S3のバケット名。Globalで一意である必要あり。例：docker-lambda-s3  |
| 7|IMAGE_TAG  |Imageのタグ。例：latest  |
| 8|DOCKER_IMAGE_NAME  |Docker Image名とECRのリポジトリ名。好きにつけてOK。例：docker_lambda_s3 ← 本当はlambda-image-s3にしようとして間違えたけどQiitaにのせるハードコピー取り直すの大変なのでこのままでいく|
| 9|DOCKER_CONTAINER_NAME  |Docker Container名で、好きにつけてOK。 例：lambda-container-s3 |
| 10|LAMBDA_FUNC_NAME  |lambdaの関数名。例：lambda-s3  |

　　↓　こんな風になる

```sh:.env
AWS_ACCESS_KEY=★自分のAWS_ACCESS_KEY
AWS_SECRET_ACCESS_KEY=★自分のAWS_SECRET_ACCESS_KEY
AWS_ACCOUNT_ID=★自分のAWS_ACCOUNT_ID
AWS_DEFAULT_REGION=ap-northeast-1
LOG_FILE=.log
BUCKET_NAME=docker-lambda-s3
IMAGE_TAG=latest
DOCKER_IMAGE_NAME=docker_lambda_s3
DOCKER_CONTAINER_NAME=lambda-container-s3
LAMBDA_FUNC_NAME=lambda-s3
```

### 2.AWSでS3＆ECRを作成する
構成図の緑の丸部分を作る
![構成図_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/4d6d6073-5c5e-240b-d192-d8b9af958d8b.jpeg)

#### ・S3作成
1.バケット作成
 - バケット名の例：docker-lambda-s3
![S3作成_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/3dc01c11-3e95-5296-2a61-d88a2d210a4f.jpeg)
2..envの★6に環境変数を設定
    BUCKET_NAME=docker-lambda-s3

#### ・ECR作成
1.リポジトリを作成
.envの★8で設定した名前:docker_lambda_s3
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/d2a14634-0c78-cb1e-9461-290e84e302cd.png)


2.リポジトリの中を見てみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/c3b60823-f4d0-d387-b289-f7e67d0fb75a.png)

今はimageがない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/7ceef026-7840-12f3-67d3-8784d51d4a4a.png)

### 3.ローカル環境でS3にファイルをアップロードする

構成図の緑の部分を動かす
![構成図_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/4a8c1207-648a-2158-0dcf-78e1c36edc3b.jpeg)

1.DevContainerをひらく
- VSCode左下の「><」をクリックして、「コンテナーで再度開く」を選択
![devcon_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/e7d6d264-fbad-e399-14cc-68ae7129452a.png)

しばらく待っていると、開発コンテナーが開く
![devcon_2_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/0e76679f-7f70-1010-9685-bbb9718f1f8e.png)






- Dockerを確認
    - Image
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/62d44ffb-ae66-33c1-87ac-652c4f147816.png)

    - Container
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/a3822c42-4855-10bb-501f-32f1c8e17f0d.png)

2.実行する
 - 「lambda_funcion.py」を右クリックして「ターミナルでPythonファイルを実行する」をクリックする
![devcon_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/6894e4b3-661c-a101-e3b9-c26b345556eb.png)


 - 正常に実行されて、ターミナルに「年月日_時間分秒　テスト　ファイル　だよ」と出る。
![devcon_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/599a85c0-0405-5f4b-737c-302d529693dd.png)


3.S3を確認する
- バケット「docker-lambda-s3」の中に、実行した日付「9月4日」のフォルダが作成されており、その中に「年月日_時間分秒.log」が作成されている
![s3_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/e394530a-800f-206e-1f85-6016f34d53df.jpeg)
- 「年月日_時間分秒.log」の中身を見てみる。
![s3_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/e25038f4-9138-1c3b-eb4f-6ce229599671.jpeg)

中身が、ターミナルに出ていた「年月日_時間分秒 テスト　ファイル　だよ」となっている。
![s3_4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/ad4c98dd-0450-af35-2294-dc682eec7bc3.jpeg)


#### 4.Docker ImageをECRにpushする
構成図の緑の部分を行う
![構成図_4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/fe632121-58c5-1a8d-66e0-ce74c1ea4fc0.jpeg)

1.開発コンテナーを閉じる
![devcon_8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/c928967a-251c-77c4-12c1-b2018d1877a7.png)

2.プロジェクトルートフォルダを開く
![git bash_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/933dd43a-f04d-8dfb-09ed-12f81000fe86.png)

3.awscli.shの「ECRにプッシュしたイメージをlambdaに更新」から下をコメントアウト（範囲選択してCTL + /）
　該当箇所はlambdaにECRイメージを更新する部分で、lambdaはまだ未作成でエラーになるため、ここではコメントアウトする。
```sh:awscli.sh
# ECRにプッシュしたイメージをlambdaに更新
# aws lambda update-function-code --function-name $LAMBDA_FUNC_NAME --image-uri $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$DOCKER_IMAGE_NAME:$IMAGE_TAG > /dev/null 2> /tmp/aws_lambda_error.log

# if [ $? -eq 0 ]; then
#     echo "lambda update success"
# else
#     # エラーメッセージを表示する
#     cat /tmp/aws_lambda_error.log
#     return 1
# fi

# # 一時ファイルを削除
# rm -f /tmp/aws_lambda_error.log
```

4.awscli.shをGit bashで実行する
```none:Git bash
 source awscli.sh
 ```
5.実行結果が下記のようになって成功していることを確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/6b85f429-3156-faa0-7db2-52118ea36f7b.png)

6.ECRでイメージが作成されていることを確認する
![ECR作成_4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/6d7ed421-fc15-7b81-d1fd-8901b17f07ff.jpeg)


#### 5.Lambda作成＆実行
構成図の緑の丸部分を動かす
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/df51f4bd-e956-82f9-50e5-caa726bfdf79.png)

1.関数作成
- 関数の作成
![lambda_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/dc4c3f59-8870-5984-9a7d-cf9247c885b4.png)
 - コンテナイメージを選択。関数名はLAMBDA_FUNC_NAME=★10に設定したものと同じにするので、「lambda-s3」
![lambda_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/2a93c77a-59b9-5f2b-776a-e24f2db8e94f.png)
- ECRのリポジトリを選択する。イメージは、latestを選ぶ。
![lambda_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/450b069a-4457-b128-e727-a484aa410195.png)
![lambda_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/78354848-5ab0-c723-59ed-c93822a512c7.png)
- ロールは後で変更。とりあえず「基本的な～新しいロールを作成」を選んで、関数の作成
![lambda_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/1bbfd168-3938-997e-326e-04576b1a9b82.png)
- Lambdaが選んだECRのイメージで作成されていることを確認する
![lambda_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/a69393c0-c2d2-aa1f-fba6-76d93c24d670.png)

2.設定
1. アクセス権限
- S3への読み書き許可のポリシーを与える
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/984d0c8c-3a14-7b20-f969-7dfbc28a37a8.png)

- インラインポリシーを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/5897a91e-fee9-81d3-261c-c786ae252cbe.png)
- JSONでポリシーを記入。BUCKET_NAME=★6で設定した名前を使う
 ```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::docker-lambda-s3/*"
        }
    ]
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/a3133651-25a9-97c1-f914-87777de6dcc2.png)

- ポリシーの作成（ポリシー名は適当。例：lambda-s3-get-put）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/960f1a5f-1d5a-2fb5-b850-7f631b91b2c3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/cbec1fd4-1120-d554-e62b-36951ff382ca.png)

2.環境変数
- 設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/8eea3695-4551-fc84-2ca3-6f0314bcd9d8.png)
.envのLOG_FILE=★5とBUCKET_NAME=★6をここに記入
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/3c2d6ff2-1783-8de3-532c-62281ed0fde2.png)


2.関数実行
- テストを保存後、テストする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/d909079b-6c8a-6086-6e01-e7f567695e68.png)
- 成功していることを確認する
![lambda_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/4ea3faa3-055c-671e-2952-af896d468ba2.png)


3.S3を確認
- バケット「docker-lambda-s3」の中に、実行した日付「9月5日」のフォルダが作成されており、その中に「年月日_時間分秒.log」が作成されている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/2ab8e5ee-6b98-d377-c3a6-ff2e53d58d6d.png)
- 「年月日_時間分秒.log」の中身を見てみる。
中身が、「年月日_時間分秒 テスト　ファイル　だよ」となっている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/2008d4ce-1da5-8084-25b6-3545d9c1ea07.png)



### 6.修正を反映してみる
構成図の流れ全部
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/1a1def1f-9aff-82d6-2de3-c51401ed9dcb.png)

1.ローカル
- 開発コンテナでlambda_function.pyを修正
例：「追加」を後ろにつける

```python:lambda_function.py
log_content = f"{today_time_str}　テスト ファイル だよ 追加"
```
- 実行した結果は、「年月日_時間分秒 テスト　ファイル　だよ　追加」となっている
![devcon_9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/d77b34bf-3313-8696-1005-571a4c3a1269.png)

- S3確認
    - バケット「docker-lambda-s3」の中に、実行した日付「9月5日」のフォルダが作成されており、その中に「年月日_時間分秒.log」が作成されている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/05052cf5-9a10-5f50-503f-4b128db517f4.png)
    - 「年月日_時間分秒.log」の中身を見てみる。
中身が、lambdaログに出ていた「年月日_時間分秒 テスト　ファイル　だよ　追加」となっている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/2342e200-76e4-0c4a-7db8-3a275c45c1d5.png)

2.開発コンテナ閉じる

3.プロジェクトルートフォルダを開く

4.AWS Cli
.awscli.shの「ECRにプッシュしたイメージをlambdaに更新」から下のコメントアウトを外す（範囲選択してCTL + /）
```sh:awscli.sh
# ECRにプッシュしたイメージをlambdaに更新
aws lambda update-function-code --function-name $LAMBDA_FUNC_NAME --image-uri $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$DOCKER_IMAGE_NAME:$IMAGE_TAG > /dev/null 2> /tmp/aws_lambda_error.log

if [ $? -eq 0 ]; then
    echo "lambda update success"
else
    # エラーメッセージを表示する
    cat /tmp/aws_lambda_error.log
    return 1
fi

# 一時ファイルを削除
rm -f /tmp/aws_lambda_error.log
```

4.awscli.shをGit bashで実行する
```none:Git bash
 source awscli.sh
 ```
- Dockerイメージを作成＆ECRにプッシュ＆lambda更新が出来ているか確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/77c586db-1b9d-37a5-b31e-37a5b17cb900.png)

3.AWS
- lambdaを実行する
ブラウザを更新して、下記のように更新中の場合はまだ反映できていないので実行しない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/ac04c19c-d7f4-7cf9-8a93-43c6276e56bd.png)
下記のように、更新されていると表示されていたり、何も表示されていない場合は実行してＯＫ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/f3b7f8bd-f66e-2a15-4369-ef37cafcfaf2.png)
- テスト実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/c2aec69f-9602-551b-7f5e-e1bc8f153cf6.png)
成功していることを確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/39324e32-16ca-c4a7-6916-183b51e0b104.png)
- S3確認
　- バケット「docker-lambda-s3」の中に、実行した日付「9月6日」のフォルダが作成されており、その中に「年月日_時間分秒.log」が作成されている
　- 「年月日_時間分秒.log」の中身を見てみる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/820c5a89-2067-aa9c-9b9d-80022602e28c.png)
中身が、「年月日_時間分秒 テスト　ファイル　だよ　追加」となっている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/0e1b6ea1-b6a5-e9a5-1802-b329d880e1cd.png)

おしまい。

## プログラム解説

### Dockerfile
Dockerコンテナイメージの構築手順を定義するファイル。
ファイル名はこれじゃないとダメ。


-  public.ecr.aws/lambda/python:3.8というAWS Lambdaと互換性のあるPython 3.8のベースイメージを利用。
```sh:
FROM public.ecr.aws/lambda/python:3.8
```

- 作業ディレクトリを/var/taskに設定。これはLambda関数のデフォルトの作業ディレクトリと一致。
```sh:
# ワーキングディレクトリを設定
WORKDIR /var/task
```

- Pythonのライブラリを追加する場所として/var/task/appを利用するため、PYTHONPATHの環境変数を設定。
```sh:
# PYTHONPATH の設定
ENV PYTHONPATH="/var/task/app"
```

- 依存関係のファイルrequirements.txtをコピー。
 yumコマンドでシステムを更新し、tarやgzipといった必要なパッケージをインストール。pipを最新版に更新し、requirements.txtにリストされたPythonのライブラリをインストール。
```sh:
# 依存関係のコピー
COPY requirements.txt .

# yumを更新し、必要なパッケージをインストール
RUN yum update -y && \
    yum install -y tar gzip

# 依存関係のインストール
RUN pip install --upgrade pip && \
    pip install -r requirements.txt
```

- appディレクトリの内容をコピー。
```sh:
# appディレクトリを/var/task/app/へコピー
COPY app/ /var/task/app/
```

- AWS Lambdaが呼び出す関数としてlambda_function.lambda_handlerを指定。
```sh:
CMD ["lambda_function.lambda_handler"]
```

### docker-compose.yml
Dockerコンテナの設定や連携を定義するファイル。
ファイルの名前を変更するとコマンド実行時にファイル名を指定する必要が出てくるので、基本的にこのファイル名。
- docker-composeのバージョンを指定。
```sh:
version: "3"
```

- services: devという名前のサービスを定義
  - build: Dockerfileを基にコンテナイメージを構築。
  - image & container_name: 環境変数によって指定されるイメージ名とコンテナ名を使用。
  - working_dir: コンテナ内の作業ディレクトリを指定。
  - volumes: ホストとコンテナ間でのディレクトリの共有を指定。これにより、ローカルの変更が即座にコンテナに反映。
  - ports: ホストとコンテナのポートをマッピング。例として、ホストの9000番ポートとコンテナの8080番ポートを結びつけ。
environment & env_file: AWSの認証情報などの環境変数を設定。
```sh:
services:
  dev:
    build:
      context: .
      dockerfile: Dockerfile
    image: $DOCKER_IMAGE_NAME
    container_name: $DOCKER_CONTAINER_NAME
    working_dir: /var/task
    volumes:
      - ./:/var/task
    ports:
      - "9000:8080"
    environment:
      AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY
      AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
    env_file:
      - ./.env
```


### devcontainer.json
VSCodeのRemote - Containers拡張のための設定ファイル。
ファイル名はこれじゃないとダメ。
- name：コンテナの名前を指定。
- dockerComposeFile：使用するdocker-composeのファイルパスを指定。
- service：docker-compose.yml内で使用するサービスを指定。
- workspaceFolder：開発コンテナでの作業ディレクトリをコンテナ内の/var/taskに指定。
- settings：開発コンテナでの使用するターミナルのシェルをbashに指定。
- customizations：開発コンテナでの使用するVSCode拡張機能のリストを指定。
- remoteUser：コンテナ内で操作する際のユーザーをrootとして指定。
- shutdownAction：コンテナのシャットダウンアクションとして、docker-composeの停止を指定。

```sh:
{
  "name": "Lambda Dev Container",
  "dockerComposeFile": "../docker-compose.yml",
  "service": "dev",
  "workspaceFolder": "/var/task",
  "settings": {
    "terminal.integrated.shell.linux": "/bin/bash"
  },
  "customizations": {
    "vscode": {
      "extensions": [
        "amazonwebservices.aws-toolkit-vscode",
        "ms-python.python",
        "njqdev.vscode-python-docstring",
        "magicstack.MagicPython",
        "ms-python.vscode-pylance",
        "kevinrose.vsc-python-indent",
        "esbenp.prettier-vscode",
        "microsoft.vscode-docker",
        "njpwerner.autodocstring"
      ]
    }
  },
  "remoteUser": "root",
  "shutdownAction": "stopCompose"
}
```
### .dockerignore
特定のファイルやディレクトリをDockerビルドから除外するための設定ファイル。
ファイル名はこれじゃないとダメ。
コンテナでは色々なファイルが見れると助かるけど、Imageでは軽量化したかったり、セキュリティ的に含めたくないものをImageにしてECRにpushしないように、不要なものを設定。


### .gitignore
特定のファイルやディレクトリをGitリポジトリの追跡から除外するための設定ファイル。
ファイル名はこれじゃないとダメ。

### .env
環境変数の設定を行うファイル。AWSの認証情報などの重要な情報を含むので、取扱注意！
ファイル名はこれじゃないとダメ。

### awscli.sh
AWS CLIのコマンドをまとめて実行するためのスクリプト。

### requirements.txt
Pythonプロジェクトで使用する外部ライブラリやそのバージョンをリスト化するためのファイル。
ファイル名はこれじゃないとダメ。
このファイルを使用することで、プロジェクトに必要な依存関係を一元管理し、他の環境やサーバーでの再現性を高める。
具体的には、pip install -r requirements.txtコマンドで一括で依存関係をインストール可能。

### appフォルダの中身
- `__init__.py`
このファイルは、appディレクトリをPythonのパッケージとして扱うための特殊なファイル。
ファイル名はこれじゃないとダメ。
具体的な実行内容は無いが、このファイルが存在することで、他のPythonファイルからapp内のモジュールや関数をインポートできるようになる。

- lambda_function.py
AWS Lambdaで動作開始時に呼び出されるスクリプト。
ファイル名は今回の構成ではこれじゃないとダメ。
ログを生成、一時ファイルへ書き込んでS3にログファイルをアップロードする処理をコーディング。

- log_manager.py
ログに関する処理を定義しているファイル。

- s3_uploader.py
Amazon S3にファイルをアップロードするための処理を定義しているファイル。
指定の一時ログファイルを読み込み、S3の指定のキーにアップロード。
アップロード後、一時ログファイルは削除。

## 料金
なんでEC2じゃなくてLambdaで作りたいのかと言うと、驚くほど安い！！からなわけです。
正確なお値段は各自の利用状況で調べて頂きたいのですが、私の「lambda＆S3＆ECR」は、月$1にも満たない感じです。
（20回以上ECRにpushして、lambdaも20回以上テストしているぐらいの利用状況。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/095507e5-39fa-4352-64b5-82899fa7d23a.png)


## まとめ
環境構築するまでが大変ですが、環境を作り終わった後は楽に改修＆Lambdaに反映出来るようになるのが良いと思います。次回はこの仕組みを使って開発して、Lambdaを使ってWebScripingするという内容をまとめたいと思います。