EC-CUBEをサーバレスで動かすための準備運動 〜AWSのリソースを使ってEC-CUBEを動かす〜

# はじめに

3月13日(木)に勉強会発表します。
https://classmethod.connpass.com/event/340667/
EC-CUBEはサーバレスで動かせるのか？
というテーマで発表します。

勉強会で発表するつもりですが、純粋なサーバレスではなく、
Fargate&ECS + ALB + RDS + EFS
のような構成とすることで部分的なサーバレスを実現します。

検証進めている途中ですが、一番ネックになるのはFargate&ECSの部分なので
先にこの部分をEC2内で実行するDockerを使って実現することで、理解を早めようと思いここにログを残します。

# 構成

後々はFargate&ECSで対応しますが、初期構築用EC2としての対応は以下をイメージします。
![ttech202503-ttech202503_ec2検証.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353602/dc23ab8d-7ad5-4f75-8268-47339249fc78.png)
EC2でdockerを立ち上げEC-CUBEを動作させ、
データベースはAurora、共用ストレージとしてEFSを使うというもの。

# AWSサービスの準備

## セキュリティグループ

![security_group.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353602/d9b2c21e-9a7d-4109-9a1c-38b27d1029c2.png)

上記イメージのように5つのセキュリティグループを作成。
- for_ec2 : EC2に設定するセキュリティグループ。80,443を全公開。
- for_efs : EFSに設定するセキュリティグループ。in/out共に全許可。
- for_alb : ALBに設定するセキュリティグループ。80,443を全公開。
- for_ecs : ECSに設定するセキュリティグループ。for_albからの80を受け付ける。
- for_rds : RDSに設定するセキュリティグループ。for_ec2/for_ecs からのアクセスを許可する。

## IAMロール

![iam_role_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353602/f46f0d4b-0fd2-4494-9481-6aaade1105ef.png)
![iam_role_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353602/df18810b-c7fb-4b54-a157-102b8fbd0ab3.png)

2つのIAMロールを作成。
- ttech2025UseECRRole : EC2インスタンスに設定するロール。 AmazonEC2ContainerRegistryFullAccess が許可されていること。
- ecsTaskExecutionRole : ECSで利用するロール。 AmazonECSTaskExecutionRolePolicy が許可されていること。

## EC2

以下の要素でインスタンス作成します。
- インスタンスタイプ : t3.smallで十分
- OS : Amazon Linux 2023
- 付与するIAMロール : ttech2025UseECRRole

インスタンスを立ち上げたら以下実行

```sh
// 検証用EC2にdockerのインストールとサービス起動
# dnf install -y docker
# systemctl start docker

// 検証用EC2にgitのインストールとEC-CUBEのダウンロード
# dnf install -y git
# cd /opt/
# git clone https://github.com/EC-CUBE/ec-cube.git
# cd /opt/ec-cube/
# git branch
* 4.3
// 2025-01 時点では4.3ブランチが最新
// とりあえずなにも変えずビルド
# docker build -t ec-cube .

```

ビルドが完了したら、次はECRの作成に進む。

## ECR

![make_repository.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353602/75116d56-7a9f-46b0-a694-6b942934a5d3.png)

プライベートリポジトリを作成で、ここではリポジトリ名 ec-cube で作成します。
作成したらEC2インスタンスで以下を実行。

```sh
// 検証用EC2でECRログイン(ロール付与してれば成功する)
# aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded

// 検証用EC2からECRへのpushとタグ付け
# 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

```
![ecr_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353602/c8d1ad5d-dd6d-48a8-9085-378aa08937b7.png)

リポジトリ ec-cube のイメージが作成されます。

## RDS

データベースはRDSを利用します。
まずはRDSの作成。
![create_rds.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353602/dff3e436-2b51-4413-9a35-0f312a59766a.png)
ここでは以下で作成しました。
- インスタンスタイプ : db.t3.medium
- セキュリティグループ : for_rds

作成できたらEC2で以下実行。

```sh
// 検証用EC2にmysqlのクライアントをインストール
# dnf -y install https://dev.mysql.com/get/mysql84-community-release-el9-1.noarch.rpm
# dnf -y install mysql
// RDSに接続
# mysql -h ec-cube-cluster.cluster-c9rb6qfpwavf.ap-northeast-1.rds.amazonaws.com -u admin -p
// docker-compose.mysql.yml の設定と同じユーザー/パスワード/DB設定でユーザー登録しておく
mysql> CREATE USER 'dbuser'@'%' IDENTIFIED BY 'secret';
mysql> GRANT ALL PRIVILEGES ON eccubedb.* TO 'dbuser'@'%';
mysql> FLUSH PRIVILEGES;

```

## EFS

複数の環境で同じストレージを使うためEFSを採用しました。
![create_efs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353602/f1da908d-5cee-485c-aa64-6a01e80eb7a4.png)
名前に ec-cube-html と設定しておきます。

![efs_attach.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353602/088cd738-c88f-462b-9cce-bbd67918051d.png)
アタッチの説明を見たら、検証用EC2で以下を実行。
```sh
# dnf install -y amazon-efs-utils
# mkdir /mnt/efs
# chmod 777 /mnt/efs
# mount -t efs -o tls fs-00f0e4ce20d7117fa:/ /mnt/efs

```
chmodフル許可だけど検証だから気にしない！

## EC2でDocker設定

まずは検証用EC2にdocker-composeインストールします。
```sh
# curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose
# docker-compose --version
Docker Compose version v2.33.1
```

docker-compose.yml を変更します。
変更後のymlファイルは以下です。
```yml
version: "3"

networks:
  backend:
    driver: bridge

volumes:
  ### ignore folder volume #####
  var:
    driver: local
  vendor:
    driver: local
  node_modules:
    driver: local

services:
  ### ECCube4 ##################################
  ec-cube:
    ### ローカルでビルドする場合は以下のコマンドを使用します
    ## docker build -t ec-cube --no-cache --pull --build-arg TAG=8.1-apache .
    ## docker tag ec-cube ghcr.io/ec-cube/ec-cube-php:8.1-apache
    image: XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/ec-cube:latest
    ports:
      - 80:80
    volumes:
      ### 同期対象からコストの重いフォルダを除外 #####################
      - "var:/var/www/html/var"
      - "vendor:/var/www/html/vendor"
      - "node_modules:/var/www/html/node_modules"
      - "/mnt/efs/html:/var/www/html/html"
    environment:
      # EC-CUBE environments
      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"
      DATABASE_SERVER_VERSION: 3
      DATABASE_CHARSET: 'utf8'
      ECCUBE_AUTH_MAGIC: "<change.me>"
      # TRUSTED_HOSTS: '^127.0.0.1$$,^localhost$$'
      # ECCUBE_LOCALE: "ja"
      # ECCUBE_TIMEZONE: "Asia/Tokyo"
      # ECCUBE_CURRENCY: "JPY"
      # ECCUBE_ADMIN_ROUTE: "admin"
      # ECCUBE_USER_DATA_ROUTE: "user_data"
      # ECCUBE_ADMIN_ALLOW_HOSTS: []
      # ECCUBE_FORCE_SSL: false
      # ECCUBE_PHPINFO_ENABLED=false
      # ECCUBE_TEMPLATE_CODE: "default"
      # ECCUBE_COOKIE_NAME: "eccube"
      # ECCUBE_COOKIE_PATH: "/"
      # ECCUBE_COOKIE_LIFETIME: 0
      # ECCUBE_GC_MAXLIFETIME: 1440
      # ECCUBE_ADMIN_USER: "admin"
      # ECCUBE_ADMIN_PASS: "password"
    networks:
      - backend
```

変更差分は以下。

```diff
# diff docker-compose.yml docker-compose.new.yml
8,10d7
<   mailcatcher-data:
<     driver: local
<
25c22
<     image: ${REGISTRY:-ghcr.io}/${IMAGE_NAME:-ec-cube/ec-cube-php}:${TAG:-8.1-apache}
---
>     image: XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/ec-cube:latest
27,28c24
<       - 8080:80
<       - 4430:443
---
>       - 80:80
33a30
>       - "/mnt/efs/html:/var/www/html/html"
36,38c33,35
<       APP_ENV: "dev"
<       APP_DEBUG: 1
<       DATABASE_URL: "sqlite:///var/eccube.db"
---
>       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"
41d37
<       MAILER_DSN: "smtp://mailcatcher:1025"
62,69d57
<   ### Mailcatcher ##################################
<   mailcatcher:
<     image: schickling/mailcatcher
<     ports:
<       - "1080:1080"
<       - "1025:1025"
<     networks:
<       - backend
```

EFSの設定。
```sh
// git保有のhtml内容をEFSにコピーする
# cp -pr html/ /mnt/efs/
# chmod -R 777 /mnt/efs/html/
```

最後に docker-compose 起動

```sh
# docker-compose up -d
```

これでEC2インスタンスのIPにアクセスできるかと思います。

![web_top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353602/446f0a52-33f4-446a-890d-06a5c6728c21.png)

EC2でここまで準備したら、次回はFargate&ECSに挑戦してみます。