AWS lambda nodeをローカルでdocker開発して、イメージデプロイする



https://aws.amazon.com/jp/builders-flash/202103/new-lambda-container-development/?awsf.filter-name=*all

AWS lambdaの開発にSAMを使用していましたが、ローカルでdocker開発して、そのままデプロイできるようになったらしいので手順の確認。

dockerのイメージ生成→AWSのECRリポジトリにPUSH→AWS Lambda にECRからデプロイ。

https://qiita.com/rei-ta/items/e86546130d157561ba8e

Dockerfile
docker-compose.yml
package.json
app.js

Dockerfile

```
FROM public.ecr.aws/lambda/nodejs:16
COPY app.js package*.json ./
RUN npm install
CMD [ "app.lambdaHandler" ]
```

ecrイメージでのdockerを作成。public.ecr.aws/lambda/nodejs:16

docker-compose.yml

```
version: '3'
services:
  cloudsearch-api:
    image: cloudsearch-api
    build: .
    ports:
      - 9199:8080
    tty: true
    volumes:
      - "./data/:/var/task/data"
    working_dir: /var/task/

```


package.json
「 "type": "module",」は、AWS lambdaで実行する際に、ES6と認識させるためのおまじない。

```
{
    "type": "module",
    "dependencies": {
        "@aws-sdk/client-cloudsearch-domain": "^3.159.0"
    }
}
```


app.js
AWS公式のサンプルから、ES6+形式 cloudsearchからデータを取得するだけのコード

```
import { CloudSearchDomainClient, SearchCommand } from "@aws-sdk/client-cloudsearch-domain";
const client = new CloudSearchDomainClient({
  region: 'ap-northeast-1'
  , endpoint: 'https://search-xxxxxxxxxxxxxxxxx.ap-northeast-1.cloudsearch.amazonaws.com'
  , credentials: { accessKeyId: 'AKXXXXXXXXXXXXZWH', secretAccessKey: '6o6FDDDDDDDDDDDDDDDDDDDDDDDO' },
});

export const lambdaHandler = async (event, context) => {

  var params = {
    query: query: event.queryStringParameters.q
  };
  const command = new SearchCommand(params);
  // async/await.
  try {
    var data = await client.send(command);
    // process data.
  } catch (error) {
    console.log(error);
    // error handling.
  } finally {
    // finally.
  }

  return {
    statusCode: 200,
    body: data,
  };;
};


```

build 
```
$ docker build -t cloudsearch-api .
[+] Building 14.3s (8/8) FINISHED
 => [internal] load build definition from Dockerfile               0.1s
 => => transferring dockerfile: 153B                               0.0s
 => [internal] load .dockerignore                                  0.1s
 => => transferring context: 2B                                    0.0s
 => [internal] load metadata for public.ecr.aws/lambda/nodejs:16   0.0s
 => [internal] load build context                                  0.0s
 => => transferring context: 985B                                  0.0s
 => CACHED [1/3] FROM public.ecr.aws/lambda/nodejs:16              0.0s
 => [2/3] COPY app.js package*.json ./                             0.1s
 => [3/3] RUN npm install                                         13.8s
 => exporting to image                                             0.2s
 => => exporting layers                                           0.2s
 => => writing image sha256:624f55e0a75f2666da7797d6b311611d32da7cf825aec867bf6922f78ad9f613          0.0s
 => => naming to docker.io/library/47news-cloudsearch-api                  

```

作成した、イメージに、ECRにデプロイするためのタグを付与する
docker tag {作成したイメージ} {AWS ID}.dkr.ecr.{region}.amazonaws.com/{ECRイメージ名}

```
docker tag cloudsearch-api:latest 8xxxxxxxxxxxx2.dkr.ecr.ap-northeast-1.amazonaws.com/cloudsearch-api:latest
```

```
$ docker images
REPOSITORY                                                            TAG                   IMAGE ID       CREATED         SIZE
8xxxxxxxxxxxx2.dkr.ecr.ap-northeast-1.amazonaws.com/cloudsearch-api   latest                624f55e0a75f   8 minutes ago   495MB
47news-cloudsearch-api                                                latest                624f55e0a75f   8 minutes ago   495MB
```

PUSHするために事前にECRリポジトリにログイン
--profileが必要な環境の場合は忘れずに。

```
 aws ecr get-login-password --region ap-northeast-1 --profile tanigawa.rei| docker login --username AWS --password-stdin 8xxxxxxxxxxxx2.dkr.ecr.ap-northeast-1.amazonaws.com

```


AWS ECRにリポジトリを作成
```
$ aws ecr create-repository --repository-name cloudsearch-api --profile tanigawa.rei
{
    "repository": {
        "repositoryArn": "arn:aws:ecr:ap-northeast-1:8xxxxxxxxxxxx2:repository/cloudsearch-api",
        "registryId": "8xxxxxxxxxxxx2",
        "repositoryName": "47news-cloudsearch-api",
        "repositoryUri": "8xxxxxxxxxxxx2.dkr.ecr.ap-northeast-1.amazonaws.com/cloudsearch-api",
        "createdAt": "2022-08-28T09:25:23+09:00",
        "imageTagMutability": "MUTABLE",
        "imageScanningConfiguration": {
            "scanOnPush": false
        },
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        }
    }
}
```


push
```
reita@antares:~/work/47news-cloudserach-api$ docker push 8xxxxxxxxxxxx2.dkr.ecr.ap-northeast-1.amazonaws.com/47news-cloudsearch-api:latest
The push refers to repository [8xxxxxxxxxxxx2.dkr.ecr.ap-northeast-1.amazonaws.com/47news-cloudsearch-api]
07685b2aaf58: Pushed 
ffd7c3a91706: Pushed 
aad36147b931: Pushed 
573ca4d658ec: Pushed 
e44da8829878: Pushed 
56f4a848bdee: Pushed 
28228b277b60: Pushed 
c777e9b43a56: Pushed 
latest: digest: sha256:8b098f30431a0d0328310a9381d200e459848b82dc8c643960e72e5e90f20d13 size: 1998
```

コンソールからpushしたいDockerイメージが確認できます。digest値などを確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83911/0f475a26-72c5-9636-b750-d9fc7ec6196c.png)


lambda functionを作成。CLI経由でも、コンソールでも。ロールの指定が必要なので、コンソールのほうが作りやすいかも。決まっているロールがあれば、それを使用するだけですので、CLIから
aws: error: argument --role: expected one argument
roleをつけないと、エラーになります。

```
 aws lambda create-function      --function-name cloudsearch-api       --package-type Image      --code ImageUri=8xxxxxxxxxxxx2.dkr.ecr.ap-northeast-1.amazonaws.com/47news-cloudsearch-ap@8b098f30431a0d0328310a9381d200e459848b82dc8c643960e72e5e90f20d13 --profile tanigawa.rei --role arn:aws:iam::884510347902:role/lambda-s3-execution-role
```


コンソールの場合、作成して、Deploy new imageからデプロイ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83911/b8aeff81-da11-756d-5758-7f3c56c9962d.png)

Blowser ImagesからPUSHしたイメージを手動選択できます。（digest値を控えなくてよくて簡単）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83911/559ec01d-143d-724c-ad12-cd8a3699272b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83911/6f6795c0-e1c3-6747-5893-a5bed70e93bd.png)

選択した後にSAVEしてデプロイ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83911/8c983748-b2aa-5af1-125b-d91ed8ce7c8e.png)

少し時間がかかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83911/6395d6e5-98f1-c42d-bb77-5749a5edaec6.png)


successfully!!