Docker超入門|仮想化との違い・基本コマンド・Dockerfile作成までを対話形式でわかりやすく解説
はじめに
こんにちは!株式会社メンバーズで生成AI基盤チームに所属している前田です。普段は生成AIの未来を創るべく、様々なインフラ基盤技術について学んでいます。日々の学習で得た知識や経験を共有し、技術力を高めることが目標です。
今回は、私が先輩エンジニアSさんと一緒にDockerを学習した内容を記事にまとめました。インフラに苦手意識のある方や、Dockerを始めたばかりの方、仮想化について学習中の方にぜひ読んでいただけたら嬉しいです。先輩をS、後輩をKとして記述していきます。
一般的な仮想化とDockerによる仮想化の違いについて
K: 先輩、仮想化について少し教えてもらえませんか?Dockerのことも気になっているんですが、一般的な仮想化と何が違うのかよくわからなくて。
S: もちろんだよ。まず、一般的な仮想化について説明するね。仮想化とは、物理的なハードウェアを抽象化して、複数の仮想マシンを作る技術なんだ。これにより、一台のサーバー上で複数のOSを稼働させることができる。ハイパーバイザー[*1]と呼ばれるソフトウェアが物理サーバーの上にあり、その上で複数の仮想マシンが実行される。
K: なるほど、仮想マシンはそれぞれ独立したOSを持つんですね。
S: その通り。各仮想マシンは自己完結型で、独自のオペレーティングシステムやアプリケーションを実行できる。例えば、ある仮想マシンはWindowsを動かし、別の仮想マシンはLinuxを動かすことも可能だ。しかし、この方法はリソースを多く消費するし、起動にも時間がかかる。仮想マシンを立ち上げるためには、OSのブートプロセス全体を実行する必要があるからね。
K: 確かに、仮想マシンはそれぞれOSを持つから、メモリやCPUのリソースをかなり消費しそうですね。
S: その通り。リソースのオーバーヘッドが大きく、特にサーバーの数が多くなると、管理が複雑になりがちだ。また、仮想マシンのスナップショットやバックアップも時間がかかる。
K: それに対して、Dockerはどういう仕組みなんですか?
S: Dockerは「コンテナ」という概念を使っているんだ。コンテナはホストOSのカーネルを共有しながら、独立したアプリケーション環境を提供する。これにより、リソースの効率が良く、起動も非常に速い。具体的には、Dockerのコンテナは数秒で立ち上がるし、リソースのオーバーヘッドも最小限に抑えられる。
K: それはすごいですね。どうしてコンテナはそんなに軽量なんですか?
S: コンテナはホストOS上で直接実行されるため、各コンテナが独自のOSを持たないという特性があるんだ。これにより、ストレージやメモリの使用量が大幅に削減される。また、コンテナはイメージという形でアプリケーションとその依存関係をパッケージ化するため、簡単に移動やデプロイができるのも利点だ。
K: 確かに、開発環境と本番環境の一貫性が保てそうですね。
S: そうだね。Dockerを使えば、同じイメージを使ってローカル環境で開発し、そのまま本番環境にデプロイできるから、環境の違いによる問題が減るんだ。さらに、Dockerはスケーラビリティにも優れていて、必要に応じてコンテナを簡単に追加したり削除したりできる。これが、特にマイクロサービスアーキテクチャ[*2]においては非常に重要なんだ。
K: なるほど、Dockerの利点がよくわかりました。一般的な仮想化に比べて、Dockerは効率的で使いやすいってことですね。
S: その通り。もちろん、その利点を理解して使いこなすことで、開発や運用の効率が大幅に向上するよ。
[*1]: 物理的なサーバーの上で、複数の仮想マシンを管理・実行するための特別なソフトウェアです。ハイパーバイザーは、各仮想マシンに適切なリソースを割り当てたり、仮想マシン同士が干渉しないように制御したりする役割を担っています。
[*2]: 一つの大きなアプリケーションを、小さな独立したサービスの集まりとして構築する設計手法のことです。各サービスはそれぞれ独立して開発、デプロイ、スケーリングできます。Dockerコンテナは、このマイクロサービスを実現するための重要な技術の一つです。
仮想マシン vs Docker|違いを比較解説した一覧表
特徴 | 一般的な仮想化(仮想マシン) | Docker(コンテナ) |
リソースの効率 | 高いオーバーヘッド(OSごとにリソースを使用) | 軽量(ホストOSのカーネルを共有) |
起動時間 | 数分かかる | 数秒で起動 |
管理の複雑さ | 管理が複雑でスナップショットやバックアップに時間がかかる | シンプルでイメージにより一貫性が保たれる |
互換性 | 異なるOSを同時に動作可能 | 同じOSのカーネルを使う必要がある |
移植性 | 仮想マシンの移行が必要(VM形式に依存) | イメージファイルで簡単に移動・デプロイ可能 |
スケーラビリティ |
|
|
セキュリティ |
| カーネルを共有するためセキュリティリスクがある |
開発環境の一貫性 |
| 同じイメージを使用できるため一貫性が保たれる |
仮想マシン vs Dockerコンテナ|アーキテクチャ比較図
アーキテクチャ比較図
Dockerのコマンドの使い方
Dockerの基本コマンドを学ぼう!先輩Sと後輩KのDocker入門
K: 先輩、Dockerって便利だって聞きましたけど、まず何から始めればいいですか?どんなコマンドを覚えればいいんでしょう?
S: お、Dockerに興味持ったんだね!いい質問だ。Dockerを使う上で最初に覚えるべき基本的なコマンドがいくつかあるんだ。これらを理解すれば、コンテナの基本的なライフサイクル(作成、起動、停止、削除)を操作できるようになるよ。
K: ライフサイクル、ですか。
S: そう。コンテナはプログラムを動かす「箱」みたいなものなんだけど、その箱を「作る」「電源を入れる」「状態を確認する」「電源を切る」「捨てる」っていう一連の流れがあるんだ。それを操作するのがコマンドってわけ。
まずは、この基本的なコマンド一覧を見てみようか。
Dockerのコマンド一覧表
操作 | コマンド | 説明 |
コンテナを作成 | docker create <イメージID> | 指定したイメージから新しいコンテナを作成するが、まだ実行はしない。 |
コンテナを作成して起動 | docker run <イメージID> | 指定したイメージから新しいコンテナを作成し、すぐに実行を開始する。 |
コンテナを起動 | docker start <コンテナID> | 停止中の既存コンテナを指定して起動する。 |
コンテナの状態確認 | docker ps | 実行中のコンテナ一覧を表示する。 |
全てのコンテナの状態確認 | docker ps -a | 実行中を含む、全ての状態のコンテナ(停止中なども)一覧を表示する。 |
コンテナを停止 | docker stop <コンテナID> | 実行中のコンテナに停止信号を送り、終了させる。 |
コンテナを削除 | docker rm <コンテナID> | 停止中のコンテナを削除する。 |
コンテナを強制削除 | docker rm --force <コンテナID> | 実行中のコンテナを強制的に削除する。(非推奨) |
K: なるほど、こうやって見ると操作とコマンドが分かりやすいですね! <コンテナID> とか <イメージID> っていうのは、そのコンテナやイメージを識別するための名前や番号ですか?
S: そうだね。正確には、長いIDが振られるんだけど、識別のために短いIDの一部を使ったり、自分で分かりやすい「名前」を付けて使うこともできるんだ。コマンドを使うときは、そのIDか名前を指定するよ。
K: 「作成」と「作成と起動」のコマンドがあるんですね。create と run。違いは何ですか?
S: いいところに気づいたね!
docker create <イメージID> は、設計図である「イメージ」をもとに、コンテナという「箱」だけを作るコマンド。家電製品で言うと、工場で製品が完成した状態かな。まだ電源は入っていない。
docker run <イメージID> は、create で箱を作ってから、すぐに start で電源を入れる、という一連の流れをまとめて行うコマンドなんだ。だから、Dockerで何か動かしたいときに一番よく使うのが docker run だね。
「作成だけ」が必要なケースは、例えばコンテナの設定を細かく行ってから起動したい場合とか、少し特殊な用途になることが多いかな。まずは docker run を中心に覚えれば大丈夫だよ。
K: なるほど!ほとんどの場合は run で、必要な時だけ create と start を分けて使うんですね。
S: その通り!そして、コンテナがちゃんと動いているか、あるいは停止しているかを確認するのが docker ps コマンドだ。
K: 確認するコマンドで、docker ps と docker ps -a がありますけど、違いは何ですか?さっきの一覧だと -a がつくと停止したコンテナも見られるって書いてましたね。
S: そうそう、まさにそこがポイント!
単に docker ps と打つと、現在実行中のコンテナだけが表示されるんだ。今まさに動いているサービスやアプリケーションを確認したいときに使う。
一方、docker ps -a の -a オプションは "all" の略で、実行中か停止中かに関わらず、全てのコンテナを表示してくれるんだ。以前に作ったけど今は止まっているコンテナや、エラーで終了してしまったコンテナなども含めて、自分のPCやサーバーにあるコンテナを全部リストアップしたいときに使うんだよ。
ブログ記事にするなら、ここで実際に docker ps -a の出力例を少し載せると、読者は自分の環境で実行した結果と比べられて分かりやすいかもしれないね。
K: なるほど!実行中だけ見たい時は docker ps、全部見たい時は docker ps -a なんですね。これでコンテナがどういう状態か把握できます。
S: そうだね。状態を確認できたら、次は操作だ。動いているコンテナを止めたいときは docker stop <コンテナID> を使う。これはコンテナに「シャットダウンしてね」っていう信号を送るイメージ。
完全に不要になったコンテナを片付けたいときは docker rm <コンテナID> で削除するんだけど、これは停止しているコンテナにしか使えないんだ。動いているものをいきなり消すと問題が起こる可能性があるからね。
K: じゃあ、もしコンテナが固まって docker stop でも止まらない時はどうすればいいんですか?
S: いい質問!まさにその時のためにあるのが docker rm --force <コンテナID> だ。 --force オプションを付けると、実行中のコンテナでも強制的に削除できる。これは最後の手段として使うもので、データが失われたり、予期せぬ副作用があったりする可能性もあるから、使うときは注意が必要だよ。基本的には stop で止めてから rm で削除、という流れを推奨する。
K: 停止してから削除、ですね。分かりました!これで、コンテナを作ったり、動かしたり、止めたり、消したりする基本的な流れが理解できました。
S: うん、素晴らしい!これらのコマンドがDocker操作の基本のキだから、まずはこれをしっかり押さえよう。慣れてきたら、イメージの扱い方や、コンテナ同士を連携させる方法なんかも学んでいくと、さらにDockerの便利さを実感できるはずだよ。
K: ありがとうございます!
Dockerイメージ作成の設計図!Dockerfileとビルド、そして実行
S: 前回の話で、コンテナの起動や停止、削除といった基本的な操作ができるようになったね。でも、そもそもその「コンテナ」はどうやって手に入れるんだろう?実は、コンテナのもとになる「Dockerイメージ」を自分で作るのが一般的なんだ。
K: Dockerイメージを作るんですか?どうやって作るんですか?
S: そのイメージを作るための「設計図」となるのが、Dockerfile というテキストファイルなんだ。このファイルに、どんなOSをベースにするか、どんなソフトウェアをインストールするか、自分のアプリケーションのファイルをどう配置するか、コンテナが起動したときに何を実行するか、といった手順を順番に記述していくんだよ。
K: なるほど、設計図!具体的にはどんな内容を書くんですか?
S: いい質問だ。例えば、Pythonのアプリケーションを動かすイメージを作りたいなら、以下のようなDockerfileを作成することができるよ。一つ一つの行が、イメージを構築する際の手順に対応しているんだ。
Dockerfile
# ベースとなるDockerイメージを指定
FROM python:3.9-slim-buster# 作業ディレクトリを作成・移動
WORKDIR /app# ローカルにあるファイル(Dockerfileと同じディレクトリ以下)をコンテナの /app ディレクトリにコピー
COPY . /app# requirements.txt を先にコピーして依存関係をインストール(層のキャッシュ活用のため)
COPY requirements.txt .
RUN pip install -r requirements.txt# コンテナが起動したときにデフォルトで実行するコマンドを指定
CMD ["python", "main.py"]K: うわあ、なんか見慣れないコマンドがいっぱいですね!これ、一つずつどういう意味なんですか?
S: そうだね、初めてだと戸惑うよね。大丈夫、順番に説明するよ。
FROM python:3.9-slim-buster:
これが一番最初に来るコマンドで、ベースとなるイメージを指定するんだ。今回はPython 3.9がインストールされていて、かつ軽量な slim-buster というDebianベースのイメージを使いますよ、という意味。自分でゼロから環境を作るのは大変だから、Docker Hubなどで公開されている公式イメージをベースにするのが一般的だよ。
WORKDIR /app:
これは、その後のコマンド(COPY や RUN など)を実行する際の作業ディレクトリをコンテナ内に設定するコマンド。この場合、コンテナ内の /app ディレクトリに移動してから次の作業をする、ということになる。これでコマンドのパス指定が楽になるんだ。
COPY . /app:
ローカルのPC(Dockerコマンドを実行している場所)にあるファイルやディレクトリを、Dockerイメージの中にコピーするためのコマンド。最初の . は「Dockerfileがあるカレントディレクトリにある全てのファイルとディレクトリ」を指していて、二番目の /app は「コンテナ内のどこにコピーするか」を指定しているんだ。
COPY requirements.txt .: ここ、さっきの COPY . /app と似てるけど、なんで requirements.txt だけ別にコピーしてるか分かる?
RUN pip install -r requirements.txt:
RUN コマンドは、イメージをビルドする最中に実行されるコマンドだよ。ここではPythonのパッケージ管理ツール pip を使って、requirements.txt に書かれたライブラリをコンテナ内にインストールしているんだ。さっき requirements.txt だけ先にコピーした理由だけど、もしアプリケーション本体のコード(COPY . /app の部分)だけに変更があった場合、requirements.txt が変わっていなければ、この RUN でのパッケージインストールは再度実行されず、前回のビルド結果が使い回されるんだ。これをDockerのレイヤーキャッシュというんだけど、ビルド時間を短縮するテクニックの一つなんだ。
CMD ["python", "main.py"]:
これが、このイメージからコンテナが起動したときにデフォルトで実行されるコマンドだよ。ここでは、コンテナが起動したら /app ディレクトリ(WORKDIR で設定した場所)で python main.pyというコマンドが実行されるように指定している。CMD はDockerfile内に一つだけ指定できて、コンテナの「主となるプロセス」を指定するイメージかな。
K: なるほど!一つ一つの手順がコンテナの中身を作っていくイメージですね。RUN はビルド中に実行されて、CMD はコンテナが起動してから実行されるんですね。そしてキャッシュの話、賢いですね!
S: そうなんだ。このDockerfileという設計図ができたら、いよいよDockerイメージをビルドするコマンドを使うよ。カレントディレクトリにDockerfileがある前提で、次のように実行するぜ。
docker build -t my-python-app .K: docker build ですね!-t と最後の . は何ですか?
S: docker build がイメージをビルドするコマンド。-t は --tag の略で、作成するイメージに**名前(タグ)**を付けるためのオプションだ。ここでは my-python-app という名前を付けている。名前を付けておくと、後でコンテナを起動するときに指定しやすくなるんだ。
最後の . は、ビルドコンテキストを指定しているんだ。これは「Dockerfileはどこにあるか」「COPYコマンドなどで使うファイルはどこから持ってくるか」を示す場所。通常はDockerfileが置かれているディレクトリ自身を指定するので、カレントディレクトリを表す . を使うことが多いんだ。Dockerデーモンはこのビルドコンテキストの中にあるファイルだけを参照できるんだよ。
K: なるほど!設計図がある場所を教えてあげて、ビルドして名前を付けるんですね。これで、my-python-app という名前のイメージが作成される、と。
S: その通り!イメージが無事に作成されたら、次はそれを使ってコンテナを実行する段階だ。実行するには、前回の復習にもなるけど、docker run コマンドを使うよ。
docker run my-python-app
K: これでコンテナが起動して、main.py が実行されるんですよね。Dockerfileの CMD で指定した通りに!
S: 大正解!docker run にイメージ名を指定して実行すると、デフォルトではDockerfileの CMD に書かれたコマンドが実行されるんだ。
K: もし、Dockerfileは同じ my-python-app イメージだけど、今回は main.py じゃなくて、別の script.py というPythonスクリプトを実行したい場合はどうすればいいんですか?Dockerfileを書き換えないといけないですか?
S: いい質問だね!Dockerfileの CMD を書き換えるのは、イメージを作り直すことになるから、ちょっと手間だし柔軟性がない。そういう「一時的に違うコマンドを実行したい」場合は、docker run コマンドを使うときに、実行したいコマンドをイメージ名の後ろに引数として指定するんだ。
たとえば、script.py を実行したいなら、次のように実行することができるよ。
docker run my-python-app python script.py
K: おお!イメージ名の後ろに実行したいコマンドを書けばいいんですね!
S: そうなんだ。docker run <イメージ名> <実行したいコマンド> という形で指定すると、Dockerfileの CMD で指定されたデフォルトコマンドは無視されて、ここで指定したコマンドが代わりに実行されるんだよ。これはデバッグ目的でコンテナの中に入ってシェルを起動したいとき(例: docker run -it my-python-app bash)などにも応用できる、すごく便利な使い方なんだ。
K: なるほど!これでDockerイメージの作り方から、そのイメージを使ってコンテナを起動し、さらに実行するコマンドを柔軟に変える方法まで分かりました!Dockerfileのそれぞれの行の意味も理解できて、すごくスッキリしました!ありがとうございます!
S: どういたしまして!Dockerfileとイメージ、コンテナの関係性、そして build と run の使い分けはDockerの肝だから、ここが理解できると一気に視野が広がるよ。次は、作ったコンテナを外部からアクセスできるようにする方法や、複数のコンテナを連携させる方法なんかも見ていくと、もっと面白くなると思うよ!
まとめ
Dockerは、開発環境から本番環境までチーム全員が一貫した環境を構築・維持できる効率的な仮想化技術として、多くの開発現場で不可欠となっています。一般的な仮想化に比べ、OSごと起動する手間が省けるため驚くほど軽量で高速に動作し、サーバーリソースを大幅に節約できます。基本的なコマンドやDockerfileの作成方法を理解し、実際にプロジェクトで活用してみてください。これからの開発がよりスムーズになるはずです。
最後に、DockerDesktopのインストールとDockerHub入門
のリンクを記載しておきます。これを読んだ方の理解の一助になると幸いです。記事を最後まで読んでいただき、ありがとうございました。
この記事を書いた人
What is BEMA!?
Be Engineer, More Agile


