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?

Spring Bootはjarだけでも動く。それでもDockerを使うのはなぜ?

0
Posted at

Spring BootアプリケーションをAWSへデプロイする方法を調べていると、Dockerがよく登場します。

例えば、ECS + Fargateを利用する場合は次のような構成です。

Spring Boot
    ↓
Docker Image
    ↓
ECR
    ↓
ECS
    ↓
Fargate

しかし、ここで疑問が出てきました。

Spring Bootってjarファイルをサーバーに置いて実行すれば動くのでは?

実際、その通りです。

Dockerを使わなくてもSpring Bootアプリケーションは動かせます。

では、なぜDockerを利用するのでしょうか。

この記事では、

「Dockerを使わず直接jarを実行する方法」と「Dockerを利用する方法」の違い

から、Dockerを利用する理由を整理します。


そもそもSpring BootはDockerなしでも動く

Spring Bootアプリケーションはビルドすると、jarファイルとして出力できます。

Mavenなら、例えば次のようにビルドできます。

./mvnw clean package

すると、

target/
└── application.jar

のようなjarファイルが生成されます。

Javaがインストールされたサーバーへjarファイルを配置すれば、

java -jar application.jar

でSpring Bootアプリケーションを起動できます。

つまり、例えばEC2を使うなら、

Internet
    |
    v
+-------------------+
|       EC2         |
|                   |
| Java 21           |
| application.jar   |
|                   |
| java -jar ...     |
+-------------------+

という構成でもアプリケーションを動かせます。


Apache HTTP Serverは必須ではない

Webアプリケーションというと、

Apache HTTP Server
↓
Javaアプリケーション

のような構成を想像するかもしれません。

しかし、一般的なSpring BootのWebアプリケーションでは、TomcatなどのWebサーバーが組み込まれています。

そのため、

java -jar application.jar

だけでHTTPリクエストを受け取れるWebアプリケーションとして起動できます。

つまり、単純な構成なら、

Linux
↓
Java
↓
Spring Boot jar

だけでも動かせます。

では、なぜわざわざDockerを追加するのでしょうか。


Dockerなしの場合は「サーバー側に環境を作る」

Dockerを使わずEC2へ直接デプロイするとします。

まずEC2を作成します。

その後、

EC2を起動
↓
Javaをインストール
↓
必要な設定をする
↓
jarを配置
↓
環境変数を設定
↓
アプリを起動

という作業が必要になります。

例えばアプリケーションがJava 21を必要としているなら、EC2側にも対応するJava環境が必要です。

Spring Boot Application
        |
        | Java 21が必要
        v
EC2
└── Java 21

これは1台だけなら、それほど問題には見えません。


サーバーが増えると環境管理が大変になる

例えば同じアプリケーションを3台のサーバーで動かすとします。

EC2 A
├── Java 21
├── 設定
└── application.jar

EC2 B
├── Java 21
├── 設定
└── application.jar

EC2 C
├── Java 21
├── 設定
└── application.jar

すべて同じ環境にする必要があります。

しかし、長期間運用していると、

EC2 A
Java 21

EC2 B
Java 21

EC2 C
Java 17 ← あれ?

といった環境差分が発生する可能性があります。

ほかにも、

このサーバーだけ設定が違う

このサーバーだけライブラリが古い

開発環境では動いたのに本番では動かない

といった問題が起こり得ます。


Dockerでは「実行環境」をコードとして定義できる

Dockerを利用すると、アプリケーションを実行するための環境をDockerfileに記述できます。

例えばSpring Bootなら、単純化すると次のように書けます。

FROM eclipse-temurin:21-jre

COPY target/application.jar application.jar

ENTRYPOINT ["java", "-jar", "application.jar"]

ここでは、

Java 21の環境を使う

application.jarを配置する

java -jar application.jar で起動する

という情報をDockerfileとして定義しています。

そしてDockerfileからDocker Imageを作成します。

Dockerfile
    |
    | docker build
    v
Docker Image

このDocker Imageを使ってコンテナを起動します。


Docker Imageには実行環境をまとめられる

Docker Imageには、アプリケーションだけでなく、その実行に必要な環境も含められます。

イメージとしては、

+----------------------+
|     Docker Image     |
|                      |
| Java Runtime         |
| application.jar      |
| 起動方法             |
+----------------------+

となります。

そのため、

サーバー側にJava 21をインストールしておいてください

ではなく、

このDocker Imageを実行してください

という形でアプリケーションを扱いやすくなります。


「自分のPCでは動いたのに」を減らせる

開発ではよく、

開発者PC
↓
動いた!

本番サーバー
↓
動かない!

という問題があります。

原因の一つが実行環境の違いです。

例えば、

開発環境
Java 21

本番環境
Java 17

なら、当然問題が発生する可能性があります。

Dockerを使えば、

開発環境
   |
   v
Docker Image A

テスト環境
   |
   v
Docker Image A

本番環境
   |
   v
Docker Image A

のように、同じイメージを各環境で利用できます。

もちろんOSやCPUアーキテクチャ、外部サービスなどの違いまで完全になくなるわけではありません。

それでも、アプリケーションの実行環境を統一しやすくなるのはDockerの大きなメリットです。


Docker Imageを「アプリの配布物」にできる

Dockerを使わない場合、デプロイするものはjarファイルだけではありません。

場合によっては、

jarを配置する

Javaを準備する

起動方法を設定する

必要な依存関係を準備する

といった作業も必要です。

Dockerを使うと、

Docker Image

をアプリケーションの配布単位として扱えます。

例えば、

application:v1
application:v2
application:v3

のようにイメージへタグを付けて管理できます。

AWSならAmazon ECRなどにDocker Imageを保存できます。

Developer
    |
    | docker build
    v
Docker Image
    |
    | push
    v
+------------------+
|       ECR        |
+------------------+
    |
    | pull
    v
ECS / Fargate

ECS・FargateとDockerの相性が良い

AWSでECS + Fargateを利用する場合、DockerなどのOCI互換コンテナイメージを利用してアプリケーションを実行できます。

例えば、

Spring Boot
    ↓
Docker Image
    ↓
ECR
    ↓
ECS
    ↓
Fargate Task

という流れです。

利用者は、

このコンテナイメージを使う

CPUはこれくらい

メモリはこれくらい

環境変数はこれ

といったTask Definitionを設定します。

Fargateを利用する場合、コンテナを動かすためのEC2インスタンスを自分で用意する必要はありません。


Taskが壊れても作り直しやすい

Dockerコンテナを使う構成では、

「動いているサーバーを修理する」より「同じイメージから新しいコンテナを作る」

という考え方を取りやすくなります。

例えばECS Serviceで、

Desired Count = 2

としていたとします。

正常時は、

Task A
Task B

の2つが動いています。

Task Aが停止すると、

Task A
  ↓
停止

ECS Service
「Taskが1つ足りない」

  ↓

新しいTaskを起動

  ↓

Task B
Task C

という形で必要なTask数を維持できます。

新しく作られるTaskも、指定されたコンテナイメージを利用します。

つまり、

壊れたサーバーへSSH
↓
原因を調査
↓
その場で修正

だけではなく、

問題のあるTaskを終了
↓
同じImageから新しいTaskを起動

という運用がしやすくなります。


スケールもしやすい

アクセスが増えてTaskを増やしたい場合も、コンテナ化されていると同じ環境を複製しやすくなります。

Docker Image
     |
     +--> Task A
     |
     +--> Task B
     |
     +--> Task C

すべて同じイメージから起動できます。

ALBと組み合わせれば、

             +--> Task A
             |
Internet --> ALB +--> Task B
             |
             +--> Task C

という構成も作れます。

アプリケーションを同じ形で複製しやすいことは、コンテナを利用する大きなメリットです。


ではDockerを使えばすべて解決する?

もちろん、そうではありません。

Dockerを導入すると、新しく覚えることも増えます。

例えば、

Dockerfile

Docker Image

Container

Registry

Volume

Network

Image Tag

Docker Compose

などです。

さらにAWSで利用するなら、

ECR

ECS

Task Definition

Fargate

なども理解する必要があります。

つまりDockerを利用すると、

環境を統一・再現・配布しやすくなる代わりに、コンテナを管理するための知識が必要になる

という側面があります。


小規模アプリならjarを直接置いてもいい

Dockerが便利だからといって、

Dockerを使わない
=
間違い

ではありません。

例えば、

小規模なアプリ

サーバー1台

環境も単純

頻繁にデプロイしない

といった場合、

EC2
↓
Java
↓
application.jar

というシンプルな構成の方が扱いやすい場合もあります。

Dockerを導入することで、逆に構成が複雑になる可能性もあります。

重要なのは、

Dockerを使うこと自体を目的にしないこと

だと思います。


EC2 + jarとECS + Fargateを比較する

かなり単純化して比較すると、次のようになります。

EC2 + jar ECS + Fargate + Container
Java環境 サーバー側で準備 Image内に定義可能
サーバー管理 必要 EC2管理は基本不要
実行環境の統一 自分で管理 Imageで統一しやすい
アプリの複製 サーバー構築が必要 Taskを増やしやすい
デプロイ単位 jarなど Container Image
学習コスト 比較的低い 比較的高い
構成 シンプル 複雑になりやすい

どちらが絶対的に優れているという話ではありません。

アプリケーションの規模や運用方法によって適切な構成は変わります。


Dockerの本質は「どこでも同じように動かしやすくすること」

Dockerを勉強し始めると、

Dockerfileを書いて

Imageを作って

Containerを起動する

という操作そのものに目が行きがちです。

しかし重要なのは、

なぜコンテナ化するのか

だと思います。

Dockerを利用することで、

アプリケーション
+
実行環境
+
起動方法

を一定の形としてまとめられます。

そして、そのImageを、

開発
↓
テスト
↓
ステージング
↓
本番

と利用できます。

つまり、

「このサーバーを同じ状態にしてください」

ではなく、

「このImageを実行してください」

という形へ変えられるわけです。


まとめ

Spring Bootアプリケーションを動かすために、Dockerは必須ではありません。

JavaがインストールされたEC2へjarを配置して、

java -jar application.jar

でも動かせます。

それでもDockerが利用される理由として、主に次のようなものがあります。

  • 実行環境をDockerfileとして定義できる
  • 開発・テスト・本番の環境差を減らしやすい
  • Container Imageをアプリケーションの配布単位として扱える
  • 同じ環境を複製しやすい
  • ECS / Fargateなどのコンテナサービスと組み合わせやすい
  • Taskが停止しても同じImageから作り直しやすい

一方でDockerを利用すると、コンテナに関する知識や管理も必要になります。

そのため、

Dockerを使う
=
必ず正解

ではありません。

重要なのは、

アプリケーションをどう実行・配布・更新・スケール・運用したいのか

を考え、その手段としてDockerが適しているか判断することです。

Spring Bootはjarだけでも動きます。

そのうえでDockerを利用する最大の理由は、

アプリケーションだけでなく、その実行環境も含めて一定の形にし、同じものを再現・配布・作り直しやすくするため

と考えると、Dockerを使う意味が理解しやすくなります。

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?