これまで Dockerを使ったことがないと、Docker の用語はどれも意味がわかりづらいかもしれません。人によって Docker 用語が違うものを指しているような場合や、異なる用語が同じ意味で使われているような場合もあります。
Docker を学び始めたばかりだと、たとえば、Docker イメージと Docker コンテナの違いがわからないこともあるでしょう。その違いはつかみづらいですが、とても重要です。
そこで、この記事では、Docker のイメージとコンテナをそれぞれいつ、どのように使うのかがわかるよう、これらの違いについて説明します。
Docker の概要
Docker、Flatpak、Snaps などのソリューションはどれも目的は同じです。それは、アプリを、Linux ディストリビューションにインストールできる単一のバンドルにパッケージ化することです。
Docker は、2013 年に Solomon Hykes 氏がオープンソースプロジェクトとして発表したものです。2014 年に本番環境向けの最初の商用版が登場しました。
Docker は、コンテナ化プラットフォームです。アプリケーションを簡単に作成、デプロイ、実行できるようにするために、コンテナを使います。このコンテナは輸送コンテナのようなものですが、ソフトウェアのためのコンテナです。アプリケーションを生産者から消費者に効率的に配布できるよう、ファイルやプログラムなどの重要なコンテンツを保持します。
コンテナ化の主なメリットの 1 つは、Linux ディストリビューションでの実行に必要なすべての依存関係と一緒にアプリをパッケージ化できることです。そのため、依存関係を一つひとつ手動でインストールする必要がなくなります。
コンテナは複数同時に実行でき、それぞれのベースになるイメージは同じものでも別々のものでもかまいません。オペレーティングシステムのインスタンスを複数作成する点は、Docker も仮想マシンも同じです。ただし、Docker では、同じオペレーティングシステム上で稼働するコンテナを作成できます。そのため、同じハードウェア構成であれば、コンテナの方が仮想マシンよりも運用できる数が多くなります。
Docker コンテナは、仮想マシン内でも稼働できます。Docker では仮想マシンを作成するのではなく、抽象化と自動化のレイヤーを追加するため、使い勝手が優れています。
このコンテナ化プラットフォームは、開発者やシステム管理者の間で人気が高まっています。その理由は、アプリケーションのファイルシステム全体とそのすべての依存関係をパッケージ化できるからです。これにより、変わることのないインフラを実現でき、デプロイの一貫性が保証されます。何度デプロイ操作を繰り返しても、デプロイの結果はまったく変わりません。
イメージやコンテナなどは、バックグランドで実行される Docker デーモンが管理します。クライアントとデーモンとの通信は、ソケットまたは RESTful API を介して行われます。
Docker イメージとは?
イメージは、コンテナを作成するための指示が記載された読み取り専用のテンプレートです。Docker イメージは、Docker プラットフォーム上で稼働するコンテナを作成します。
イメージは、稼働中のコンテナの中身を記録したブループリントやスナップショットのようなものです。
イメージは、フォトエディターのレイヤーのように、複数の積み重なったレイヤーで構成されており、それぞれのレイヤーが環境に変更を加えます。イメージには、アプリケーションを実行するために必要なコードやバイナリ、ランタイム、依存関係、およびその他のファイルシステムオブジェクトを格納します。イメージはホストオペレーティングシステム (OS) のカーネルに依存します。
たとえば、Web サーバーのイメージをビルドする場合は、まずイメージに Ubuntu Linux (ベース OS) を含めます。次に、その上に Apache や PHP などのパッケージを追加します。
イメージは Dockerfile を使って手動でビルドできます。Dockerfile は、Docker イメージを作成するためのコマンドがすべて含まれているテキストドキュメントです。レジストリと呼ばれる一元的なリポジトリから、または docker pull [name]
コマンドを使用して Docker Hub などのリポジトリから、イメージをプルすることもできます。
Docker ユーザーがイメージを実行すると、イメージが 1 つまたは複数のコンテナインスタンスになります。コンテナの初期状態は、インストールと構成が済んでいるサーバーにしたり、bash シェルが root として実行されているだけにしたりと、開発者が自由に決められます。しかし、実際のところは、イメージには事前設定された何らかのソフトウェアと設定ファイルが含まれていることがほとんどです。
Docker イメージは変更不可能です。そのため、作成後に変更することはできません。変更が必要な場合は、変更を加えたコンテナを別途作成し、別のイメージとして保存します。または、既存のイメージをベースとして使用して新しいコンテナを稼働させ、そのコンテナに変更を加えます。
アプリケーションが正常にビルドされたら、Docker からイメージを別のイメージにエクスポートできます。一般に、派生元のイメージは親イメージ、そこから派生したイメージは子イメージと呼ばれます。
1 つのイメージに複数のタグを付けられますが、各タグは一意です。タグはイメージを識別するためのもので、たとえば ubuntu:latest や ubuntu:14.04 のようになります。
Docker イメージ自体が稼働するわけではありませんが、イメージからコンテナを作成して稼働させることができます。
コンテナとは?
コンテナは、アプリケーションを実行する分離された環境です。システムの他の部分が影響を受けることも、システムがアプリケーションに影響を与えることもありません。分離されているため、機密性の高いリソースにアクセスする必要があるデータベースや Web アプリケーションなどのソフトウェアを、アクセス可能なシステム上のユーザーを限定しながらセキュアに実行するのに最適です。
コンテナは Linux でネイティブに稼働し、ホストマシンのカーネルを共有するため、軽量で、他の実行可能ファイルに比べメモリを使用しません。コンテナが停止後に自動的に再起動することはありません。ただし、再起動するよう設定している場合は除きます。それでも、オペレーティングシステム全体のオーバーヘッドが発生しないため、仮想マシンよりもはるかに効率的と言えます。コンテナは単一のカーネルを他のコンテナと共有し、数分どころか数秒で起動します。
コンテナを使用して、アプリケーションとそれに必要なすべてのコンポーネントをパッケージ化すると、すべてをまとめた 1 つのコンテナとしてリリースできます。このアプローチは広く使われています。その理由として、開発環境、QA 環境、本番環境間の移行がスムーズになり、ソフトウェアをリリースするまでの期間を短縮できることが挙げられます。ソフトウェアコンテナ内でアプリケーションをビルドしてデプロイするため、他の開発者と共同でコードを開発している場合に起こる “自分のマシンでは動く” という問題がなくなります。
アプリケーションは、どのインフラでも、どのクラウドでも、実行できます。アプリケーションとその基盤となるインフラを他のアプリケーションから分離することができるのです。
Docker のコンテナとイメージの違い
Docker イメージにより、Docker コンテナ内でコードが実行されます。稼働させるコンテナを作成するには、コア機能入りの書き込み可能なレイヤーを Docker イメージに追加します。
Docker コンテナは、稼働させるイメージのインスタンスのようなものです。同じイメージから複数のコンテナを作成し、それぞれのデータや状態を個別に変えることができます。
他にもコンテナの作成方法はありますが、イメージがよく使われています。
コンテナを導入すると、開発、運用、テストが標準化、簡素化されるという大きなメリットがあります。ただし、チームでコンテナをフル活用するには、開発者、運用エンジニア、テスト担当者が一貫性のある環境を作成するよう徹底する必要があります。
継続的インテグレーション & 継続的デプロイメント (CI/CD) パイプラインを導入すれば、コンテナをビルド、テスト、パッケージ化できます。その後、デプロイして、そのコンテナをアプリケーションの一環として実行できるランタイム環境にそのコンテナを配布します。
CircleCI などの継続的インテグレーションソリューションを使用すれば、こうしたビルド、テスト、デプロイのプロセスを自動化できます。CircleCI で Docker コンテナを使用すると、アプリケーションを複数の環境に簡単にデプロイできるようになります。
CircleCI では、たとえば、Docker イメージをビルドしてコンテナイメージレジストリ (Docker Hub など) にプッシュできます。そこから、Kubernetes や OpenShift などでそのイメージをコンテナにインスタンス化できます。
このフローをまとめると、次のようになります。
- 変更を Git リポジトリにコミットする
- コミットにより CircleCI のビルドジョブがトリガーされて、Git からソースコードがチェックアウトされ、コードに対して単体テストが実行される
- 単体テストに合格した場合は、CircleCI によりビルドイメージが Docker Hub にプッシュされる
- 単体テストに失敗した場合は、CircleCI から開発者に通知が届き、ワークフローが停止する
Docker レイヤーキャッシュやテスト分割などの機能も、イメージのビルドやテストを高速化し、デプロイまでの時間を短縮するのに役立ちます。継続的インテグレーションプラットフォームを使用して、Docker のビルド、テスト、デプロイを自動制御するメリットは他にもありますので、「Docker を使用した CI/CD パイプラインのビルド方法」で詳細をご覧ください。
おわりに
Docker のイメージとコンテナは、目的は似ていますが、用途が異なります。イメージは環境のスナップショットで、コンテナはソフトウェアを実行する環境です。
コンテナとイメージはどちらも、ユーザーがアプリケーションの依存関係と設定を指定し、マシンがそのアプリケーションを実行するために必要な事項をすべて記述できます。ただし、コンテナとイメージはライフサイクルが異なります。たとえば、Pivotal Cloud Foundry などのコンテナベースのシステムでは、コンテナは使用できますが、イメージは使用できません。一方、Heroku や OpenShift などの非コンテナシステムでは、イメージは使用できますが、コンテナは使用できません。
これは、コンテナとイメージのどちらかを選ばなければならないということではありません。コンテナとイメージは相互に依存しているため、Docker を利用する場合は両方が必要です。
ここまでお読みいただいたみなさんは、Docker のイメージとコンテナの違いを理解し、Docker プラットフォームをフル活用する準備が整ったことでしょう。Docker に自動化を組み合わせれば、インテグレーションを迅速化し、開発者がアプリケーションの新しい機能の開発に時間を割けるようにすることができます。ぜひ、こちらで、CircleCI で Docker と Kubernetes を連携させてソフトウェア開発プロセスの効率を向上させる方法についてもご確認ください。