Dev Guide / 2026 ・ No.05

Docker 入門と実践

仕組みの基本から、Java Web システムの開発・デプロイ・保守まで

公開

ターミナルで docker compose up -d を実行し、db・app・web の3つのコンテナが順に起動したあと、docker compose ps で状態を表示し、curl で API から顧客一覧の JSON が返ってきた画面
この記事のサンプルを起動したところ。DB の準備ができるのを待ってからアプリ、最後に画面のコンテナが立ち上がり、API が顧客データを返しています(筆者が実際に実行した出力を、読みやすいようにターミナルの画面として描き直したもの)

「私の PC では動くのに、サーバーでは動かない」。「新しいメンバーの環境構築に丸一日かかる」。
「本番のミドルウェアを上げたいけれど、怖くて手が出せない」。
Docker は、こうした現場の悩みをまとめて小さくしてくれる道具です。この記事では、まず Docker の仕組みと用語を整理し、
どんな場面で使われているかを紹介したうえで、Spring Boot と Vue で作る顧客向けの Web システムを例に、
開発・デプロイ・運用・保守のどこで何が楽になるのかを、実際に動かしたサンプルで説明します。

一

Docker とは

Docker は、アプリと、それが動くのに必要なもの(OS のライブラリ、Java などの実行環境、設定ファイル)を一つの箱(コンテナ)にまとめて、どこでも同じように動かすための仕組みです。2013年に公開され、いまではアプリの配布と実行の標準的な形になっています。

たとえるなら輸送用のコンテナです。中身が家具でも食品でも、規格の決まった箱に入れてしまえば、船・トラック・鉄道のどれでも同じように運べます。Docker のコンテナも、中身が Java のアプリでも DB でも、Docker があるマシンならどこでも同じ手順で起動できます。

CORE

Docker の価値は、「環境ごと」持ち運べることです。「Java 25 と、このバージョンのライブラリと、この設定」がひとまとまりになっているので、開発者の PC、検証サーバー、本番サーバーで同じものが動きます。「私の環境では動く」問題の多くは、ここで消えます。

二

仕組み:コンテナと仮想マシンの違い

「環境をまるごと用意する」なら、昔から仮想マシン(VM)がありました。違いは、OS をどこまで持つかです。

VM は OS ごと、コンテナはアプリだけ

仮想マシン(VM) アプリごとに OS を丸ごと用意 アプリ1 ライブラリ ゲスト OS アプリ2 ライブラリ ゲスト OS アプリ3 ライブラリ ゲスト OS ハイパーバイザー ホスト OS ハードウェア コンテナ(Docker) OS のカーネルは共有する アプリ1 ライブラリ アプリ2 ライブラリ アプリ3 ライブラリ Docker Engine ホスト OS(Linux カーネル) ハードウェア ゲスト OS がない分、コンテナは軽く、数秒で起動する Mac・Windows では、小さな Linux の VM の中でコンテナが動く

コンテナは Linux カーネルの機能(名前空間で見える範囲を分け、cgroups で CPU やメモリを制限)で、プロセスを隔離しています

仮想マシンコンテナ
起動数十秒〜数分(OS が起動する)数秒以下(プロセスが起動するだけ)
大きさ数 GB〜数十〜数百 MB
1台に載る数数台〜十数台数十〜
隔離の強さ強い(カーネルも別)VM よりは弱い(カーネルを共有)
中の OSWindows も Linux も基本は Linux(ホストのカーネルを使う)

どちらが上というより、役割が違います。クラウドでも社内でも、「VM の上で Docker を動かす」のがごく普通の構成です。VM で機械を分け、コンテナでアプリを分ける、と考えるとわかりやすいでしょう。

三

押さえておきたい用語

Dockerfile からコンテナまで

Dockerfile 設計図 イメージ 読み取り専用 レジストリ Docker Hub 等 サーバー 検証・本番 コンテナ 動いている実体 build push pull run ボリューム DB のデータ ← 開発者の PC・CI ← 置き場所(社内でも可) 一度作ったイメージを、開発・検証・本番でそのまま使い回す コンテナは消して作り直す前提。残したいデータはボリュームへ

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 DesktopWindows・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 やサーバーでぶつからずに動かせる
検証環境の使い捨て不具合の再現用、デモ用、研修用の環境をすぐ作ってすぐ消せる
マイクロサービスサービスごとに言語やライブラリを変えても、配り方と動かし方は同じ
古いシステムの延命・移行古い実行環境をイメージに閉じ込めて、新しいサーバーへ移す。移行までの時間を稼げる
データ分析・AIPython と GPU ライブラリの面倒な組み合わせを、イメージとして配る
五

Windows・Mac・Linux で使うには

OS入れるものメモ
Linux(サーバー)Docker Engine(無料・オープンソース)本番はふつうこれ。コンテナが直接動く
WindowsDocker Desktop(WSL 2 を使う)ソースは WSL 側に置くとファイルの読み書きが速い
MacDocker DesktopApple Silicon では arm64 のイメージが使われる
代わりの道具Rancher Desktop、Podman Desktop など無料・オープンソース。Compose ファイルもおおむね使える
LICENSE

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です。

サービスごとにコンテナを分ける

docker compose(サーバー1台) ブラウザ 利用者 web nginx + Vue app Spring Boot db PostgreSQL ボリューム cache Redis(任意) :80 /api 1サービス=1コンテナ。役割ごとに分けて、まとめて起動する 朱の枠=この記事のサンプルで実際に動かした部分

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"));
    }
}
POINT

新しく参加したメンバーに必要なのは、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回、同じものを配る

Git コードを push CI ビルド・テスト レジストリ app:1.0.1 検証環境 同じイメージ 本番環境 同じイメージ 戻すときはタグを 1.0.0 に app:1.0.0 CI:GitHub Actions・GitLab CI・Jenkins など。テストは Testcontainers 「検証で確かめたもの」と「本番で動くもの」が、バイト単位で同じ 手順書の手作業が減り、だれがデプロイしても結果が同じになる

レジストリは Docker Hub の非公開リポジトリのほか、クラウドや社内のものも使えます

バージョンアップは、.env の TAG を書き換えて、もう一度 docker compose up -d するだけ。変わったサービスだけが作り直され、DB はそのまま動き続けます。

ターミナルで .env のバージョンを 1.0.1 に書き換えて docker compose up -d を実行し、db はそのまま、app と web だけが作り直された画面
バージョンアップの操作。変わった app と web だけが作り直され、データの入った 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 が、そのまま「環境の設計書」になる。属人化を防げる
障害の調査本番と同じイメージを手元で起動し、同じ条件で再現・調査できる
MERIT

保守でいちばん大きいのは、「上げる」「戻す」が気軽にできることです。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 でのイメージ作成 → ④ 検証環境 → ⑤ 本番。前の段階の効果を確かめながら、一歩ずつ進めましょう。

結 — 一枚まとめ

  1. Docker は、アプリと実行環境をコンテナという箱にまとめ、どこでも同じように動かす仕組み。VM と違い OS のカーネルを共有するので軽く速い。
  2. 用語は Dockerfile → build → イメージ → push → レジストリ → pull → run → コンテナ。データはボリューム、複数のコンテナは Compose でまとめる。
  3. Java Web システムでは、開発用の DB・ミドルウェア、テスト、アプリ本体と画面、CI、検証・本番のすべてに使える。まずは開発用の DB から。
  4. デプロイは同じイメージを配ってタグで管理。更新もロールバックも TAG を変えて up -d。
  5. 保守では Java・ミドルウェアの更新や脆弱性対応が「試して、だめなら戻す」で進められる。Docker Desktop のライセンスと Docker Hub の取得上限には注意。

参考

サンプルは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

← 記事一覧へ