内容
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 :3000 や docker 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