ServerlessFrameworkでLambdaからFargateコンテナを呼びだす

Lamdaからboto3でFargateのコンテナを起動する際の手順です。
ググると簡単にできそうなのですが、私はなぜか盛大にハマってかなり時間がかかったので注意点を記載します。

## serverless.ymlの設定

まず、IAMでECSアクセスのポリシーを付与します。

```serverless.yml
provider:
  iamManagedPolicies: # Optional IAM Managed Policies, which allows to include the policies into IAM Role
      - arn:aws:iam::aws:policy/AmazonECS_FullAccess
```

なお、上記のポリシーが付与されていないと以下のようなエラーが出力されます。
翻訳すると「実行が許可されていません。」ということらしいです。

```
An error occurred (AccessDeniedException) when calling the PutRule operation: User: arn:aws:sts::999999999999:assumed-role/demo-service-lambda-dev-ap-northeast-1-lambdaRole/demo-service-lambda-dev-fargate is not authorized to perform: events:PutRule on resource: arn:aws:events:ap-northeast-1:999999999999:rule/fargate-run
```

## 呼び出し側のlambdaの設定

```test.py
    ecs = boto3.client('ecs')
    response = ecs.run_task(
        cluster='selenium',
        taskDefinition='fargate-shell',
        launchType='FARGATE',
        overrides={
            'containerOverrides': [
                {
                    'name': 'far',
                    'command': ["./test.sh",
                                "aaa"],
                    'memory': 64
                }
            ]
        }
    )


```
当初こんな感じでLambdaを起動したところ、以下のようなエラーが出ました。
翻訳すると「networkMode 'awsvpc' が指定されている場合は、ネットワーク設定を提供する必要があります。」

```
An error occurred (InvalidParameterException) when calling the RunTask operation: Network Configuration must be provided when networkMode 'awsvpc' is specified.

```

そこで思い出したのが、ecs-cliでFargateを起動した時のパラメータファイルです。

```ecs-params.yml
version: 1
task_definition:
  ecs_network_mode: awsvpc
  task_execution_role: ecsTaskExecutionRole
  task_size:
    cpu_limit: 256
    mem_limit: 512
  services:
    fargate:
      secrets:
        - value_from: AAA
          name: TOKEN

run_params:
  network_configuration:
    awsvpc_configuration:
      subnets:
        - subnet-12345678901234567
        - subnet-12345678901234568
      security_groups:
        - sg-12345678901234567
      assign_public_ip: ENABLED
```

ecs-cliでは、問題なく呼び出せたのでserverless.ymlにawsvpcの設定を追加しました。
ここが大ハマリする分かれ目でした。。

```serverless.yml
provider:
  iamManagedPolicies: # Optional IAM Managed Policies, which allows to include the policies into IAM Role
      - arn:aws:iam::aws:policy/AmazonECS_FullAccess

〜〜〜〜〜省略〜〜〜〜
functions:
  hello:
    handler: handler.hello
### ↓追加 ###
    vpc:
      securityGroupIds:
        - sg-12345678901234567
      subnetIds:
        - subnet-12345678901234567
        - subnet-12345678901234568
### ↑追加 ###
    events:
      - http:
          path: /test
          method: post
```

## さっきのエラーは解消した！！！
実行してみると、「networkMode 'awsvpc' が指定されている場合は、ネットワーク設定を提供する必要があります。」のエラーは解消していました。
ただ、timeoutoのエラーが発生しています。

```
2020-06-09T11:19:13.298Z ec5e6182-10f7-494a-b781-f108a3789387 Task timed out after 6.01 seconds
```
まずやったのは、lambdaのtimeoutの設定変更です。Fargateの起動が1分弱くらいなので、それが関係ある？？とりあえず余裕をみて120秒を設定。

```serverless.yml
functions:
  hello:
    handler: handler.hello
### ↓追加 ###
    timeout: 120
### ↑追加 ###
    vpc:
      securityGroupIds:
        - sg-12345678901234567
      subnetIds:
        - subnet-12345678901234567
        - subnet-12345678901234568
    events:
      - http:
          path: /test
          method: post
```

当初APIGatewayからLambdaを起動していましたが、APIGatewayは30秒でtimeoutしてしまうので、S3から起動するように修正。

```serverless.yml

〜〜〜省略〜〜〜
functions:
  hello:
    handler: handler.hello
    timeout: 120
    vpc:
      securityGroupIds:
        - sg-12345678901234567
      subnetIds:
        - subnet-12345678901234567
        - subnet-12345678901234568
    events:
      - http:
          path: /test
          method: post
### ↓追加 ###
      - s3:
          bucket: "s3test-fargate"
          event: s3:ObjectCreated:*
          rules:
            - prefix: test/
          existing: true
### ↑追加 ###
```

S3をトリガにしてLambdaを実行してみたが120秒でtimeout・・。

```
2020-06-09T11:31:12.118Z 0e01d9c6-1b62-4a5e-9fd2-c1ae84f80b98 Task timed out after 120.01 seconds
```

## Lambdaの設定も追加してみる
```test.py
    ecs = boto3.client('ecs')
    response = ecs.run_task(
        cluster='selenium',
        taskDefinition='fargate-shell',
        launchType='FARGATE',
        ################# 追加 #################
        networkConfiguration={
            'awsvpcConfiguration': {
                'subnets': [
                    'subnet-12345678901234567',
                    'subnet-12345678901234568'
                ],
                'securityGroups': [
                    'sg-12345678901234567'
                ],
                'assignPublicIp': 'ENABLED'
            }
        },
        ################# 追加 #################
        overrides={
            'containerOverrides': [
                {
                    'name': 'far',
                    'command': ["./test.sh",
                                "aaa"],
                    'memory': 64
                }
            ]
        }
    )
```

boto3のecsに`networkConfiguration`の設定項目があったので、lambdaの設定と全く同じ内容で追加してみました。そして再度実行しましたが、、やはりtimeout。

あとは↓こんなことをやってみましたが、常にtimeoutで進展なし。。
・セキュリティグループIDとVPCIDを間違えていたので修正。
・timeoutを5分まで延長
・LambdaにAdministratorAccessのポリシーを割り当てる
・セキュリティグループのインバウント、アウトバウンドの設定を全て開放する

## 結論

serverless.ymlでLambda関数にvpcの設定を入れていたことがtimeoutの原因だったようです。
この設定を外すとうまく行きました。
なぜ、ダメなのかはっきりとは理解できていませんが、みなさん気をつけてください。。

```serverless.yml

〜〜〜省略〜〜〜
functions:
  hello:
    handler: handler.hello
    timeout: 120

######　この設定が原因だった　######
#    vpc:
#      securityGroupIds:
#        - sg-12345678901234567
#      subnetIds:
#        - subnet-12345678901234567
#        - subnet-12345678901234568
    events:
      - http:
          path: /test
          method: post
      - s3:
          bucket: "s3test-fargate"
          event: s3:ObjectCreated:*
          rules:
            - prefix: test/
          existing: true
```