0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

EC2上のWebアプリをオールDocker化(Next.js+Spring Boot+MySQL) 備忘録

0
Posted at

内容

EC2上でそれぞれ単体で動いていた「Next.js」「Spring Boot」「Docker(MySQL)」のシステム構成を、すべてDocker(Docker Compose)で一元管理する構成へ変更。

1. Dockerfileとdocker-compose.ymlの設計と作成

概要

各コンテナの「詳細な指示書(Dockerfile)」と、それらを統括して重ね合わせる「全体指示書(docker-compose.yml)」を作成・整理。

構成イメージ

  • Dockerfile:料理で例える「焼きそば」「お好み焼き」のような個々の部品のレシピ。
  • docker-compose.yml:それらをどう重ねて、どういう順番で起動するかを決める「広島風お好み焼き」のレシピ。
  • MySQL:今回はDockerfileを作らず完成品イメージをそのまま使うため、「永谷園のお茶漬けの素」のような位置付け。

作成したファイル

frontend/Dockerfile (Next.js用)
# 1. ビルドステージ
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# 2. 本番ステージ
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app ./
EXPOSE 3000
CMD ["npm", "start"]
backend/Dockerfile (Spring Boot用)
FROM eclipse-temurin:17-jdk
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
docker-compose.yml (全体統括用)
version: "3.8"

services:
  frontend:
    build: ./frontend-prod
    ports:
      - "3000:3000"
    depends_on:
      - backend

  backend:
    build: ./backend-prod
    ports:
      - "8080:8080"
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/demo?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=utf8
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: root
    depends_on:
      - mysql
  
  mysql:
    image: mysql:8.0
    container_name: mysql8
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: demo
      TZ: Asia/Tokyo
      LANG: C.UTF-8
      LC_ALL: C.UTF-8
      MYSQL_CHARSET: utf8mb4
      MYSQL_COLLATION: utf8mb4_unicode_ci
    ports:
      - "3306:3306"
    volumes:
      - ~/mysql-init:/docker-entrypoint-initdb.d

EC2へファイル送信

0.backend-prodフォルダを作成(これだけTeraTeam上で実行)
⇒mkdir -p backend-prod/target

1.SpringBootを./mvnw.cmd clean package -DskipTestsでjarファイルを最新

2.jarファイルをEC2へ送信
⇒scp -i "C:\Users\nayut\AWS\Key\gakumas-key.pem" "C:\Users\nayut\Documents\開\DEV2026_002\demo\target\demo-0.0.1-SNAPSHOT.jar" ec2-user@13.238.116.102:/home/ec2-user/backend-prod/target

3.Next.js関連をEC2へ送信(.next/node-module以外)
⇒scp -i "C:\Users\nayut\AWS\Key\gakumas-key.pem" -r "C:\Users\nayut\Documents\開\DEV2026_002\frontend-prod" ec2-user@13.238.116.102:~

4.dockerfile⇒frontend-prod EC2へ送信
⇒scp -i "C:\Users\nayut\AWS\Key\gakumas-key.pem" "C:\Users\nayut\Documents\開\DEV2026_002\demo\docker\frontend\Dockerfile" ec2-user@13.238.116.102:/home/ec2-user/frontend-prod

5.dockerfile⇒backend-prod EC2へ送信
⇒scp -i "C:\Users\nayut\AWS\Key\gakumas-key.pem" "C:\Users\nayut\Documents\開\DEV2026_002\demo\docker\backend\Dockerfile" ec2-user@13.238.116.102:/home/ec2-user/backend-prod

6.docker-compose.yml⇒home EC2へ送信
⇒scp -i "C:\Users\nayut\AWS\Key\gakumas-key.pem" "C:\Users\nayut\Documents\開\DEV2026_002\demo\docker-compose.yml" ec2-user@13.238.116.102:~

2. 旧コンテナ生成時の「不要なゴミ」によるビルドエラーの防止

概要

EC2のNext.jsコード(frontend-prod)の中に、古い node_modules.next が残ったままだと、コンテナ内に不純物がコピーされてビルドエラーを引き起こす。事前にこれらを物理削除。

実行コマンド

隠しフォルダを表示する -a オプション(ls -al)で .next の存在を確認し、削除。

cd ~/frontend-prod
ls -al  # 隠しフォルダの確認
rm -rf node_modules
rm -rf .next

3. 【エラー】Node.jsのバージョン不足によるビルド失敗

発生した現象

docker compose up -d --build の初回実行時、Next.jsのビルドステージでプロセスが異常終了。

エラーログ

You are using Node.js 18.20.8. For Next.js, Node.js version ">=20.9.0" is required.
failed to solve: process "/bin/sh -c npm run build" did not complete successfully: exit code: 1

原因と対策

EC2のNode.jsではなく、Dockerfileの1行目で指定した使い捨てビルド用コンテナ(builder)のNode.jsバージョンが古いことが原因。
frontend/Dockerfile を開き、Node.jsのベースイメージを 18-alpine から 20-alpine へ修正(2箇所)。

nano ~/frontend-prod/Dockerfile
# node:18-alpine を node:20-alpine に書き換えて保存

4. 【エラー】AWS(EC2)のディスク容量不足(ENOSPC)

発生した現象

Node.jsバージョン変更後に再ビルドを走らせたところ、npm install の途中でストレージ容量を使い果たしクラッシュ。

エラーログ

npm warn tar TAR_ENTRY_ERROR ENOSPC: no space left on device

原因と対策

Next.jsのコンテナビルドは一時的に大量の容量を消費するため、EC2初期設定の8GB(空き2.9GB)では物理的に不足。
Dockerのキャッシュ掃除を実行。

# Dockerのビルドキャッシュや古い未使用イメージを一括掃除
docker system prune -a --volumes -f
df -h  # ディスク空き容量の確認

5. 【エラー】ゾンビコンテナによるポート競合(3000番)

発生した現象

容量拡張後、再度起動を試みるも「3000番ポートがすでに使われている」とDocker daemonから拒否される現象が発生。

エラーログ

Error starting userland proxy: listen tcp4 0.0.0.0:3000: bind: address already in use

原因と対策

sudo lsof -i :3000docker ps(起動中コンテナ一覧)には何も映らないものの、前回のビルド失敗時に中途半端に残った停止中のコンテナの残骸(ゾンビコンテナ)がポートをロック。また、OSカーネルのネットワークテーブル(TIME_WAIT状態)による誤認も重なっていた。

安易に3001番ポート等へ逃げる本番環境のアンチパターンを避け、3000番を通すためにコンテナ残骸の強制一掃とEC2の再起動を実行。

# 停止中も含めたすべてのコンテナの残骸を強制全削除
docker rm -f $(docker ps -aq) 2>/dev/null

# Linuxカーネルのネットワークロックを安全に初期化するためOS再起動
sudo reboot

6. 【エラー】MySQLの破損データによる即死 & アプリ接続失敗

発生した現象

EC2再起動後、コンテナ自体は Started になるものの、バックエンド(Spring Boot)のログにデータベース接続エラーが多発。

エラーログ

[mysql8] [ERROR] --initialize specified but the data directory has files in it. Aborting.
[backend] ERROR 1 --- [main] o.h.engine.jdbc.spi.SqlExceptionHelper : Communications link failure

原因と対策

手順4の容量100%のタイミングでMySQLがクラッシュしたため、永続化ボリューム(/var/lib/mysql)の中に壊れた初期化ゴミファイルが残ってしまい、MySQLコンテナが起動直後に即死(Aborting)。
コンテナを落とした後、壊れたデータボリュームを完全にクレンジングして初期化をやり直すことで解決。

docker compose down
docker volume prune -f  # 破損した初期化ボリュームを安全にリセット
docker compose up -d    # 再起動

成果(結果)

すべてのエラーを根本から解決した結果、以下の通り3つのコンテナが正常に共存・生存するオールDocker環境が完成。

\$ docker ps
CONTAINER ID   IMAGE               STATUS          PORTS                                      NAMES
a0e24903fbd0   ec2-user-frontend   Up 12 seconds   0.0.0.0:3000->3000/tcp                     ec2-user-frontend-1
4633a7f5bd01   ec2-user-backend    Up 13 seconds   0.0.0.0:8080->8080/tcp                     ec2-user-backend-1
cd01676de163   mysql:8.0           Up 13 seconds   0.0.0.0:3306->3306/tcp, 33060/tcp           mysql8
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?