EC-CUBEをサーバレスで動かす 〜Fargate&ECS実践編〜

# はじめに

無事勉強会の発表が終わりました。
https://classmethod.connpass.com/event/340667/
EC-CUBEはサーバレスで動かせるのか？

勉強会自体は結局「こういう風に構築すれば動かせるぜ」の説明で終始したため
細かい設定等をお見せすることはできなかったので、こちらの記事で設定を残します。

前回の記事は以下をごらんください。
https://qiita.com/tendashimada/items/72dd62b93c91d4a2756b

# 構成

構成は以下をイメージします。
![ttech202503.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353602/f5b55496-bcb3-4350-ad2e-05df6c87b5a5.png)

## タスク定義の作成

Amazon Elastic Container Service → 新しいタスク定義の作成 に進みます。
コンテナの詳細は以下設定
- 名前 : eccube
- イメージ URI : XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/ec-cube:latest

環境変数は以下設定
- APP_ENV : prod
- APP_DEBUG : 0
- DATABASE_URL : mysql://dbuser:secret@ec-cube-cluster.cluster-c9rb6qfpwavf.ap-northeast-1.rds.amazonaws.com:3306/eccubedb?charset=utf8mb4
- ECCUBE_AUTH_MAGIC : <secure-key>

ボリューム関連は以下設定
- ボリューム名 : html-volume
- ボリュームタイプ : EFS
- ファイルシステム ID : fs-00f0e4ce20d7117fa
- ルートディレクトリ : /html

コンテナマウントポイントは以下設定
- コンテナ : eccube
- ソースボリューム : html-volume
- コンテナパス : /var/www/html/html

設定内容のキャプチャ(とても長い)はこんな感じ。
![taskdef.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353602/365467d8-3f68-47b7-b016-6ae026f85d01.png)

作成したらjsonタブを開き「JSONのダウンロード」を実行しておきましょう。
上記の作成内容は以下の通り。
```json
{
    "taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task-definition/ec-cube:2",
    "containerDefinitions": [
        {
            "name": "eccube",
            "image": "XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/ec-cube:latest",
            "cpu": 0,
            "portMappings": [
                {
                    "name": "eccube-80-tcp",
                    "containerPort": 80,
                    "hostPort": 80,
                    "protocol": "tcp",
                    "appProtocol": "http"
                }
            ],
            "essential": true,
            "environment": [
                {
                    "name": "ECCUBE_AUTH_MAGIC",
                    "value": "<secure-key>"
                },
                {
                    "name": "APP_ENV",
                    "value": "prod"
                },
                {
                    "name": "DATABASE_URL",
                    "value": "mysql://dbuser:secret@ec-cube-cluster.cluster-c9rb6qfpwavf.ap-northeast-1.rds.amazonaws.com:3306/eccubedb?charset=utf8mb4"
                },
                {
                    "name": "APP_DEBUG",
                    "value": "0"
                }
            ],
            "environmentFiles": [],
            "mountPoints": [
                {
                    "sourceVolume": "html-volume",
                    "containerPath": "/var/www/html/html",
                    "readOnly": false
                }
            ],
            "volumesFrom": [],
            "ulimits": [],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "/ecs/ec-cube",
                    "mode": "non-blocking",
                    "awslogs-create-group": "true",
                    "max-buffer-size": "25m",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "ecs"
                },
                "secretOptions": []
            },
            "systemControls": []
        }
    ],
    "family": "ec-cube",
    "executionRoleArn": "arn:aws:iam::XXXXXXXXXXXX:role/ecsTaskExecutionRole",
    "networkMode": "awsvpc",
    "revision": 2,
    "volumes": [
        {
            "name": "html-volume",
            "efsVolumeConfiguration": {
                "fileSystemId": "fs-00f0e4ce20d7117fa",
                "rootDirectory": "/html"
            }
        }
    ],
    "status": "ACTIVE",
    "requiresAttributes": [
        {
            "name": "ecs.capability.execution-role-awslogs"
        },
        {
            "name": "com.amazonaws.ecs.capability.ecr-auth"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.28"
        },
        {
            "name": "ecs.capability.execution-role-ecr-pull"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
        },
        {
            "name": "ecs.capability.task-eni"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.29"
        },
        {
            "name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
        },
        {
            "name": "ecs.capability.efsAuth"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
        },
        {
            "name": "ecs.capability.efs"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.25"
        }
    ],
    "placementConstraints": [],
    "compatibilities": [
        "EC2",
        "FARGATE"
    ],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "1024",
    "memory": "3072",
    "runtimePlatform": {
        "cpuArchitecture": "X86_64",
        "operatingSystemFamily": "LINUX"
    },
    "registeredAt": "2025-03-07T10:00:09.188Z",
    "registeredBy": "arn:aws:iam::XXXXXXXXXXXX:user/shimada",
    "enableFaultInjection": false,
    "tags": []
}
```

## サービスの作成

設定内容をキャプチャしたものは以下です。こちらも長い。
![create_service.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353602/266b7402-ae47-4da8-8d9d-42eaa6727ff0.png)

サービス作成にてセキュリティグループを for_ecs で設定します。
このまま起動すると、ALBのセキュリティグループも for_ecs になっているので、 ALBのセキュリティグループは for_alb に変更してください。
また、サービス作成と同時にALB作成した場合細かい設定ができておらず、ターゲットグループの振り分けがラウンドロビンになっています。
維持設定とか適宜修正してください。

## その他の設定

ALBの設定のセキュアリスナーはACMで取得した証明書にしておきます。
![alb_https2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353602/b6b2f092-1479-4e7e-9029-2ae33674ac21.png)

これで代替ドメインでアクセスできるので、 https でアクセスできるはず。

ただ、カートに入れようとしたらエラーとなってしまいました。
どうやらカートに入れるボタンがhttpになっているからのようです。
ということでEC-CUBEのソースを修正してみます。

EC2インスタンスで以下修正を実施。
```sh
// 回避策を取る。検証用EC2で以下設定。
# cd /opt/ec-cube/
# vi index.php
# git diff index.php
diff --git a/index.php b/index.php
index 001279a600..d33974a002 100644
--- a/index.php
+++ b/index.php
@@ -55,6 +55,10 @@ if ($trustedHosts) {
     Request::setTrustedHosts(explode(',', $trustedHosts));
 }

+if (@$_SERVER["HTTP_X_FORWARDED_PROTO"] === 'https') {
+    $_SERVER['HTTPS'] = 'on';
+}
+
 $request = Request::createFromGlobals();
```

index.phpを編集したので、ECRを最新化してECSに反映します。
```sh
# docker build -t ec-cube .
# aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com
# docker tag ec-cube:latest XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/ec-cube:latest
# docker push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/ec-cube:latest
```

最後にサービスの強制更新を実施します。

ここまでやれば、
Fargate&ECS + ALB + RDS + EFS
が実現できます。

需要は多くないでしょうが必要とするごく一部の方が幸せになればと願ってここに残します。
ここまでみていただきありがとうございました。