Dev Guide / 2026 ・ No.05
Docker 入門と実践
仕組みの基本から、Java Web システムの開発・デプロイ・保守まで
公開
「私の PC では動くのに、サーバーでは動かない」。「新しいメンバーの環境構築に丸一日かかる」。
「本番のミドルウェアを上げたいけれど、怖くて手が出せない」。
Docker は、こうした現場の悩みをまとめて小さくしてくれる道具です。この記事では、まず Docker の仕組みと用語を整理し、
どんな場面で使われているかを紹介したうえで、Spring Boot と Vue で作る顧客向けの Web システムを例に、
開発・デプロイ・運用・保守のどこで何が楽になるのかを、実際に動かしたサンプルで説明します。
Docker とは
Docker は、アプリと、それが動くのに必要なもの(OS のライブラリ、Java などの実行環境、設定ファイル)を一つの箱(コンテナ)にまとめて、どこでも同じように動かすための仕組みです。2013年に公開され、いまではアプリの配布と実行の標準的な形になっています。
たとえるなら輸送用のコンテナです。中身が家具でも食品でも、規格の決まった箱に入れてしまえば、船・トラック・鉄道のどれでも同じように運べます。Docker のコンテナも、中身が Java のアプリでも DB でも、Docker があるマシンならどこでも同じ手順で起動できます。
Docker の価値は、「環境ごと」持ち運べることです。「Java 25 と、このバージョンのライブラリと、この設定」がひとまとまりになっているので、開発者の PC、検証サーバー、本番サーバーで同じものが動きます。「私の環境では動く」問題の多くは、ここで消えます。
仕組み:コンテナと仮想マシンの違い
「環境をまるごと用意する」なら、昔から仮想マシン(VM)がありました。違いは、OS をどこまで持つかです。
VM は OS ごと、コンテナはアプリだけ
コンテナは Linux カーネルの機能(名前空間で見える範囲を分け、cgroups で CPU やメモリを制限)で、プロセスを隔離しています
| 仮想マシン | コンテナ | |
|---|---|---|
| 起動 | 数十秒〜数分(OS が起動する) | 数秒以下(プロセスが起動するだけ) |
| 大きさ | 数 GB〜 | 数十〜数百 MB |
| 1台に載る数 | 数台〜十数台 | 数十〜 |
| 隔離の強さ | 強い(カーネルも別) | VM よりは弱い(カーネルを共有) |
| 中の OS | Windows も Linux も | 基本は Linux(ホストのカーネルを使う) |
どちらが上というより、役割が違います。クラウドでも社内でも、「VM の上で Docker を動かす」のがごく普通の構成です。VM で機械を分け、コンテナでアプリを分ける、と考えるとわかりやすいでしょう。
押さえておきたい用語
Dockerfile からコンテナまで
build・push・pull・run は、そのまま docker コマンドの名前です
| 用語 | 意味 | たとえ |
|---|---|---|
| イメージ | アプリと実行環境を固めた読み取り専用のテンプレート。レイヤー(層)を重ねた構造で、共通部分は使い回される | 料理の冷凍パック |
| コンテナ | イメージから起動した、動いている実体。同じイメージからいくつでも起動でき、消して作り直すのが前提 | 温めて出した一皿 |
| Dockerfile | イメージの作り方を書いたテキスト。どのベースから始め、何をコピーし、何を実行するか | レシピ |
| レジストリ | イメージの置き場所。公開の Docker Hub のほか、AWS の ECR、GitHub の GHCR、社内の Harbor など | 冷凍倉庫 |
| タグ | イメージのバージョン名。postgres:18 の 18 の部分 | ラベル |
| ボリューム | コンテナを消しても残るデータの置き場。DB のデータはここに | 外付けの保存庫 |
| ネットワーク | コンテナどうしをつなぐ仮想ネットワーク。Compose ではサービス名(db など)で相手に届く | 社内の内線 |
| Docker Compose | 複数のコンテナの組み合わせを compose.yaml に書き、docker compose up の一言でまとめて起動する道具 | コース料理の献立表 |
| Docker Engine | コンテナを動かす本体(デーモンとコマンド)。Linux サーバーではこれを入れる。オープンソース | 厨房 |
| Docker Desktop | Windows・Mac 向けの、Engine と画面と小さな Linux VM のセット | 家庭用の厨房セット |
イメージはOCIという業界標準の形式なので、Docker で作ったイメージは Podman や Kubernetes など、ほかの道具でもそのまま動きます。
Docker が活躍する場面
| 場面 | 何がうれしいか |
|---|---|
| 開発環境の統一 | DB やミドルウェアのバージョンをチーム全員でそろえられる。新メンバーは docker compose up だけで準備完了 |
| テストの自動化 | テストのたびに本物の DB を使い捨てで起動できる(Testcontainers)。モックでは見つからない SQL の不具合を早く見つけられる |
| CI/CD | ビルドとテストを毎回まっさらな環境で実行。できたイメージをそのまま配布物にできる |
| 本番のデプロイ | 検証したイメージをそのまま本番へ。戻すときはタグを一つ前に |
| 複数のバージョンの同居 | 顧客 A は Java 21、顧客 B は Java 25、といった違いを、1台の PC やサーバーでぶつからずに動かせる |
| 検証環境の使い捨て | 不具合の再現用、デモ用、研修用の環境をすぐ作ってすぐ消せる |
| マイクロサービス | サービスごとに言語やライブラリを変えても、配り方と動かし方は同じ |
| 古いシステムの延命・移行 | 古い実行環境をイメージに閉じ込めて、新しいサーバーへ移す。移行までの時間を稼げる |
| データ分析・AI | Python と GPU ライブラリの面倒な組み合わせを、イメージとして配る |
Windows・Mac・Linux で使うには
| OS | 入れるもの | メモ |
|---|---|---|
| Linux(サーバー) | Docker Engine(無料・オープンソース) | 本番はふつうこれ。コンテナが直接動く |
| Windows | Docker Desktop(WSL 2 を使う) | ソースは WSL 側に置くとファイルの読み書きが速い |
| Mac | Docker Desktop | Apple Silicon では arm64 のイメージが使われる |
| 代わりの道具 | Rancher Desktop、Podman Desktop など | 無料・オープンソース。Compose ファイルもおおむね使える |
Docker Desktop は、従業員250人以上、または年間売上1,000万ドル以上の組織での仕事の利用には有料のサブスクリプションが必要です(個人・教育・非商用のオープンソース・この条件より小さい会社は無料)。Linux サーバーの Docker Engine はこの対象ではありません。また Docker Hub からの取得には回数の上限があり、ログインなしは6時間に100回(IP アドレスごと)、無料アカウントは200回です。CI では社内のレジストリやキャッシュを用意しておくと安心です。
実践:Java Web システムのどこに使うか
ここからは、顧客向けの業務 Web システム(顧客管理などの CRM)を例にします。構成は、いまの Java 案件で多いSpring Boot(Java)の API と、Vue の画面、PostgreSQL の DBです。
サービスごとにコンテナを分ける
web がブラウザからの入口になり、画面のファイルを返しつつ、/api を app に転送します
| 部分 | Docker の使い方 | 使うイメージの例 |
|---|---|---|
| 開発環境 | DB やミドルウェアだけをコンテナで起動し、アプリは IDE で動かす(デバッグしやすい) | compose.yaml にまとめる |
| DB | 本番と同じ製品・同じメジャーバージョンを全員の PC で。テストでも使い捨てで起動 | postgres、mysql、mariadb、Oracle なら gvenzl/oracle-free |
| ミドルウェア | キャッシュ、メッセージ、検索、認証、ファイル保存などを必要な分だけ追加 | redis、rabbitmq、elasticsearch、keycloak、minio |
| 開発用の道具 | メールの送信テスト、DB の管理画面など、本番には要らないもの | mailpit、pgadmin |
| アプリ本体 | Spring Boot の jar を、Java の実行環境ごとイメージにする | eclipse-temurin(JRE)をベースに |
| 画面 | Vue をビルドした静的ファイルを nginx で配る。API への転送もここで | node でビルド → nginx で配信 |
| バッチ | 夜間の集計などを、同じイメージを別の起動方法で動かす | app と同じイメージ |
| CI | ビルド・テスト・イメージ作成を毎回同じ環境で | GitHub Actions、GitLab CI、Jenkins |
| 検証・本番 | サーバー1台なら Compose、台数が多いならコンテナ基盤へ | Compose/Kubernetes/ECS など |
この記事のサンプル(Spring Boot 4.1.1・Java 25、Vue 3、nginx 1.30、PostgreSQL 18)は、筆者が Docker Engine 29 と Compose v5 で、ビルドから起動、更新、ロールバックまで実際に動かして確かめたものです。
手順1:開発環境の DB をコンテナに
まずは一番効果が大きく、リスクの小さいところから。DB だけをコンテナにします。プロジェクトの直下に次の compose.yaml を置きます。
# crm/compose.yaml(開発用:DB だけ)
services:
postgres:
image: postgres:18 # 本番と同じメジャーバージョンに
environment:
POSTGRES_DB: crm
POSTGRES_USER: crm
POSTGRES_PASSWORD: secret
ports:
- "5432" # PC 側の空いている番号に自動で割り当て
Spring Boot には Docker Compose との連携機能(spring-boot-docker-compose)があります。依存関係に加えておくと、IDE でアプリを起動したときに Spring Boot が自動で docker compose up を実行し、DB の接続先もコンテナに合わせて設定してくれます。application.properties に接続先を書く必要すらありません。
# アプリを起動したときのログ(抜粋・実際の出力) DockerComposeLifecycleManager : Using Docker Compose file .../crm/compose.yaml DockerCli : Container crm-postgres-1 Started DockerCli : Container crm-postgres-1 Healthy DbMigrate : Migrating schema "public" to version "1 - create customer" CrmApplication : Started CrmApplication in 7.271 seconds
テストでは Testcontainers が使えます。テストの実行中だけ本物の PostgreSQL を起動し、終わったら片づけます。Spring Boot なら @ServiceConnection を付けるだけで接続が設定されます。
// テスト用の設定(Spring Initializr が生成するものとほぼ同じ)
@TestConfiguration(proxyBeanMethods = false)
class TestcontainersConfiguration {
@Bean
@ServiceConnection
PostgreSQLContainer postgresContainer() {
return new PostgreSQLContainer(DockerImageName.parse("postgres:18"));
}
}
新しく参加したメンバーに必要なのは、Docker と JDK と IDE だけ。「PostgreSQL をインストールして、ユーザーを作って、文字コードを設定して……」という手順書は要らなくなります。DB の表はアプリ起動時に Flyway などのマイグレーションで作るようにしておくと、だれの PC でも同じ状態から始められます。
手順2:アプリをイメージにする
次は Spring Boot のアプリそのものをイメージにします。ポイントはマルチステージビルド。ビルド用(JDK と Maven 入り)と実行用(JRE だけ)を分けて、本番のイメージにはコンパイラもソースも入れません。
# crm/Dockerfile # syntax=docker/dockerfile:1 # ---- 1. ビルド用ステージ(JDK と Maven で jar を作る)---- FROM eclipse-temurin:25-jdk AS build WORKDIR /src COPY .mvn/ .mvn/ COPY mvnw pom.xml ./ RUN --mount=type=cache,target=/root/.m2 ./mvnw -B -q dependency:go-offline COPY src/ src/ RUN --mount=type=cache,target=/root/.m2 ./mvnw -B -q -DskipTests package # ---- 2. 実行用ステージ(JRE だけの小さなイメージ)---- FROM eclipse-temurin:25-jre WORKDIR /app RUN useradd --system --uid 10001 app COPY --from=build /src/target/crm-*.jar app.jar USER app EXPOSE 8080 ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75", "-jar", "app.jar"]
- 依存ライブラリを先にコピー ── pom.xml が変わらなければ、ライブラリの取得はキャッシュが効いて飛ばされます。ソースを少し直しただけなら、ビルドは数秒〜数十秒
- root で動かさない ── 専用のユーザー(app)で実行し、万一のときの被害を小さく
- メモリは割合で ── -XX:MaxRAMPercentage=75 で、コンテナに割り当てたメモリの75%をヒープの上限に
- Dockerfile を書かない方法も ── Spring Boot の ./mvnw spring-boot:build-image なら、Buildpacks で自動的にイメージを作れます
画面(Vue)も同じ考え方です。node でビルドし、できた静的ファイルだけを nginx のイメージに入れます。
# web/Dockerfile FROM node:24-alpine AS build WORKDIR /web COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM nginx:1.30-alpine COPY nginx.conf /etc/nginx/conf.d/default.conf COPY --from=build /web/dist /usr/share/nginx/html
# web/nginx.conf
server {
listen 80;
root /usr/share/nginx/html;
location / { # Vue の画面(SPA)
try_files $uri $uri/ /index.html;
}
location /api/ { # API は Spring Boot のコンテナへ
proxy_pass http://app:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
proxy_pass http://app:8080 の app は、次の Compose ファイルのサービス名です。IP アドレスを書かなくても、名前で相手に届きます。
手順3:本番の構成を Compose で
サーバー1台で動かす規模なら、Docker Compose がいちばん手軽です。検証サーバーと本番サーバーに、同じ compose.yaml を置きます。
# deploy/compose.yaml(検証・本番用)
services:
web: # Vue の画面 + 入口(nginx)
image: registry.example.com/crm/web:${TAG}
ports:
- "80:80"
depends_on:
- app
restart: unless-stopped
app: # Spring Boot の業務アプリ
image: registry.example.com/crm/app:${TAG}
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/crm
SPRING_DATASOURCE_USERNAME: crm
SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}
TZ: Asia/Tokyo
depends_on:
db:
condition: service_healthy # DB の準備ができてから起動
restart: unless-stopped
db: # PostgreSQL(データはボリュームに保存)
image: postgres:18
environment:
POSTGRES_DB: crm
POSTGRES_USER: crm
POSTGRES_PASSWORD: ${DB_PASSWORD}
TZ: Asia/Tokyo
volumes:
- db-data:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U crm -d crm"]
interval: 5s
retries: 10
restart: unless-stopped
volumes:
db-data:
# deploy/.env(サーバーごとに置く。Git には入れない) TAG=1.0.0 DB_PASSWORD=change-me
- バージョンは TAG の1か所だけ ── どの版を動かすかは .env で決まります
- パスワードはファイルの外へ ── Compose ファイルには書かず、.env や秘密情報の仕組みで渡します
- PostgreSQL 18 のボリューム ── 18 からはデータの場所が変わり、ボリュームは /var/lib/postgresql にマウントします(17 以前は /var/lib/postgresql/data)
- restart: unless-stopped ── サーバーの再起動後やアプリが落ちたときに、自動で立ち上がります
起動は docker compose up -d の一言です。記事冒頭の画面が、その実際の出力です。DB が healthy になるのを待ってからアプリが起動しているのがわかります。
デプロイが変わる
ビルドは1回、同じものを配る
レジストリは Docker Hub の非公開リポジトリのほか、クラウドや社内のものも使えます
バージョンアップは、.env の TAG を書き換えて、もう一度 docker compose up -d するだけ。変わったサービスだけが作り直され、DB はそのまま動き続けます。
| これまで | Docker を使うと | |
|---|---|---|
| 配る物 | war・jar と、手順書(Java や Tomcat の設定) | イメージ1つ(実行環境ごと) |
| 作業 | サーバーにログインして、コピー・設定・再起動を手で | TAG を変えて docker compose up -d |
| 検証との差 | サーバーごとに Java やライブラリの版がずれる | 検証と本番で同じイメージ |
| ロールバック | 前の war を探して入れ直す。設定も戻す | TAG を前の版に戻すだけ(数十秒) |
| 新しいサーバー | OS から順に構築。数日 | Docker を入れて、ファイルを2つ置く。数十分 |
| だれが作業するか | 手順に詳しい人に偏る | 手順が短く、だれがやっても同じ結果 |
データの持ち方が変わる更新(表の追加など)は、アプリの起動時に Flyway などで自動で反映するようにしておくと、イメージの入れ替えだけで済みます。ロールバックで DB をどう戻すかは、事前に決めておきましょう(戻せる変更にする、または更新前にバックアップを取る)。
運用・保守が変わる
運用
- 状態がひと目でわかる ── docker compose ps で全サービスの状態、docker compose logs -f app でアプリのログ。どのサーバーでも同じコマンド
- 自動で立ち直る ── 再起動ポリシーとヘルスチェックで、落ちたコンテナが自動で起動し直す
- 環境の違いによる障害が減る ── 「本番だけ文字化けする」「本番だけ動かない」の原因になりがちな、OS やライブラリの差がなくなる
- リソースを区切れる ── コンテナごとに CPU やメモリの上限を決められ、一つの暴走が全体を巻き込みにくい
- 規模が大きくなっても同じイメージ ── 利用者が増えたら、同じイメージのまま Kubernetes やクラウドのコンテナサービスへ移れる
保守
| よくある保守作業 | Docker での進め方 |
|---|---|
| Java のバージョンアップ(例:21 → 25) | FROM eclipse-temurin:21-jre を 25-jre に変えてビルドし、検証環境で試す。だめなら元のタグに戻す |
| セキュリティパッチ | ベースイメージを最新に更新して再ビルド・再デプロイ。OS の更新をサーバーごとに手でやらなくてよい |
| 脆弱性の確認 | Docker Scout や Trivy で、イメージに含まれる部品の既知の脆弱性を一覧にできる。CI に組み込める |
| ミドルウェアの更新(DB、nginx など) | 新しいタグで検証環境を丸ごと作り、本番と並べて確かめる。サポート切れ(EOSL)への対応計画が立てやすい |
| 複数の顧客の保守 | 顧客ごとにバージョンが違っても、PC 一台で顧客 A・B の環境を切り替えて不具合を再現できる |
| 担当者の交代 | Dockerfile と compose.yaml が、そのまま「環境の設計書」になる。属人化を防げる |
| 障害の調査 | 本番と同じイメージを手元で起動し、同じ条件で再現・調査できる |
保守でいちばん大きいのは、「上げる」「戻す」が気軽にできることです。Java や Spring Boot、DB の古いバージョンが残りやすいのは、更新が怖くて止まってしまうから。新しい環境を横に作って試し、だめなら一行で戻せるなら、サポート切れの前に計画的に更新できます。
導入するときの注意点
| 注意点 | 対策 |
|---|---|
| データの消失 | DB のデータは必ずボリュームに。docker compose down -v はボリュームまで消すので本番では使わない。バックアップは別に取る(pg_dump など) |
| latest タグ | 中身が知らないうちに変わる。postgres:18 のように版を決めて書く |
| 秘密情報 | パスワードや鍵をイメージや Git に入れない。.env、Docker の secrets、クラウドの秘密管理を使う |
| ベースイメージの放置 | 作って終わりにしない。定期的に再ビルドしてパッチを取り込む |
| 時刻・文字コード | コンテナは UTC が標準。TZ=Asia/Tokyo を設定し、DB の文字コードも確認 |
| Windows・Mac の速度 | 大量のファイルを PC と共有すると遅い。ソースは WSL 側に置く、ビルドはコンテナ内のキャッシュを使う |
| 本番の規模 | サーバー1台なら Compose で十分。複数台・無停止の更新・自動の増減が要るなら、Kubernetes やクラウドのコンテナサービスを検討 |
| 顧客の環境 | Docker を入れられない顧客もある。その場合も、開発・テスト・検証で使うだけで効果は大きい |
はじめから全部をコンテナにする必要はありません。おすすめの順番は、① 開発用の DB → ② テスト(Testcontainers)→ ③ CI でのイメージ作成 → ④ 検証環境 → ⑤ 本番。前の段階の効果を確かめながら、一歩ずつ進めましょう。
結 — 一枚まとめ
- Docker は、アプリと実行環境をコンテナという箱にまとめ、どこでも同じように動かす仕組み。VM と違い OS のカーネルを共有するので軽く速い。
- 用語は Dockerfile → build → イメージ → push → レジストリ → pull → run → コンテナ。データはボリューム、複数のコンテナは Compose でまとめる。
- Java Web システムでは、開発用の DB・ミドルウェア、テスト、アプリ本体と画面、CI、検証・本番のすべてに使える。まずは開発用の DB から。
- デプロイは同じイメージを配ってタグで管理。更新もロールバックも TAG を変えて up -d。
- 保守では Java・ミドルウェアの更新や脆弱性対応が「試して、だめなら戻す」で進められる。Docker Desktop のライセンスと Docker Hub の取得上限には注意。
参考
- Docker Docs — What is Docker?
- Docker Docs — Docker Engine release notes
- Docker Docs — Docker Compose
- Docker Docs — Multi-stage builds
- Docker Docs — Docker Desktop license agreement
- Docker Docs — Docker Hub pull usage and limits
- Spring Boot 4.1.1 — Development-time Services(Docker Compose)
- Spring Boot 4.1.1 — Testcontainers
- Spring Boot Maven Plugin — Packaging OCI Images
- Docker Hub — eclipse-temurin
- Docker Hub — postgres
- Docker Hub — nginx
サンプルは2026年10月9日に、Docker Engine 29.4・Compose v5.1 の環境で、Spring Boot 4.1.1(Java 25)、Vue 3、nginx 1.30、PostgreSQL 18 を使って実際にビルド・起動・更新・ロールバックまで確かめたものです。画面は実際の出力を読みやすく描き直したもので、レジストリの名前(registry.example.com)は例です。Docker Desktop のライセンスや Docker Hub の上限は2026年10月時点の公式ドキュメントによります。
開発ガイド No.5 — Docker 入門と実践 / 2026.10