はい、承知いたしました。誰でもわかる Docker:コンテナ技術の第一歩を解説する、約5000語の詳細な記事を作成します。
誰でもわかる Docker:コンテナ技術の第一歩を解説
はじめに:ソフトウェア開発とデプロイの「困った!」を解決する救世主、Docker
ソフトウェア開発の世界では、古くから存在する大きな課題がありました。それは、「開発環境では動いたのに、本番環境では動かない」という問題、通称「これは私の環境では動く!」問題です。この問題は、アプリケーションが依存するライブラリのバージョン違い、OSのバージョンの違い、設定ファイルの違いなど、様々な要因によって引き起こされます。開発者は「なぜ?!」と頭を抱え、運用チームは「どうすれば動くんだ?!」と途方に暮れる。このような状況は、時間とリソースの無駄遣いとなり、プロジェクトの遅延やコスト増加の原因となっていました。
さらに、複数のアプリケーションを一台のサーバーで動かそうとすると、それぞれのアプリケーションが必要とするライブラリのバージョンが異なり、衝突してしまう「依存関係地獄」に陥ることも少なくありませんでした。あるアプリケーションはPython 2.7が必要なのに、別のアプリケーションはPython 3.9が必要、といった具合です。
これらの問題を根本的に解決し、ソフトウェアの開発、テスト、デプロイ、運用を劇的に効率化した技術が「コンテナ技術」です。そして、このコンテナ技術を世界に普及させ、デファクトスタンダードとなったプラットフォームが「Docker」です。
Dockerが登場する前にもコンテナに類する技術は存在しましたが、Dockerはその使いやすさ、移植性、そして強力なエコシステムによって、瞬く間に開発者や運用担当者の間で広まりました。今や、Webアプリケーション開発、マイクロサービス、継続的インテグレーション/継続的デプロイメント(CI/CD)、さらには機械学習やデータ分析の分野に至るまで、Dockerは様々なシーンで活用されています。
この記事では、Dockerとは何か、コンテナ技術とは何かを、初心者の方でも理解できるように、丁寧かつ詳細に解説していきます。難しい専門用語は避け、具体的な例やコマンドを交えながら、Dockerの基本的な使い方からそのメリット、デメリットまでを網羅します。この記事を読めば、Dockerの全体像を把握し、実際に自分でDockerを使い始めるための第一歩を踏み出せるはずです。
さあ、ソフトウェア開発の世界に革命をもたらしたDockerの世界へ、一緒に踏み出しましょう!
第1章:Docker登場以前の世界 – なぜコンテナが必要だったのか?
Dockerの価値を理解するためには、まずDockerが登場する前のソフトウェア実行環境が抱えていた課題を知ることが重要です。
1.1. 物理サーバー時代の課題
インターネットが黎明期だった頃、一つのアプリケーションを実行するために一台の物理サーバーを丸ごと使うことが一般的でした。ウェブサイト、データベース、メールサーバーなど、重要なアプリケーションにはそれぞれ専用の物理サーバーが割り当てられていました。
この方式のメリットは、他のアプリケーションの影響を受けない「分離性」が高いことでした。しかし、デメリットも非常に大きかったのです。
- リソースの無駄遣い: 多くのアプリケーションは、サーバーのリソース(CPU、メモリ、ストレージなど)を常にフルに使用するわけではありません。一台のサーバーを丸ごと使っても、そのサーバーの能力のほんの一部しか使っていないという状況が頻繁に発生しました。
- コストの高さ: アプリケーションが増えるたびに物理サーバーを購入・設置・管理する必要があり、ハードウェアコスト、電気代、設置場所、管理者の人件費など、多大なコストがかかりました。
- 管理の手間: 各サーバーのOSやミドルウェアのアップデート、セキュリティパッチの適用などを個別に行う必要があり、サーバーの台数が増えるほど管理者の負担が増大しました。
- デプロイの困難さ: 新しいアプリケーションをデプロイしたり、既存のアプリケーションを更新したりする際に、サーバー固有の設定や既存の他のアプリケーションとの依存関係による衝突に気を配る必要があり、非常に手間がかかりました。
1.2. 仮想マシン(VM)の登場とその限界
物理サーバーの課題を解決するために登場したのが「仮想マシン(Virtual Machine, VM)」です。VMwareやVirtualBox、Hyper-Vといった仮想化ソフトウェア(ハイパーバイザー)を使うことで、一台の物理サーバー上に複数の仮想的なコンピューター(仮想マシン)を作り出すことができるようになりました。
仮想マシンは、物理サーバーと同じように独立したOS(ゲストOS)を持ち、その上でアプリケーションを実行できます。これにより、一台の物理サーバーのリソースを複数の仮想マシンで分け合うことが可能になり、リソースの利用効率が向上し、ハードウェアコストを削減できるようになりました。また、アプリケーションごとに独立した環境を持つことで、依存関係の衝突もある程度避けることができるようになりました。
VMは物理サーバー時代の多くの課題を解決し、クラウドコンピューティングの基盤技術ともなりました。しかし、VMにもまたいくつかの限界がありました。
- リソースオーバーヘッド: 各仮想マシンは独立したOS(ゲストOS)を実行するため、そのOS自体がリソース(CPU、メモリ、ディスク容量)を消費します。また、ハイパーバイザーもリソースを消費します。そのため、コンテナと比較するとリソースのオーバーヘッドが大きくなりがちです。
- 起動時間の長さ: 仮想マシンを起動する際には、ゲストOSの起動処理が必要となるため、数分から数十分かかることがあります。これは、素早いデプロイやオートスケーリングといった用途には不向きな場合があります。
- イメージサイズの大きさ: 仮想マシンのイメージ(OSを含むファイル群)は、数GBから数十GBになることが一般的です。これにより、イメージの作成、保存、配布に時間がかかり、ストレージ容量も圧迫します。
- 環境構築の手間: 仮想マシンを作成した後も、その上でアプリケーションを実行するために必要なミドルウェアやライブラリをゲストOS上にインストールし、設定するといった環境構築の手間がかかります。
仮想マシンは確かに素晴らしい技術であり、現在も多くの場面で活用されていますが、より軽量で、より高速で、より移植性の高いアプリケーション実行環境が求められるようになったのです。そこで登場したのが、コンテナ技術です。
第2章:コンテナ技術とは何か? – 「どこでも動く」魔法の箱
コンテナ技術は、仮想マシンとは異なるアプローチでアプリケーションの分離と移植性を実現します。仮想マシンが「ハードウェアごと仮想化」するのに対し、コンテナは「OSの一部を共有しつつ、アプリケーションとその実行環境を隔離」します。
2.1. コンテナの基本的な考え方:荷物用コンテナのアナロジー
コンテナ技術を理解する上で、最もよく使われるアナロジーは「海上輸送用の荷物用コンテナ」です。
考えてみてください。世界中を船で運ばれる荷物は、大きさも形も種類も様々です。もし荷物をそのままの形で船に積み込んだり、港で積み替えたりするとしたら、途方もない手間と時間がかかるでしょう。そこで考え出されたのが、サイズと形状が世界共通規格で決められた頑丈な「コンテナ」に、様々な荷物を詰め込んでしまう方法です。
コンテナの中には、穀物が入っているかもしれないし、自動車部品が入っているかもしれないし、衣料品が入っているかもしれません。中身が何であれ、コンテナの「外側」はすべて同じ形・サイズです。これにより、船も港のクレーンもトラックも鉄道も、この共通規格のコンテナを扱う仕組みだけを用意すれば良くなります。中身を気にすることなく、効率的に荷物を運んだり、積み替えたり、保管したりできるのです。
ソフトウェアの世界の「コンテナ」も、これと非常によく似ています。
アプリケーションとその実行に必要なすべてのもの(コード、ランタイム、システムツール、ライブラリ、設定ファイルなど)を、一つの標準化された「コンテナ」の中にまとめてパッケージングします。この「コンテナ」は、中身がどのようなアプリケーションであっても、実行環境(OSやサーバー)からは同じように扱えるようになります。
2.2. コンテナの仕組み:OSの機能を共有する
仮想マシンがゲストOSを丸ごと持つリソースオーバーヘッドが大きいという問題を解決するために、コンテナはホストOSのカーネルを共有します。
コンテナ技術のコアは、Linuxカーネルが提供する以下の2つの機能です。
- Namespace (名前空間): プロセス、ネットワークインターフェース、ファイルシステムのマウントポイントなどを分離する機能です。これにより、あるコンテナ内のプロセスは、他のコンテナ内のプロセスやホストOS上のプロセスからは見えなくなります。ネットワークも分離され、各コンテナは自身のネットワークインターフェースやIPアドレスを持つことができます。ファイルシステムも分離され、各コンテナは独立したルートファイルシステムを持つことができます。
- Control Groups (cgroups): プロセスが使用できるCPU、メモリ、ネットワーク帯域、ディスクI/Oなどのリソースを制限・管理する機能です。これにより、一つのコンテナがホストOSや他のコンテナのリソースを独占してしまうことを防ぎ、安定した動作を保証します。
これらの機能を使うことで、コンテナはゲストOSを持たずに、ホストOSのカーネルを共有しながらも、あたかも独立した環境であるかのように振る舞うことができるのです。
**仮想マシン (VM):**
`[ハードウェア] → [ホストOS] → [ハイパーバイザー] → [ゲストOS] → [アプリケーション + ライブラリ]`
* ゲストOS分のオーバーヘッドが大きい
* 完全に独立した環境
**コンテナ:**
`[ハードウェア] → [ホストOS (カーネル共有)] → [コンテナエンジン (Dockerなど)] → [アプリケーション + ライブラリ]`
* ホストOSのカーネルを共有するため、軽量で高速
* OSレベルでの分離 (ファイルシステム、プロセス、ネットワークなどは分離)
コンテナはゲストOSを持たないため、仮想マシンに比べて以下のようなメリットがあります。
- 軽量で高速: ゲストOSの起動や実行のオーバーヘッドがないため、起動が非常に速く(数秒程度)、消費リソースも少なくて済みます。
- 高い移植性: アプリケーションとその依存関係がすべてコンテナにパッケージ化されているため、「Build once, Run anywhere」(一度ビルドすればどこでも動く)が実現できます。開発環境、テスト環境、ステージング環境、本番環境、さらには異なるクラウド環境であっても、同じコンテナイメージを使えば同じように動作します。
- 効率的なリソース利用: 一つのホストOS上で多数のコンテナを効率的に実行できます。
- 管理の容易さ: 標準化されたコンテナイメージとランタイムによって、アプリケーションのデプロイ、スケーリング、管理が容易になります。
この革新的なコンテナ技術を、誰でも簡単に扱えるようにしたプラットフォーム、それが「Docker」なのです。
第3章:Dockerとは何か? – コンテナ活用のためのプラットフォーム
Dockerは、コンテナイメージの作成、配布、実行、管理を行うためのオープンソースプラットフォームです。Linuxカーネルのコンテナ機能を活用していますが、それを開発者や運用担当者が直感的に扱えるツールとして提供しています。
Dockerが登場するまで、Linuxのコンテナ機能(LXCなど)を使うには専門的な知識が必要でした。Dockerは、この複雑な部分を隠蔽し、シンプルなコマンドや設定ファイル(Dockerfile)を通じてコンテナを扱えるようにしました。これにより、コンテナ技術が広く普及し、多くの開発者や企業がその恩恵を受けられるようになったのです。
3.1. Dockerの主要なコンポーネント
Dockerプラットフォームは、いくつかの重要なコンポーネントで構成されています。
- Docker Engine: Dockerのコアとなる部分で、コンテナの実行や管理を行うデーモン(バックグラウンドプロセス)です。クライアントからのAPIリクエストを受け付け、イメージ管理、コンテナ実行、ネットワーク構築、データボリューム管理などを担当します。
- Docker CLI (Command Line Interface): ユーザーがDocker Engineと対話するためのコマンドラインツールです。
docker run
,docker build
,docker pull
といったコマンドを実行することで、コンテナの操作を行います。 - Docker Desktop: WindowsやmacOS上でDocker Engineを実行するためのアプリケーションです。これらのOSはネイティブにはLinuxコンテナをサポートしていませんが、Docker Desktopは軽量なLinux仮想マシンなどを内部で実行することで、Docker環境を提供します。開発者が自身のローカルマシンでDockerを使うためによく利用されます。
- Docker Registry: Dockerイメージを保存・共有するためのリポジトリサービスです。最も有名なのは公式のDocker Hubですが、プライベートなレジストリを構築することも可能です。
docker pull
コマンドでレジストリからイメージを取得し、docker push
コマンドでイメージをレジストリにアップロードします。
3.2. Dockerのコアコンセプト:イメージとコンテナ
Dockerを理解する上で、最も重要な概念が「イメージ」と「コンテナ」です。これらはしばしば混同されがちですが、全く異なるものです。
-
Docker Image (イメージ):
- アプリケーションとその実行に必要なすべてのものが含まれた、読み取り専用のテンプレートです。
- OSの最小限のファイル、アプリケーションコード、ライブラリ、設定ファイルなどが層(Layer)状に積み重ねられて構成されています。
- これは例えるなら、「クラスの設計図」や「料理のレシピ」のようなものです。これ自体は実行可能な「何か」ではありませんが、これから実行可能な「何か」を作り出すための元になります。
- イメージは、通常「Dockerfile」というテキストファイルに記述された手順に従ってビルドされます。
- イメージはDocker Registryに保存され、共有されます。
-
Docker Container (コンテナ):
- Dockerイメージを基にして作成され、実行されているインスタンスです。
- イメージの読み取り専用層の上に、コンテナ固有の書き込み可能な層が追加されます。コンテナ内で発生した変更(ファイルの作成・変更、プロセス実行など)はこの書き込み可能な層に記録されます。
- これは例えるなら、「クラスから生成されたオブジェクト」や「レシピを見て実際に作られた料理」のようなものです。実際に動作する「何か」です。
- コンテナは隔離されており、それぞれが独立したファイルシステム、プロセス空間、ネットワークインターフェースを持ちます(ただしカーネルは共有)。
まとめると、イメージは静的な設計図であり、コンテナはその設計図から作られた動的な実体です。一つのイメージから複数のコンテナを起動することができます。
第4章:Dockerを始めよう! – 基本的な使い方とコマンド
Dockerの概念を理解したところで、実際にDockerを使ってみましょう。ここでは、Dockerのインストール方法から、最も基本的なコマンドの使い方までを解説します。
4.1. Dockerのインストール
Dockerを使うには、まずお使いのOSにDockerをインストールする必要があります。Windows、macOS、Linuxそれぞれに対応したインストール方法があります。
- Windows / macOS: 公式サイトから「Docker Desktop」をダウンロードしてインストールするのが最も簡単です。インストーラーを実行すれば、必要なものがすべてセットアップされます。Docker Desktopは、CLIツール、Docker Engine、Docker Compose(後述)などが含まれています。
- Linux: 各ディストリビューション向けに公式のインストールスクリプトやパッケージが提供されています。Ubuntu、Debian、CentOS/Fedoraなど、主要なディストリビューションのインストール手順は公式ドキュメントを参照してください。通常、リポジトリを追加してパッケージマネージャー(
apt
,yum
,dnf
など)を使ってインストールします。
インストール後、ターミナルやコマンドプロンプトを開いて以下のコマンドを実行し、Dockerが正しくインストールされたか確認します。
bash
docker --version
または
bash
docker info
これらのコマンドがDockerのバージョン情報や詳細情報を表示すれば、インストールは成功です。
4.2. 最初のDockerコマンド:docker run
Dockerで最も頻繁に使うコマンドが docker run
です。これは、指定したイメージから新しいコンテナを作成し、実行するためのコマンドです。
まずは、Dockerの動作確認のためによく使われる hello-world
イメージを実行してみましょう。
bash
docker run hello-world
このコマンドを実行すると、以下の処理が行われます。
- Docker Engineが
hello-world
という名前のイメージがローカルマシンに存在するか確認します。 - もし存在しなければ、デフォルトのレジストリであるDocker Hubから
hello-world
イメージをプル(ダウンロード)します。 - プルしたイメージを基に、新しいコンテナを作成します。
- 作成したコンテナを起動します。
- コンテナ内で指定されたプログラム(この場合はシンプルなメッセージを表示するプログラム)が実行されます。
- プログラムの実行が終了すると、コンテナも停止します。
出力には、Dockerが正しく動作していることと、実行された手順に関するメッセージが表示されるはずです。
“`
Unable to find image ‘hello-world:latest’ locally
latest: Pulling from library/hello-world
…(ダウンロードの進行状況が表示される)…
Digest: sha256:…
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
…(その他のメッセージ)…
“`
4.3. コンテナの実行と操作
hello-world
はすぐに終了するコンテナでしたが、通常はウェブサーバーのように継続的に動作するアプリケーションをコンテナで実行します。
例として、Ubuntu OSのコンテナを起動し、その中で対話的にコマンドを実行してみましょう。
bash
docker run -it ubuntu bash
このコマンドのオプションについて説明します。
-i
(or--interactive
): コンテナの標準入力 (STDIN) を開いたままにします。これにより、コンテナ内でコマンドを入力できるようになります。-t
(or--tty
): 疑似TTY(仮想端末)を割り当てます。これにより、コンテナ内でのシェル操作が可能になり、対話的なセッションを確立できます。-it
はセットで使われることが多いです。ubuntu
: 使用するDockerイメージの名前です。Docker Hubの公式Ubuntuイメージが使われます。bash
: コンテナが起動した後に実行するコマンドです。ここではBashシェルを起動します。
このコマンドを実行すると、Ubuntuコンテナが起動し、そのコンテナ内のBashシェルに接続されます。プロンプトがコンテナ内のものに変わるはずです(例: root@<コンテナID>:/#
)。
ここで、コンテナ内でUbuntuのコマンドを実行できます。
bash
ls /
cat /etc/os-release
exit
exit
と入力すると、Bashシェルが終了し、それに伴いコンテナも停止します。
4.4. 実行中のコンテナを確認する:docker ps
バックグラウンドで実行されているコンテナや、最近実行されて停止したコンテナを確認したい場合があります。
bash
docker ps
このコマンドは、現在実行中のコンテナの一覧を表示します。先ほど ubuntu bash
で起動して exit
で終了したコンテナは、このコマンドでは表示されません。
停止したコンテナを含め、すべてのコンテナを表示するには -a
(or --all
) オプションを使います。
bash
docker ps -a
このコマンドを実行すると、停止した ubuntu
コンテナや、以前実行した hello-world
コンテナなども表示されるはずです。各コンテナにはユニークな CONTAINER ID
や、自動的に割り当てられた NAMES
が表示されます。
出力例:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1b2c3d4e5f6 ubuntu "bash" 2 minutes ago Exited (0) 2 minutes ago compassionate_bohr
g7h8i9j0k1l2 hello-world "/hello" 5 minutes ago Exited (0) 5 minutes ago vigilant_sammet
4.5. コンテナを停止・起動・再起動する
実行中のコンテナを停止したい場合は、docker stop
コマンドを使います。コンテナIDまたはコンテナ名で指定します。
bash
docker stop <コンテナID または コンテナ名>
例:
bash
docker stop compassionate_bohr
停止したコンテナを再び起動したい場合は、docker start
コマンドを使います。
bash
docker start <コンテナID または コンテナ名>
実行中のコンテナを再起動したい場合は、docker restart
コマンドを使います。
bash
docker restart <コンテナID または コンテナ名>
4.6. コンテナを削除する:docker rm
不要になったコンテナは削除してリソースを解放しましょう。コンテナを削除するには docker rm
コマンドを使います。
bash
docker rm <コンテナID または コンテナ名>
例:
bash
docker rm compassionate_bohr
注意: 実行中のコンテナは削除できません。削除する前に docker stop
で停止させる必要があります。
4.7. Dockerイメージを確認・削除する
ローカルマシンにダウンロードまたはビルドされたDockerイメージの一覧を確認するには、docker images
コマンドを使います。
bash
docker images
出力例:
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest d13c934041yc 2 weeks ago 72.8MB
hello-world latest bf0087c6f2c8 2 months ago 13.3kB
不要になったイメージは削除してディスク容量を解放しましょう。イメージを削除するには docker rmi
コマンドを使います。イメージIDまたは REPOSITORY:TAG
で指定します。
bash
docker rmi <イメージID または REPOSITORY:TAG>
例:
bash
docker rmi ubuntu:latest
docker rmi bf0087c6f2c8
注意: 実行中のコンテナがそのイメージを使用している場合、イメージは削除できません。先にコンテナを削除する必要があります。
第5章:独自のDockerイメージを作成する:Dockerfile
既存のDockerイメージを使うだけではなく、自分のアプリケーションを実行するための独自のイメージを作成することが、Docker活用の重要なステップです。Dockerイメージは「Dockerfile」というテキストファイルを使って定義・ビルドされます。
Dockerfileは、イメージを構築するための一連の手順を記述したスクリプトのようなものです。DockerはDockerfileを読み込み、上から順に命令を実行してイメージを作成します。
5.1. Dockerfileの基本構造と命令
Dockerfileは拡張子なしの Dockerfile
という名前で作成するのが一般的です(他の名前でも可能ですが、慣習としてこの名前を使います)。内容はシンプルなテキストです。
基本的なDockerfileの構造とよく使う命令をいくつか見てみましょう。
“`Dockerfile
ベースイメージを指定 – 作成するイメージの元となるイメージ
FROM ubuntu:latest
作成者情報などのメタデータ (必須ではない)
LABEL maintainer=”Your Name your.email@example.com“
イメージビルド時に実行されるコマンド
アプリケーションに必要なパッケージのインストールなどに使う
RUN apt-get update && apt-get install -y –no-install-recommends nginx \
&& rm -rf /var/lib/apt/lists/*
ホストマシンのファイルやディレクトリをイメージ内にコピー
アプリケーションのソースコードや設定ファイルなどをコピーするのに使う
COPY ./html /usr/share/nginx/html
コンテナがリッスンするポートを指定 (ドキュメント目的。ポートマッピングは docker run
で行う)
EXPOSE 80
コンテナ起動時にデフォルトで実行されるコマンド
これがコンテナの「メイン」となるプロセスになる
CMD [“nginx”, “-g”, “daemon off;”]
“`
主な命令の意味:
FROM <image>[:<tag>]
: ベースとなるイメージを指定します。すべてのDockerfileはこの命令から始まります。例:FROM ubuntu:latest
,FROM python:3.9-slim
,FROM nginx:latest
RUN <command>
: イメージをビルドする際に、コンテナ内でコマンドを実行します。これにより、パッケージのインストールやファイルの設定などを行います。複数のコマンドを&&
でつないで一行で書くのが一般的です。COPY <source> <destination>
: ホストマシンの指定したファイルやディレクトリを、イメージ内の指定したパスにコピーします。ADD <source> <destination>
:COPY
と似ていますが、URLからのファイルダウンロードや、tarアーカイブの自動解凍などの機能も持ちます。通常はCOPY
が推奨されます。WORKDIR <directory>
: 以降のRUN
,CMD
,ENTRYPOINT
,COPY
,ADD
命令が実行される際のワーキングディレクトリを設定します。EXPOSE <port>
: コンテナがリッスンするポート番号を指定します。これはあくまでドキュメントとしての役割が強く、実際にホストマシンからコンテナのポートにアクセスするには、docker run -p
オプションでポートマッピングを行う必要があります。ENV <key>=<value>
: 環境変数を設定します。VOLUME <path>
: コンテナ内の指定したパスをボリュームとして宣言します。これは、データの永続化やコンテナ間でのデータ共有に使われます(詳細は後述)。CMD <command>
: コンテナ起動時に実行されるデフォルトのコマンドを指定します。Dockerfile内で一つだけ指定できます。通常、コンテナのメインとなるプロセスを起動するコマンドを指定します。実行形式と引数を配列で指定する形(CMD ["executable", "param1", "param2"]
)が推奨されます。ENTRYPOINT <command>
:CMD
と似ていますが、docker run
コマンドで引数が指定された場合、その引数はENTRYPOINT
の引数として渡されます。CMD
はENTRYPOINT
のデフォルト引数として機能させることができます。
5.2. Dockerfileを使ったイメージのビルド
Dockerfileを作成したら、そのDockerfileを基にDockerイメージをビルドします。docker build
コマンドを使います。
カレントディレクトリに以下の内容で Dockerfile
を作成し、html
という名前のディレクトリを作成してその中に適当な index.html
ファイルを置きます。
“`Dockerfile
Dockerfile (同じディレクトリに html/index.html を配置)
FROM nginx:latest
COPY ./html /usr/share/nginx/html
EXPOSE 80
CMD [“nginx”, “-g”, “daemon off;”]
“`
“`html
Hello from Dockerized Nginx!
This page is served from a Docker container.
“`
次に、Dockerfileのあるディレクトリ(コンテキストディレクトリと呼ばれます)で以下のコマンドを実行します。
bash
docker build -t my-nginx-app .
docker build
: イメージビルドコマンドです。-t my-nginx-app
: ビルドするイメージにタグ(名前)を付けます。ここではmy-nginx-app
という名前にしています。タグ名をname:tag
の形式で指定しない場合、デフォルトで:latest
タグが付きます。.
: Dockerfileがあるディレクトリ(ビルドコンテキスト)を指定します。.
はカレントディレクトリを意味します。
このコマンドを実行すると、Dockerは指定されたディレクトリからDockerfileを探し、そこに記述された命令を一つずつ実行してイメージを作成します。各 RUN
や COPY
などの命令は、イメージの新しいレイヤーとしてコミットされていきます。
ビルドが成功したら、docker images
コマンドで作成されたイメージを確認できます。
bash
docker images
my-nginx-app
という名前のイメージが表示されているはずです。
5.3. ビルドしたイメージを実行する
作成した my-nginx-app
イメージからコンテナを起動し、Webサーバーとして動かしてみましょう。Nginxはデフォルトで80番ポートを使いますので、ホストマシンのポートとコンテナのポートを関連付ける(ポートマッピング)必要があります。
bash
docker run -p 8080:80 my-nginx-app
docker run
: コンテナ実行コマンドです。-p 8080:80
: ポートマッピングを指定します。ホストポート:コンテナポート
の形式です。これにより、ホストマシンの8080番ポートへのアクセスが、コンテナの80番ポートに転送されるようになります。my-nginx-app
: 実行するイメージの名前です。
コマンドを実行すると、コンテナ内でNginxが起動し、バックグラウンドで実行されます(Dockerfileの CMD
命令が nginx -g daemon off;
なので、フォアグラウンドでログを出力しつつ起動します)。
Webブラウザを開き、http://localhost:8080
にアクセスしてみてください。作成した index.html
の内容が表示されれば成功です!
コンテナを停止するには、ターミナルで Ctrl+C
を押すか、別のターミナルで docker ps
でコンテナIDを確認し、docker stop <コンテナID>
コマンドを使います。
第6章:Dockerイメージの共有:Docker HubとRegistry
作成したDockerイメージは、自分だけで使うだけでなく、他の人と共有したり、別の環境で使ったりしたい場合があります。そのために使用するのが「Docker Registry」です。Docker Hubは、Docker社が提供する公式のパブリックRegistryです。
6.1. Docker Hub
Docker Hub (https://hub.docker.com/
) は、世界中の開発者が作成・公開した様々なDockerイメージが登録されている巨大なライブラリです。公式イメージ(OSやミドルウェアなど)、認証済みパブリッシャーのイメージ、コミュニティイメージなどが公開されています。
docker pull <image_name>
コマンドでイメージをダウンロードする際、特にRegistryを指定しない場合は、デフォルトでDocker Hubからイメージが検索されます。
6.2. Docker Hubへのイメージのプッシュ(アップロード)
自分が作成したイメージをDocker Hubに公開したり、別のマシンからアクセスしたりするためには、Docker Hubアカウントを作成し、イメージをプッシュする必要があります。
- Docker Hubアカウント作成: Docker Hubのウェブサイトでアカウントを作成します。
- Dockerログイン: ローカルマシンのターミナルでDocker Hubにログインします。
bash
docker login
ユーザー名とパスワードを聞かれるので、入力します。 - イメージにタグを付ける: Docker Hubにプッシュするためには、イメージ名にユーザー名(または組織名)をプレフィックスとして付ける必要があります。
docker tag
コマンドを使います。
bash
docker tag <既存のイメージ名> <dockerhub_username>/<新しいイメージ名>[:<tag>]
例: 先ほど作成したmy-nginx-app
イメージにタグを付けます。
bash
docker tag my-nginx-app your_dockerhub_username/my-nginx-app:v1.0
これで、your_dockerhub_username/my-nginx-app:v1.0
という新しいタグが同じイメージに付きます。 - イメージをプッシュ:
docker push
コマンドでDocker Hubにイメージをアップロードします。
bash
docker push <dockerhub_username>/<image_name>[:<tag>]
例:
bash
docker push your_dockerhub_username/my-nginx-app:v1.0
プッシュが完了すると、Docker Hubの自分のリポジトリにイメージが表示されるようになります。これで、インターネット経由でどこからでもこのイメージをプルできるようになります。
6.3. プライベートRegistry
Docker Hubは便利ですが、社内だけで使いたいイメージや、公開したくないイメージを扱う場合は、プライベートRegistryを構築することも可能です。Docker Registryはオープンソースであり、簡単に自身のサーバーにデプロイできます。
第7章:コンテナの永続化とネットワーキング
コンテナはデフォルトでは一時的な環境であり、コンテナを削除するとその中に保存されていたデータも失われます。また、複数のコンテナが連携して動作するためには、コンテナ間での通信(ネットワーキング)が必要です。ここでは、これらの重要な概念について解説します。
7.1. データの永続化:Volume
コンテナ内で生成されたデータを永続化したい場合(データベースのデータ、ログファイル、アップロードされたファイルなど)や、複数のコンテナ間でデータを共有したい場合は、「Volume」を使用します。
Volumeは、ホストマシンのファイルシステム上にDockerが管理する領域を作成し、それをコンテナ内の特定のディレクトリにマウントする仕組みです。コンテナが停止・削除されてもVolumeは保持されるため、データが失われることはありません。新しいコンテナを同じVolumeに接続すれば、以前のデータを引き継ぐことができます。
Volumeには主に2つの種類があります。
- 名前付きVolume (Named Volumes): DockerがホストOS上の場所を管理します。ユーザーは名前でVolumeを指定するだけでよく、ホストOS上のどこに作成されるかを意識する必要はありません。これが最も一般的なVolumeの使い方です。
- 作成:
docker volume create mydata
- コンテナへのマウント:
docker run -v mydata:/app/data my-app
(ホスト側のVolume名:コンテナ側のパス
)
- 作成:
- バインドマウント (Bind Mounts): ホストOS上の特定のディレクトリを、コンテナ内の特定のディレクトリに直接マウントします。これは、開発中にホスト上のソースコードをコンテナ内の開発環境にマウントして、ホスト側でコードを変更したらコンテナ内に即座に反映されるようにする、といった用途によく使われます。
- コンテナへのマウント:
docker run -v /path/on/host:/path/in/container my-app
(ホスト側のパス:コンテナ側のパス
)
- コンテナへのマウント:
Volumeを使うことで、コンテナの使い捨て可能(Disposable)な特性を保ちつつ、必要なデータを安全に管理することができます。
7.2. コンテナネットワーキング
Dockerは、コンテナ間の通信や、コンテナと外部(ホストマシン、インターネット)との通信を管理するためのネットワーク機能を提供します。
Dockerをインストールすると、デフォルトでいくつかのネットワークが作成されます。
- bridge: デフォルトのネットワークです。特に指定しない場合、コンテナはこのネットワークに接続されます。bridgeネットワークに接続されたコンテナは、互いにコンテナ名やIDで通信できます(デフォルトではIPアドレスを知る必要がありますが、DNS設定を有効にすれば名前解決も可能)。ホストマシンや外部とは、ポートマッピング(
-p
オプション)を介して通信します。 - host: コンテナがホストOSのネットワーク名前空間を共有します。コンテナはホストと同じIPアドレスを持ち、ポートマッピングなしにホストのネットワークリソースに直接アクセスできます。高いパフォーマンスが得られますが、隔離性が失われます。
- none: コンテナはどのネットワークにも接続されず、ネットワークインターフェースを持ちません。外部との通信が不要なバッチ処理などに使用されます。
- overlay / macvlan など: 複数のDockerホストをまたいだコンテナ間通信や、コンテナに物理ネットワークと同じセグメントのIPアドレスを割り当てるための高度なネットワークドライバーです。SwarmやKubernetesといったオーケストレーションツールで使用されることが多いです。
通常、複数のコンテナで構成されるアプリケーション(例: Webサーバーとデータベース)を構築する際には、デフォルトのbridgeネットワークではなく、ユーザー定義のbridgeネットワークを作成してそこにコンテナを接続することが推奨されます。
“`bash
ユーザー定義ネットワークの作成
docker network create my-app-network
作成したネットワークにコンテナを接続して起動
docker run –network my-app-network –name web -d my-nginx-app
docker run –network my-app-network –name db -d postgres
同じネットワーク内のコンテナは、コンテナ名をホスト名として名前解決できる(デフォルト)
例: webコンテナ内から db コンテナに postgres://db にアクセスできる
“`
ユーザー定義ネットワークを使うことで、同じネットワーク内のコンテナはコンテナ名で互いにアクセスできるようになり、コンテナ間の疎結合性を高めることができます。
第8章:Dockerのメリットとデメリット
Dockerは多くのメリットをもたらしますが、万能ではありません。利用にあたっては、その利点と欠点を理解しておくことが重要です。
8章.1 Dockerのメリット
- 環境構築の再現性: Dockerイメージは、アプリケーションとその実行に必要なすべてのものをカプセル化します。これにより、「Dockerfile」というコードとして環境を定義し、誰でもどこでも同じ環境を再現できるようになります。「私の環境では動くのに!」問題は過去のものとなります。
- 開発環境と本番環境の差異をなくす: 開発、テスト、ステージング、本番といった各環境で同じDockerイメージを使用することで、環境による差異に起因する問題を劇的に減らすことができます。
- アプリケーションの移植性向上: コンテナは標準化された単位であり、Dockerがインストールされていれば、物理サーバーでも、仮想マシン上でも、クラウド上でも、同じように動作します。これにより、オンプレミスからクラウドへの移行なども容易になります。
- デプロイメントの高速化と効率化: コンテナは数秒で起動するため、アプリケーションのデプロイやスケーリングが非常に迅速に行えます。新しいバージョンへの更新や、問題発生時のロールバックも容易です。
- リソース利用効率の向上: VMと比較してオーバーヘッドが小さく、一台のサーバー上でより多くのアプリケーションを効率的に実行できます。
- プロセス分離とセキュリティ: 各コンテナは分離されているため、一つのコンテナ内の問題が他のコンテナやホストOSに影響を与えるリスクを低減できます(ただしカーネルレベルの脆弱性には注意が必要)。
- 開発ワークフローの改善: 開発者は依存関係を気にすることなく、コンテナ内でアプリケーションの開発に集中できます。複数プロジェクトで異なる技術スタックを使用する場合でも、コンテナを使えば環境の切り替えが容易です。
- マイクロサービスアーキテクチャとの相性: 小さな独立したサービスごとにコンテナを作成し、それらを連携させるマイクロサービスアーキテクチャにおいて、Dockerは非常に強力なツールとなります。
8章.2 Dockerのデメリット・考慮事項
- 学習コスト: Dockerの概念(イメージ、コンテナ、Dockerfile、Registry、Volume、Networkなど)やコマンドに慣れるまでには、ある程度の学習が必要です。特に、VMとは異なる考え方である点を理解する必要があります。
- 永続化データの管理: コンテナ自体は一時的なものであるため、データベースのデータなどの永続化データはVolumeを使って管理する必要があります。Volumeのバックアップやリストアといった運用を考慮する必要があります。
- コンテナオーケストレーションの複雑さ: 数個のコンテナであれば手動での管理も可能ですが、本番環境で数十、数百、数千といった規模のコンテナを運用するには、コンテナオーケストレーションツール(Kubernetes, Docker Swarmなど)が必要になります。これらのツールは学習コストが高く、運用も複雑になります。
- GUIアプリケーションの扱いにくいさ: 基本的に、DockerコンテナはサーバーサイドアプリケーションやCLIツールを実行するのに適しています。GUIを持つデスクトップアプリケーションなどをコンテナ化するのは、技術的には可能ですが、通常は煩雑であり、一般的なユースケースではありません。
- ホストOSのカーネルへの依存: コンテナはホストOSのカーネルを共有するため、コンテナで実行できるOSは基本的にホストOSと同じカーネルアーキテクチャを持つLinuxディストリビューションに限られます(Windows Serverコンテナなど特殊な場合を除く)。WindowsやmacOS上でLinuxコンテナを動かす場合は、内部でLinux VMが使われています。
- セキュリティ(注意点): コンテナはVMより軽量な分離を提供しますが、カーネルは共有しているため、カーネルの脆弱性はすべてのコンテナに影響を与えます。また、イメージの脆弱性スキャンや、適切なユーザー権限でのコンテナ実行など、コンテナ特有のセキュリティ対策も重要です。
これらのデメリットや考慮事項を理解した上で適切に利用すれば、Dockerはソフトウェア開発と運用に計り知れないメリットをもたらす強力なツールとなります。
第9章:Dockerの応用とエコシステム(次のステップへ)
これまでにDockerの基本的な使い方を見てきましたが、Dockerの真価は、さらに高度な使い方や、関連ツールと組み合わせることで発揮されます。
9.1. Docker Compose:複数のコンテナをまとめて管理
多くのアプリケーションは、Webサーバー、アプリケーションサーバー、データベースなど、複数の異なるサービス(コンテナ)で構成されています。これらのコンテナを個別に docker run
で起動し、ネットワークやVolumeを設定するのは非常に手間がかかります。
「Docker Compose」は、複数のコンテナで構成されるアプリケーションを定義・管理するためのツールです。YAMLファイル (docker-compose.yml
) にサービス(コンテナ)、ネットワーク、Volumeなどの設定を記述し、docker-compose up
という一つのコマンドで、それらすべてをまとめて起動したり停止したりできます。開発環境での複数コンテナアプリケーションの構築や、小規模な本番環境での利用によく使われます。
9.2. コンテナオーケストレーション:KubernetesとDocker Swarm
大規模な本番環境で多数のコンテナを運用する場合、コンテナのデプロイ、スケーリング、負荷分散、自己復旧、ローリングアップデートなどを自動化・効率化する必要があります。これらの機能を提供するのが「コンテナオーケストレーション」ツールです。
- Kubernetes: Googleが開発し、CNCF(Cloud Native Computing Foundation)が管理する、最も広く使われているコンテナオーケストレーションプラットフォームです。非常に高機能で柔軟性がありますが、学習コストは高いです。
- Docker Swarm: Docker社が提供するコンテナオーケストレーションツールで、Docker Engineに統合されています。Kubernetesほど高機能ではありませんが、Kubernetesよりシンプルで学習しやすいという特徴があります。
これらのツールを使うことで、コンテナ化されたアプリケーションを大規模かつ信頼性高く運用することが可能になります。
9.3. CI/CDパイプラインでの活用
Dockerは、継続的インテグレーション(CI)や継続的デプロイメント(CD)のパイプラインにおいて非常に重要な役割を果たします。
- CI: Dockerfileを使ってアプリケーションのコードからDockerイメージを自動的にビルドし、テストを実行します。ビルドされたイメージは、デプロイ可能なアーティファクトとなります。
- CD: ビルドされたDockerイメージをContainer Registryからプルし、テスト環境、ステージング環境、本番環境といった各環境にデプロイします。どの環境でも同じイメージを使うため、環境差異によるデプロイ失敗のリスクを減らせます。
Jenkins, GitLab CI, GitHub Actions, CircleCIなどのCI/CDツールは、Dockerとの連携機能を強力にサポートしています。
9.4. その他のエコシステムツール
Dockerの周りには、様々な課題を解決するためのツールやサービスが存在します。
- Container Registry: Docker Hub以外のRegistryとして、 Quay.io, Google Container Registry (GCR), Amazon Elastic Container Registry (ECR) などがあります。
- イメージスキャン: Dockerイメージに含まれる脆弱性を検出するツール(Clair, Trivyなど)や、Docker Hubなどのサービスが提供するスキャン機能があります。
- モニタリング・ロギング: コンテナのパフォーマンス監視やログ収集のためのツール(Prometheus, Grafana, Elasticsearch, Kibanaなど)と連携させて使用します。
第10章:まとめ:Dockerで広がる可能性
ここまで、Dockerとは何か、なぜ必要とされているのか、その仕組み、基本的な使い方、そして応用例について詳しく解説してきました。
Dockerは、単なる開発ツールや運用ツールにとどまらず、ソフトウェアのライフサイクル全体に変革をもたらすプラットフォームです。アプリケーションとその実行環境を「コンテナ」という標準化された単位にカプセル化することで、「Build once, Run anywhere」の世界を実現し、開発者と運用担当者の間の壁を低くしました。
「これは私の環境では動く!」問題や依存関係地獄に悩まされることなく、開発者はコードを書くことに集中でき、運用担当者は環境管理の複雑さから解放されます。アジリティの高い開発、迅速なデプロイ、効率的なリソース利用が可能となり、ビジネスの変化に素早く対応できる柔軟なシステム構築を支援します。
もちろん、Dockerも万能ではありません。学習コスト、永続化データの管理、大規模運用時のオーケストレーションの複雑さといった課題もあります。しかし、そのメリットは多くの場面でデメリットを上回ります。
この記事が、あなたがDockerとコンテナ技術の世界への第一歩を踏み出す手助けとなれば幸いです。まずは、Dockerをインストールし、docker run hello-world
から始めてみてください。そして、Dockerfileを作成して自分のアプリケーションをコンテナ化し、Docker Hubにプッシュしてみる。VolumeやNetworkを試してみる。一歩ずつ進んでいくうちに、Dockerがどれほど強力で便利なツールであるかを実感できるはずです。
コンテナ技術は、クラウドネイティブ時代におけるソフトウェア開発・運用の基盤技術として、今後ますます重要性が高まるでしょう。Dockerを学ぶことは、現代のITエンジニアにとって非常に価値のあるスキルとなります。
さあ、Dockerを使って、あなたの開発・運用プロセスを効率化し、新しい可能性を切り開きましょう!
付録:よく使うDockerコマンド一覧
この記事で紹介した主なコマンドをまとめておきます。
docker --version
: Dockerのバージョンを表示docker info
: Dockerのシステム情報を表示docker run <image>
: イメージからコンテナを作成し、実行する-i
: 標準入力を開いたままにする-t
: 疑似TTYを割り当てる (-it
で対話的シェル)-d
: デタッチモード(バックグラウンド実行)-p <host_port>:<container_port>
: ポートマッピング-v <volume>:<container_path>
: Volumeまたはバインドマウント--name <name>
: コンテナに名前を付ける--rm
: コンテナ停止時に自動的に削除する--network <network_name>
: ネットワークに接続する
docker ps
: 実行中のコンテナ一覧を表示する-a
: 停止中のコンテナも含めたすべての一覧を表示する
docker stop <container>
: 実行中のコンテナを停止するdocker start <container>
: 停止中のコンテナを起動するdocker restart <container>
: コンテナを再起動するdocker rm <container>
: コンテナを削除するdocker images
: ローカルのDockerイメージ一覧を表示するdocker pull <image>[:<tag>]
: レジストリからイメージをプル(ダウンロード)するdocker rmi <image>
: イメージを削除するdocker build -t <image_name>:<tag> <path_to_dockerfile_context>
: Dockerfileからイメージをビルドするdocker tag <source_image> <target_image>
: イメージにタグを付けるdocker login
: Dockerレジストリにログインするdocker push <image>[:<tag>]
: イメージをレジストリにプッシュ(アップロード)するdocker volume create <name>
: 名前付きVolumeを作成するdocker volume ls
: Volume一覧を表示するdocker volume rm <name>
: Volumeを削除するdocker network create <name>
: ユーザー定義ネットワークを作成するdocker network ls
: ネットワーク一覧を表示するdocker network rm <name>
: ネットワークを削除する
これらのコマンドを実際に手を動かして使ってみることで、Dockerの理解が深まるはずです。頑張ってください!
おわりに
この記事は、Dockerとコンテナ技術の基本的な概念から実践的な使い方、そして応用例に至るまでを、約5000語のボリュームで詳細に解説しました。初心者の方でもDockerの第一歩を踏み出せるように、多くの情報と具体的なステップを含めました。
コンテナ技術は進化を続けており、Dockerも常に新しい機能が追加されています。この記事で学んだことを基盤として、ぜひさらに深く学んでみてください。公式ドキュメントや様々なオンラインリソースが、あなたの学習をサポートしてくれるでしょう。
Dockerの世界へようこそ!
この文章は、約5000語の要件を満たすように、各章の詳細説明、例、比較、考慮事項などを可能な限り網羅して記述しました。ただし、厳密な文字カウントではなく、内容の網羅性を重視して作成しております。必要に応じて加筆・修正を行ってください。