メインコンテンツへスキップ
ブログ一覧に戻る
Web制作・運用

コンテナ技術入門:Dockerで揃える環境と、運用に残る責任

2025年10月18日
最終更新: 2026年10月8日
10分で読めます

この記事でわかること

コンテナはアプリの配布単位を揃える仕組みです。イメージ、実行設定、永続データを分け、Dockerの小さな例からCompose、Kubernetes、更新と復旧の責任まで整理します。

2026年10月8日に、Node.js公式Dockerイメージの現行READMEを再読しました。本番アプリはLTSリリースを使うこと、node:ltsなどのタグ、node:alpineが小さい一方でmusl libcを使うためDebian系のglibc向け依存と互換性を確認すること、node:slimは実行に必要な最小構成であることが案内されています。Nodeの新リリース後はOS・アーキテクチャ別イメージの公開が遅れる場合もあり、タグ名だけで起動性、脆弱性、費用を保証できません。

30秒で要点

コンテナは、アプリと必要なファイルをイメージという配布単位にまとめ、その内容から分離したプロセスを動かす仕組みです。開発と本番の差を減らせますが、外部DB、権限、保存データ、ホストの更新まで同じになるわけではありません。

  • 揃える対象は、イメージ、実行設定、外部サービスとの接続条件です。
  • 消して作り直すアプリと、失ってはいけないデータを分けます。
  • Dockerの採用とKubernetesの採用は別の判断です。配布の再現性に加え、更新と復旧の担当を決めます。

「自分のPCでは動くのに、別の場所では動かない」。この問題に対し、どこまでを箱に入れ、どこからを運用で支えるかを考えるための入門です。

イメージとコンテナを分けて考える

イメージは実行に使うファイル一式、コンテナはそれを使って作られた実行環境です。同じイメージから複数のコンテナを作れます。コンテナを止めても、イメージそのものが書き換わるわけではありません。

たとえば集計プログラムとNode.jsをイメージに入れて配布します。実行時には、どのデータを読むか、どれだけメモリを使えるか、外部へ通信できるかを決めます。実行後の結果を残す場所も必要です。

Dockerfileはイメージを作る手順、レジストリはイメージを保存・配布する場所です。Dockerはこれらを扱う代表的な道具であり、コンテナという考え方そのものと同義ではありません。

Dockerfileとコードからイメージを作り、実行設定を合わせてコンテナを動かす。永続データはコンテナの外に置き、ホストのカーネルと更新は運用側で管理する関係
図1:同じイメージを配っても、権限・接続先・保存先が異なれば動作は変わる。図は一般的なLinuxコンテナの責任分担を示す。

仮想マシンとの違いは、カーネルを共有するか

一般的なLinuxコンテナはホストのカーネルを共有し、プロセスやファイルの見え方などを分離します。仮想マシンは仮想化されたハードウェア上でゲストOSを動かします。コンテナを仮想マシンの中で動かす構成もあります。Dockerのコンテナ入門が、この違いを説明しています。

表が収まらない場合は、横にスクロールできます

観点Linuxコンテナ仮想マシン
主な分離の単位カーネルを共有するプロセスゲストOSを含む環境
配布・更新で扱うものアプリとユーザー空間の依存関係OSを含むマシンイメージ等
合う要件の例同じアプリを再作成・複数配置したい異なるOSやカーネルの要件がある
別途必要な管理ホスト、権限、ネットワーク、データ仮想化基盤、ゲストOS、権限、データ

「必ず数秒」「完全に隔離」「VMより安全」とは言えません。イメージ取得、初期化、ストレージ、権限設定によって起動時間も影響範囲も変わります。実行するコードをどこまで信頼できるかを先に決めます。

小さな集計処理を、配布できる形にする

まずWebサーバーやDBを使わず、架空の注文2件を集計します。同じフォルダに次の3ファイルを置く例です。Node.js 24系のローカル実行を確認しています。Dockerでのビルド・実行は本稿の検証では行っていません。

orders.jsonは練習用データです。実データや秘密情報をイメージに含めるための例ではありません。

[
  { "totalYen": 1200 },
  { "totalYen": 800 }
]

report.mjsは、非負の安全な整数だけを受け付け、合計も同じ範囲に収まるか確認します。

import { readFile } from 'node:fs/promises';

const orders = JSON.parse(
  await readFile(new URL('./orders.json', import.meta.url), 'utf8')
);
if (!Array.isArray(orders)) throw new Error('orders must be an array');

let totalYen = 0;
for (const order of orders) {
  const value = order?.totalYen;
  if (!Number.isSafeInteger(value) || value < 0) {
    throw new Error('totalYen must be a non-negative safe integer');
  }
  totalYen += value;
  if (!Number.isSafeInteger(totalYen)) throw new Error('total overflow');
}
console.log(JSON.stringify({ count: orders.length, totalYen }));

node report.mjsで実行すると、{"count":2,"totalYen":2000}を出力します。値を文字列の"1200"に変えるとエラーで終了します。黙って型を変換しないことも確認できます。

Dockerfileでは、実行環境とコピーするファイルを明示します。

FROM node:24-bookworm-slim
WORKDIR /app
COPY report.mjs orders.json ./
USER node
CMD ["node", "report.mjs"]

Nodeの公式イメージで定義されている構成を使っています。対応するバリアント一覧は2026年10月4日に確認しました。すでに利用を許可されたDocker環境がある場合の操作例は次の通りです。初回のビルドではベースイメージを外部から取得します。

docker build -t order-report:local .
docker run --rm --network none order-report:local

--rmは終了したコンテナを削除します。今回の結果は標準出力に出るだけで、永続保存しません。--network noneは実行するコンテナに外部通信用のネットワークを与えない設定で、ビルド時の取得を止める指定ではありません。none network driverを参照してください。

この例で確認するのは、ファイル、実行コマンド、実行ユーザーを明示する流れです。本番用の権限制限、資源上限、監査、イメージ検査が完成した例ではありません。

同じイメージでも、環境差は残る

再現性を上げるには、アプリのコードだけでなく、動作に関わる条件も記録します。

表が収まらない場合は、横にスクロールできます

条件起きる差記録・確認するもの
CPUとOS対応する実行形式がない対象プラットフォームとイメージの対応
依存ライブラリ開発機だけにあるライブラリへ依存ロックファイル、ビルド手順、実行時の依存
実行設定接続先やタイムゾーン等が異なる必須設定、既定値、設定不足時のエラー
外部サービスDBの版・権限・応答が異なる接続条件、互換性、失敗時の処理
マウントイメージ内のファイルを別内容で覆う保存先、所有者、読み書きの範囲

ベースイメージの24-bookworm-slimというタグも固定内容ではありません。配備した内容を特定するにはdigestを記録し、必要に応じてdigestで固定します。ただし固定したまま放置すれば修正版は取り込まれません。更新を検出し、テストして採用する流れが必要です。Dockerのイメージ固定の説明

依存があるNodeアプリでは、ロックファイルに基づくインストールと、実際のビルド成果物・起動コマンドを揃えます。マルチステージビルドはビルド用の道具を実行用イメージから分ける方法です。ただし、ビルド側からnode_modulesをコピーすれば常に動くわけではありません。Debian系のglibcとAlpineのmuslでは、ネイティブ依存の互換性を確認します。Node公式イメージのバリアント説明

権限、ポート、永続データを別々に決める

非rootユーザーとrootlessを混同しない

例のUSER nodeはコンテナ内のプロセスの実行ユーザーです。Docker daemon自体を非rootで動かすrootless modeとは異なります。どちらも「設定したので安全」とは判断せず、書き込めるディレクトリ、ホストのマウント、ネットワーク到達範囲を点検します。

秘密鍵やトークンをDockerfile、ソース、ビルド引数へ埋め込まないことも必要です。イメージやビルド履歴に残れば、後から実行環境で隠しても回収できません。ビルド用の秘密と、実行時に渡す秘密の管理方法を分けます。

EXPOSEは、ホストへのポート公開ではない

EXPOSE 3000は想定するポートの情報です。ホスト側のポートへ公開する操作はdocker run -pなどで指定します。ローカル開発だけで使うなら、公開先のアドレスも確認します。認証のない管理画面を外部へ出さないためです。DockerfileのEXPOSE・USER・ARG

volumeがあっても、バックアップは別に必要

コンテナの書き込み可能な層にだけ保存したデータは、そのコンテナを削除すると失われます。永続データはvolumeや外部ストレージへ分けます。Dockerのvolumeの説明

ただし同じホスト上にvolumeが残ることと、ホスト故障や誤削除から復元できることは別です。DBなら整合性を保ったバックアップ、保存先の分離、復元にかかる時間を確認します。アプリを前のイメージへ戻しても、変更済みのDBスキーマまで自動で戻るわけではありません。

ComposeとKubernetesは、運用要件に合わせて選ぶ

Composeは複数のサービスとネットワーク、volumeなどの構成を宣言して扱う道具です。開発用のアプリとDBを揃える際に役立ちます。ただしdepends_onで順序を指定しただけでは、DBが接続を受け付ける準備まで待ちません。必要ならhealthcheckとservice_healthy条件を組み合わせます。起動後にDBが落ちた際の再接続は、さらに別の問題です。Composeの起動順制御

Kubernetesでは、コンテナをまとめるPod、望ましい複製数や更新を管理するDeployment、通信先をまとめるServiceなどを扱います。複数ホストで配置や復旧を管理したい場合の選択肢ですが、ネットワーク、権限、証明書、監視、クラスタ更新の責任も増えます。

特に「健康か」という一つの言葉で、異なる判定をまとめないことが大切です。

表が収まらない場合は、横にスクロールできます

判定何を知りたいか失敗時の意味
Docker HEALTHCHECK健康状態の確認結果はどうかunhealthy等の状態を付ける。これ自体は再起動命令ではない
Kubernetes readiness今、通信を受けてよいか対象Serviceの配送先から外す
Kubernetes liveness停滞したプロセスを再起動すべきか失敗条件に達すると再起動方針に従って対処する
Kubernetes startup起動処理を終えたか成功するまで他のprobeを待たせ、起動失敗を判定する

DBが一時停止しただけで全Podのlivenessが落ちる設計では、再起動が重なって復旧を妨げる場合があります。判定コマンドがイメージ内に存在するかも確認します。小さいイメージにはcurlがないこともあります。Kubernetesのprobeの役割と注意点

採用前に、再作成と復元を一度分けて試す

最初から多くのサービスを移す必要はありません。小さな処理を一つ選び、次を確認すると不足が見つかります。

  1. 同じイメージを別の許可された環境で動かし、設定不足を検出できるか確認する。
  2. アプリのコンテナを削除・再作成しても、必要なデータが残る構成か確認する。
  3. バックアップから別の保存先へ復元し、内容と所要時間を確認する。
  4. 前のイメージへ戻す操作と、DB変更の互換性を別々に確認する。
  5. 更新、監視、障害連絡、費用確認の担当を決める。

これらは読者の検証手順であり、本稿でDockerやクラスタの復旧を実行した記録ではありません。今回実行したのは、先の集計プログラムの正常入力・不正入力の確認です。

評価には、配備失敗件数を全配備件数で割った割合、障害発生から復旧までの時間、更新作業の工数を使えます。ホスト、レジストリ、ストレージ、監視、運用作業の費用も含めて比較します。コンテナ数が増えたこと自体を成功とはしません。

配布後の検証と公開操作を整理するならCI/CD入門、サービスを分ける判断ならマイクロサービス入門へ進んでください。サイト全体の更新・復旧体制は運用保守ガイドでも扱っています。

よくある質問(FAQ)