サーバー ソフトウェア 公開日 2026.04.14 更新日 2026.06.13

Dockerイメージとは?コンテナとの違いを初心者向けにわかりやすく解説

Docker イメージとは何かを、コンテナとの違い、Dockerfile との関係、pull しただけでは動かない理由、実務でどこを見るべきかまで初心者向けに整理した記事です。

先に要点

  • Docker イメージ は読み取り専用のレイヤを積み重ねたテンプレートで、docker images で一覧と SIZE を確認できます。
  • コンテナイメージの上に薄い書き込み可能レイヤを足して起動した実体で、docker ps -a で起動中も停止中も確認できます。
  • コンテナ内で作ったファイルは書き込み可能レイヤに乗るため、docker rmコンテナごと消えます。残すには ボリューム を使います。
  • docker pullイメージ取得、docker run で初めてコンテナが動き、Dockerfile はそのイメージの「作り方」です。

Docker を触り始めると、イメージ コンテナ Dockerfile が一気に出てきて、ここで頭がこんがらがりやすいです。 特に「pull したのにまだ動いていないの?」あたりは、初心者がかなりつまずきやすいところです。

この記事は概念の言い換えで終わらせず、手元で docker images docker ps -a docker inspect を実際に叩いて、イメージコンテナの状態・サイズ・レイヤをどこで確認するかを示します。あわせて「コンテナ内の変更がなぜ消えるのか」を docker run → ファイル作成 → exit → 再 run の手順で再現し、commitボリューム との関係まで踏み込みます。

Docker 全体の話から見たいなら、Dockerとは?コンテナで何がうれしい?初心者向けに仕組み・メリット・使いどころを解説 から入ると流れがつかみやすいです。


Dockerイメージとは何か(まず images で見てみる)

Docker イメージ は、コンテナを作る元になる読み取り専用のテンプレートです。Docker Docs では、コンテナ実行に必要なファイル・ライブラリ・設定をまとめた標準化パッケージと説明されています。重要なのは、イメージが「複数の読み取り専用レイヤを積み重ねたもの」だという点です。

抽象的な説明よりも、まず手元で確認した方が早いです。何かイメージを取得して一覧を見てみます。

読み込み中...

docker imagesdocker image ls と同じ)の典型的な出力はこうなります。

REPOSITORY   TAG         IMAGE ID       CREATED        SIZE
node         22-alpine   3f8a1c9e0b21   2 weeks ago    156MB
node         22          7b2d4e6f9a10   2 weeks ago    1.12GB
nginx        stable      a1b2c3d4e5f6   3 weeks ago    192MB

ここで見るべきは右端の SIZE です。同じ Node.js でも 22-alpine は 150MB 台、標準の 22 は 1GB を超えます。ベースに何を選ぶかで、後述の pull 時間や CI の重さが大きく変わります。この時点ではまだ何も「動いて」いません。テンプレートをローカルに置いただけです。

レイヤ構造を確認したいときは docker history が使えます。

$ docker history node:22-alpine
IMAGE          CREATED       CREATED BY                                      SIZE
3f8a1c9e0b21   2 weeks ago   CMD ["node"]                                    0B
<missing>       2 weeks ago   RUN apk add --no-cache ...                       12.3MB
<missing>       2 weeks ago   ENV NODE_VERSION=22.x                            0B
...

各行が1レイヤで、RUNCOPY のような変更を伴う命令ごとに積み上がっているのが分かります。CMDENV のようなメタデータだけの命令は 0B です。


コンテナとの違い(ps -a で実体を数える)

イメージとコンテナの違いは、一言でいえば次の通りです。

観点イメージコンテナ
正体読み取り専用レイヤの積み重ね(テンプレート)イメージ + 書き込み可能レイヤを起動した実体
確認コマンドdocker imagesdocker ps -a
状態あるか無いか(取得済みか)created / running / exited / removed
個数の関係1つ同じイメージから何個でも起動できる
変更の永続性immutable(変わらない)書き込み可能レイヤは rm で消える

Docker Docs でも、コンテナは a runnable instance of an image と説明されています。イメージが1つでも、そこから起動したコンテナは複数になり得ます。実際に同じイメージから2つ起動して数えてみます。

$ docker run -d --name web1 nginx:stable
$ docker run -d --name web2 nginx:stable
$ docker ps
CONTAINER ID   IMAGE          COMMAND                  STATUS         NAMES
9f1a2b3c4d5e   nginx:stable   "/docker-entrypoint.…"   Up 3 seconds   web2
1a2b3c4d5e6f   nginx:stable   "/docker-entrypoint.…"   Up 8 seconds   web1

docker ps は「起動中」だけを出します。停止したコンテナも含めて全部見たいときは -a を付けます。ここを知らないと「コンテナが消えた」と勘違いしがちです。

$ docker ps -a
CONTAINER ID   IMAGE          COMMAND                  STATUS                     NAMES
9f1a2b3c4d5e   nginx:stable   "/docker-entrypoint.…"   Up 1 minute                web2
1a2b3c4d5e6f   nginx:stable   "/docker-entrypoint.…"   Exited (0) 5 seconds ago   web1

STATUS 列の UpExited が、まさに「動いているか止まっているか」です。イメージ側にはこういう状態はありません。


inspect でレイヤと書き込み層をのぞく

「コンテナはイメージ + 書き込み可能レイヤ」という説明は、docker inspect で実際に確認できます。コンテナのストレージ構成を見てみます。

$ docker inspect web1 --format '{{json .GraphDriver}}'
{"Data":{
  "LowerDir":"/var/lib/docker/overlay2/abc.../diff:/var/lib/docker/overlay2/def.../diff",
  "MergedDir":"/var/lib/docker/overlay2/xyz.../merged",
  "UpperDir":"/var/lib/docker/overlay2/xyz.../diff",
  "WorkDir":"/var/lib/docker/overlay2/xyz.../work"
},"Name":"overlay2"}

ここがイメージとコンテナの違いの核心です。

LowerDir(イメージ層)

コロン区切りで複数並ぶのが、イメージの読み取り専用レイヤです。同じイメージから起動したコンテナはこれを共有します。だから2個目以降のコンテナはほとんどディスクを食いません。

UpperDir(書き込み可能層)

このコンテナ専用の書き込み層です。コンテナ内でファイルを作る・書き換えると、すべてここに記録されます。コンテナを docker rm するとこのディレクトリごと消えます。

ストレージドライバは overlay2 がほぼ標準で、コピーオンライト方式です。元のイメージファイルを書き換えるときだけ UpperDir にコピーしてから変更するため、イメージ自体(LowerDir)は immutable のまま保たれます。これが「コンテナで何をいじってもイメージは変わらない」の仕組みです。

docker inspect はイメージにも使えます。たとえばエントリポイントやレイヤの digest を確認できます。

$ docker inspect node:22-alpine --format '{{.Config.Cmd}} {{len .RootFS.Layers}} layers'
[node] 4 layers

コンテナ内の変更が消えるのを再現する

ここが今回いちばん手を動かしてほしいところです。「コンテナを止めるとデータが消える」とよく言われますが、正確には「docker rm されると書き込み可能レイヤごと消える」「新しいコンテナには引き継がれない」です。次の手順で自分で再現できます。

読み込み中...

実際の流れと出力はこうなります。

$ docker run -it --name tmp1 ubuntu:24.04 bash
root@1a2b3c:/# echo hello > /data.txt
root@1a2b3c:/# cat /data.txt
hello
root@1a2b3c:/# exit

# 同じイメージから「別の新しいコンテナ」を起動
$ docker run --rm ubuntu:24.04 cat /data.txt
cat: /data.txt: No such file or directory

# 一方、さっきの tmp1 を再起動すると残っている
$ docker start -ai tmp1
root@1a2b3c:/# cat /data.txt
hello

ここで分かることが2つあります。第一に、/data.txt はイメージ(ubuntu:24.04)ではなく tmp1 の書き込み可能レイヤに書かれたので、別コンテナには存在しません。第二に、コンテナは exit しただけでは消えず、書き込み層も残るので、同じコンテナを docker start すればデータは復活します。「止めた瞬間に消える」のではなく「rm で消える」のです。

最後に tmp1docker rm tmp1 すると、UpperDir ごと削除されて hello は永久に失われます。

よくある失敗例

現象: 本番コンテナの中で設定ファイルを直接編集して動かしていたら、デプロイ(コンテナ作り直し)で設定が全部消えた。原因: 編集内容が書き込み可能レイヤにしか無く、イメージにも永続ストレージにも残っていなかった。確認手順: docker diff コンテナ名 で「A /etc/app/config.yml」のように書き込み層の差分が出る。回避: 再現したい変更は Dockerfile に戻す、消えてはいけないデータは ボリューム に逃がす。


commit とボリューム:変更を残す2つの道

書き込み層は消えると分かったうえで、「変更を残したい」ときの選択肢が docker commitボリュームです。性質がまったく違うので使い分けます。

docker commit でイメージに固める

docker commit は、コンテナの書き込み可能レイヤを新しいレイヤとして固め、新しいイメージにします。先ほどの tmp1 をコミットしてみます。

$ docker commit tmp1 my-ubuntu:with-data
sha256:b9c8d7...

$ docker images
REPOSITORY   TAG         IMAGE ID       CREATED          SIZE
my-ubuntu    with-data   b9c8d7e6f5a4   3 seconds ago    78.2MB
ubuntu       24.04       a1b2c3d4e5f6   2 weeks ago      78.1MB

$ docker run --rm my-ubuntu:with-data cat /data.txt
hello

新イメージ my-ubuntu:with-data から起動すると /data.txt が含まれています。ただし commit は「手作業の結果をそのまま焼き込む」ので、何をどう変えたかが記録に残りません。再現性が無く、チームで管理しにくいため、本番向けの変更は commit ではなく Dockerfile に書くのが実務の原則です。commit はトラブル調査用のスナップショット程度に留めるのが無難です。

ボリュームでデータを外に逃がす

データベースやアップロードファイルのように「コンテナとは寿命を分けたいデータ」は、ボリュームに置きます。ボリュームDocker デーモンが管理する永続ストレージで、コンテナを rm しても残ります。

$ docker volume create appdata
$ docker run -it --rm -v appdata:/data ubuntu:24.04 bash
root@x:/# echo persist > /data/note.txt
root@x:/# exit            # --rm なのでコンテナは即削除される

# 別の新コンテナで同じボリュームをマウント
$ docker run --rm -v appdata:/data ubuntu:24.04 cat /data/note.txt
persist

--rm で1つ目のコンテナは消えたのに、ボリュームにあった note.txt は2つ目のコンテナから読めます。書き込み可能レイヤとの決定的な違いです。3つの関係を整理すると次の通りです。

保存先寿命再現性向いている用途
書き込み可能レイヤコンテナと同じ(rm で消える)なし一時ファイル、キャッシュ
docker commit(新イメージ)イメージとして永続低い(手作業の記録なし)調査用スナップショット
ボリュームコンテナと独立、明示削除まで残るデータそのものDB、アップロード、ログ
Dockerfileビルドし直せば常に再現高いアプリ・依存・設定

pull と run、Dockerfile の位置づけ

ここまでで実体が掴めたら、用語の関係はすっきり整理できます。

  • docker pull: レジストリからイメージのレイヤをローカルへ取得する。まだ起動しない。
  • docker run: イメージから書き込み可能レイヤを足してコンテナを作り、起動する。ローカルにイメージが無ければ先に pull もする。
  • Dockerfile: そのイメージの「作り方」を書くテキスト。docker build でイメージになる。

つまり Dockerfile(作り方)→ イメージ(成果物)→ コンテナ(起動した実体) という一方向の流れです。「Dockerfile を書いた=もう動いている」ではないこと、「pull した=もう動いている」ではないことの2点を押さえると、最初の混乱はほぼ消えます。Dockerfile の中身については Dockerfileとは?何を書くもの?最初に読むべき命令を初心者向けに整理 で扱っています。


イメージで見るべきポイント(数値の目安つき)

ベースとサイズ

同じ言語でも alpine 系は数百MB以下、フル版は1GB超になりがちです。SIZE が大きいほど pull・CIデプロイが重くなるので、まず docker images の SIZE を見る癖をつけます。

作り直す前提で考える

イメージは immutable です。動いたコンテナを手で直して終わりにせず、再現したい変更は Dockerfile 側へ戻します。docker history でレイヤが無駄に増えていないかも確認します。

イメージを小さくする定番は、マルチステージビルドと .dockerignore です。ビルドツールを最終イメージに残さない、node_modules.gitコンテキストから除外する、といった対応で SIZE を数分の1にできることも珍しくありません。


Dockerイメージとコンテナのよくある質問

Q. イメージ1つから複数のコンテナを起動できますか?

A. はい。docker run を繰り返せば何個でも作れます。読み取り専用のイメージ層(inspect の LowerDir)は共有され、各コンテナは自分の書き込み層だけを持つので、2個目以降はディスクをほとんど消費しません。

Q. コンテナを止めるとデータは消えますか?

A. exitstop では消えません。書き込み可能レイヤは残り、docker start で復活します。消えるのは docker rm したときです。本記事の再現手順(run→作成→exit→再run)で確認できます。残したいデータは ボリューム に置きます。

Q. コンテナの中で何を変更したか後から確認できますか?

A. docker diff コンテナ名 を使います。A は追加、C は変更、D は削除を表し、書き込み可能レイヤに対する差分が一覧できます。設定を直接いじってしまった事故の切り分けに便利です。

Q. docker commit と docker build はどう使い分けますか?

A. commit はコンテナの現状を焼き込むだけで、何をしたかが記録に残らず再現できません。build は Dockerfile から作るので手順が残り、チームで再現できます。本番向けは原則 build、commit は調査用スナップショットに留めます。

Q. イメージのサイズが大きくなる原因は何ですか?

A. ベースが重い、ビルドツールを含めたまま、キャッシュやログを消していない、複数の RUN でレイヤが蓄積、などが典型です。docker history で重いレイヤを特定し、マルチステージビルドと .dockerignore で削減します。

Q. イメージはどこに保存されていますか?

A. Linux では /var/lib/docker/ 配下(overlay2 ドライバなら overlay2/)に、Docker Desktop では内部のディスクイメージ内に置かれます。docker inspect の GraphDriver でコンテナごとの実パスも確認できます。リモート共有は Docker Hub などのレジストリへ push します。

Q. イメージのタグ(latest、1.0 など)はどう運用すべきですか?

A. latest は中身が動くので本番では避けるのが安全です。ビルドごとに v1.2.3Git コミットハッシュを付けると、docker ps の IMAGE 列だけで「今動いている版が何か」を追跡できます。

Q. イメージは ARM(Apple Silicon)と x86 で互換性がありますか?

A. アーキテクチャごとに別バイナリが必要です。docker buildx でマルチアーキテクチャイメージをビルドすれば、linux/amd64linux/arm64 を1つのタグで提供できます。docker inspect の Architecture でイメージの対象を確認できます。


まとめ

Docker イメージ は読み取り専用レイヤの積み重ねたテンプレート、コンテナ はそこに書き込み可能レイヤを足して起動した実体です。違いは概念で覚えるより、docker images でサイズを、docker ps -a で状態を、docker inspect で LowerDir / UpperDir を実際に見るのが近道です。

コンテナ内の変更が消えるのは「止めたから」ではなく「書き込み層が rm で消えるから」です。残したいものは commit(再現性は低い)かボリューム(データ向け)か Dockerfile(アプリ向け)で逃がす、と整理できれば、Docker まわりの用語はほぼつながります。

続けて読むなら、Dockerfileとは?何を書くもの?最初に読むべき命令を初心者向けに整理Docker Composeとは?複数コンテナをまとめて動かす基本を初心者向けに解説 が相性のよい次の一歩です。


参考リンク

あとで見返すならここで保存

読み終わったあとに残しておきたい記事は、お気に入りからまとめて辿れます。