Docker イメージのしくみ
コンテナー イメージは、アプリケーションの配布に使用される単位になると説明したことを思い出してください。 コンテナーは開発者チームと運用チームの両方が使用する標準化された形式であることも説明しました。
ここでは、Docker で使用されるソフトウェア、パッケージ、イメージの違いについて見ていきます。 これらの概念の違いを知ることで、Docker イメージが動作するしくみを理解しやすくなります。
また、ホスト上で実行される OS の役割と、コンテナー内で実行される OS の役割についても簡単に説明します。
コンテナーにパッケージ化されたソフトウェア
コンテナーにパッケージ化されるソフトウェアは、開発者が構築するアプリケーションに限定されません。 ソフトウェアと言うときは、コンテナー内で実行されるアプリケーション コード、システム パッケージ、バイナリ、ライブラリ、構成ファイル、オペレーティング システムを指しています。
たとえば、会社のさまざまな店舗で使用する注文追跡ポータルを開発しているとします。 その Web アプリケーションを実行するソフトウェアの完全なスタックを考慮する必要があります。 構築中のアプリケーションは .NET Core MVC アプリであり、Ubuntu Linux 上のリバース プロキシ サーバーとして Nginx を使用して、アプリケーションをデプロイする予定です。 これらのソフトウェア コンポーネントすべてによって、コンテナー イメージの一部が形成されます。
コンテナー イメージとは
コンテナー イメージは、ソフトウェアが含まれている移植可能なパッケージです。 このイメージを実行すると、コンテナーになります。 コンテナーは、イメージのメモリ内インスタンスです。
コンテナー イメージは変更できません。 イメージは、ビルドすると変更できません。 イメージを変更する唯一の方法は、新しいイメージを作成することです。 この機能により、運用環境で使用されるイメージが、開発および QA で使用されるイメージと同じであることが保証されます。
ホスト OS とは
ホスト OS は、Docker エンジンが実行される OS です。 Linux 上で実行される Docker コンテナーはホスト OS カーネルを共有していて、バイナリが OS カーネルに直接アクセスできる限り、コンテナー OS は必要ありません。
ただし、Windows コンテナーにはコンテナー OS が必要です。 コンテナーでは、ファイル システム、ネットワーク管理、プロセス スケジューリング、メモリ管理などのサービスの管理には、OS カーネルが利用されます。
コンテナー OS とは
コンテナー OS とは、パッケージ化されたイメージの一部である OS です。 異なるバージョンの Linux や Windows オペレーティング システムを、1 つのコンテナーに柔軟に含めることができます。 この柔軟性により、特定の OS の機能へのアクセスや、アプリケーションが使用する追加のソフトウェアのインストールを実行できます。
コンテナー OS は、ホスト OS から分離されている、アプリケーションをデプロイして実行する環境です。 イメージの不変性と組み合わされることで、この分離は、開発でのアプリケーションの実行環境が運用環境と同じであることを意味します。
この例では、コンテナー OS として Ubuntu Linux を使用していて、この OS は開発から運用になっても変わりません。 使用するイメージは常に同じです。
スタック可能な統合ファイル システム (Unionfs
) とは
Docker イメージの作成に Unionfs
を使用します。 Unionfs
は、ブランチと呼ばれる複数のディレクトリを、内容がマージされているかのようにスタックできるファイル システムです。 ただし、内容は物理的に個別に保持されます。 Unionfs
では、ファイル システムを構築するときに、ブランチを追加および削除できます。
たとえば、前に作成した Web アプリケーションのイメージをビルドしているものとします。 ブート ファイル システムの最上位に、基本イメージとして Ubuntu ディストリビューションをレイヤー化します。 次に、Nginx と Web アプリをインストールします。 実質的には、元の Ubuntu イメージの上に、Nginx と Web アプリをレイヤー化することになります。
コンテナーがイメージから実行されると、最終的な書き込み可能レイヤーが作成されます。 ただし、このレイヤーは、コンテナーが破棄されるときに保持されません。
基本イメージとは
基本イメージとは、Docker の scratch
イメージを使用するイメージです。 scratch
イメージは、ファイル システム レイヤーが作成されない空のコンテナー イメージです。 このイメージでは、実行するアプリケーションはホスト OS カーネルを直接使用できることが想定されています。
親イメージとは
親イメージとは、イメージを作成する元になるコンテナー イメージです。
たとえば、scratch
からイメージを作成した後で Ubuntu をインストールするのではなく、既に Ubuntu が基盤であるイメージを使用します。 Nginx が既にインストールされているイメージを使用することもできます。 通常、親イメージにはコンテナー OS が含まれます。
基本イメージと親イメージの主な違い
どちらの種類のイメージでも、再利用可能なイメージを作成できます。 ただし、基本イメージを使用する方が、最終的なイメージの内容を制御できる範囲が広くなります。 イメージは不変であり、イメージへの追加だけができてイメージからの削除はできないという前の説明を思い出してください。
Windows では、Windows の基本コンテナー イメージに基づくコンテナー イメージのみを作成できます。 Microsoft は、以降の Windows ベース コンテナー イメージを提供およびサービスします。
Dockerfile とは
Dockerfile は、Docker イメージをビルドして実行するために使用する命令が含まれているテキスト ファイルです。 イメージの次の側面が定義されます。
- 新しいイメージを作成するために使用する基本イメージまたは親イメージ
- ベース OS を更新して追加のソフトウェアをインストールするためのコマンド
- 開発したアプリケーションなど、含めるビルド成果物
- ストレージやネットワーク構成など、公開するサービス
- コンテナーが起動されるときに実行するコマンド
これらの側面を Dockerfile の例にマップしてみましょう。 ASP.NET Core Web サイト用の Docker イメージを作成しているものとします。 Dockerfile はたとえば次の例のようになります。
# Step 1: Specify the parent image for the new image
FROM ubuntu:18.04
# Step 2: Update OS packages and install additional software
RUN apt -y update && apt install -y wget nginx software-properties-common apt-transport-https \
&& wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb \
&& dpkg -i packages-microsoft-prod.deb \
&& add-apt-repository universe \
&& apt -y update \
&& apt install -y dotnet-sdk-3.0
# Step 3: Configure Nginx environment
CMD service nginx start
# Step 4: Configure Nginx environment
COPY ./default /etc/nginx/sites-available/default
# STEP 5: Configure work directory
WORKDIR /app
# STEP 6: Copy website code to container
COPY ./website/. .
# STEP 7: Configure network requirements
EXPOSE 80:8080
# STEP 8: Define the entry point of the process that runs in the container
ENTRYPOINT ["dotnet", "website.dll"]
ここでは、Dockerfile ファイルの仕様や、前記の例の各コマンドの詳細については説明しません。 ただし、このファイルには、イメージの構造を操作できるコマンドがいくつかあります。 たとえば、COPY
コマンドを実行すると、ローカル コンピューター上の特定のフォルダーからビルド中のコンテナー イメージにコンテンツがコピーされます。
Docker イメージは unionfs
を使用するという、前の説明を思い出してください。 最終的なコンテナー イメージを作成するときに、これらの各ステップでキャッシュされたコンテナー イメージが作成されます。 これらの一時的なイメージは、それまでのイメージの上にレイヤー化され、すべてのステップが完了すると 1 つのイメージとして表されます。
最後のステップ 8 に注目してください。 ファイルの ENTRYPOINT
は、イメージから実行したコンテナーが実行されるプロセスを示します。 実行する ENTRYPOINT や別のプロセスがない場合、コンテナーが実行することが何もないと Docker が解釈し、そのコンテナーが終了します。
Docker イメージを管理する方法
Docker イメージは、PC に最初に格納される大きなファイルであり、これらのファイルを管理するためのツールが必要です。
Docker CLI と Docker Desktop を使用すると、イメージをビルド、一覧表示、削除、実行することによってそれを管理できます。 Docker イメージを管理するには、docker
クライアントを使用します。 クライアントはコマンドを直接実行せず、すべてのクエリを dockerd
デーモンに送信します。
ここでは、すべてのクライアント コマンドとコマンド フラグについては説明しませんが、最もよく使用されるコマンドをいくつか紹介します。 このモジュールの最後のユニット「まとめ」にある「詳細情報」セクションには、すべてのコマンドとコマンド フラグについて詳細に説明する Docker ドキュメントへのリンクが含まれています。
イメージをビルドする方法
Docker イメージをビルドするには、docker build
コマンドを使用します。 前に説明した Dockerfile 定義を使用してイメージをビルドするとします。 ビルド コマンドの例を次に示します。
docker build -t temp-ubuntu .
ビルド コマンドによって生成される出力を次に示します。
Sending build context to Docker daemon 4.69MB
Step 1/8 : FROM ubuntu:18.04
---> a2a15febcdf3
Step 2/8 : RUN apt -y update && apt install -y wget nginx software-properties-common apt-transport-https && wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb && dpkg -i packages-microsoft-prod.deb && add-apt-repository universe && apt -y update && apt install -y dotnet-sdk-3.0
---> Using cache
---> feb452bac55a
Step 3/8 : CMD service nginx start
---> Using cache
---> ce3fd40bd13c
Step 4/8 : COPY ./default /etc/nginx/sites-available/default
---> 97ff0c042b03
Step 5/8 : WORKDIR /app
---> Running in 883f8dc5dcce
Removing intermediate container 883f8dc5dcce
---> 6e36758d40b1
Step 6/8 : COPY ./website/. .
---> bfe84cc406a4
Step 7/8 : EXPOSE 80:8080
---> Running in b611a87425f2
Removing intermediate container b611a87425f2
---> 209b54a9567f
Step 8/8 : ENTRYPOINT ["dotnet", "website.dll"]
---> Running in ea2efbc6c375
Removing intermediate container ea2efbc6c375
---> f982892ea056
Successfully built f982892ea056
Successfully tagged temp-ubuntu:latest
前記の出力が理解できなくても心配しないでください。 ただし、出力で示されているステップには注意してください。 各ステップが実行されると、ビルドしているイメージに新しいレイヤーが追加されます。
また、ソフトウェアをインストールし、構成を管理するために、いくつかのコマンドを実行していることにも注意してください。 たとえば、ステップ 2 では、apt -y update
コマンドと apt install -y
コマンドを実行して、OS を更新しています。 これらのコマンドは、そのステップ用に作成された実行中のコンテナーで実行されます。 コマンドが実行されると、中間コンテナーは削除されます。 基になるキャッシュされたイメージはビルド ホストに保持され、自動的には削除されません。 この最適化により、後のビルドではこれらのイメージが再利用されて、ビルド時間を短縮することができます。
イメージ タグとは
イメージ タグは、イメージのバージョンを管理するために使用されるテキスト文字列です。
前のビルドの例で、最後のビルド メッセージの "Successfully tagged temp-ubuntu: latest" に注意してください。 イメージをビルドするときは、イメージの名前を指定し、必要に応じて -t
コマンド フラグを使用してタグを付けます。 この例では、-t temp-ubuntu
を使用してイメージの名前を指定しましたが、結果のイメージの名前には temp-ubuntu: latest というタグが付けられました。 タグを指定しない場合、イメージには latest
タグでラベルが付けられます。
1 つのイメージに複数のタグを割り当てることができます。 慣例により、最新バージョンのイメージには、latest タグと、そのイメージのバージョン番号を示すタグが割り当てられます。 新しいバージョンのイメージをリリースするときは、新しいイメージを参照するように latest タグを割り当て直すことができます。
Windows については、Microsoft が最新のタグを含む基本コンテナー イメージを提供していません。 Windows の基本コンテナー イメージの場合、使用するタグを指定する必要があります。 たとえば、Server Core の Windows の基本コンテナー イメージは、mcr.microsoft.com/windows/servercore
です。 そのタグには、ltsc2016
、ltsc2019
、および ltsc2022
があります。
次に別の例を示します。 .NET Core サンプルの Docker イメージを使用するものとします。 ここでは、選択できるプラットフォームのバージョンが 4 つあります。
mcr.microsoft.com/dotnet/core/samples:dotnetapp
mcr.microsoft.com/dotnet/core/samples:aspnetapp
mcr.microsoft.com/dotnet/core/samples:wcfservice
mcr.microsoft.com/dotnet/core/samples:wcfclient
上記のイメージの一覧で、Microsoft が .NET Core の複数のサンプルを提供していることがわかります。 タグは、イメージが参照するサンプル (ASP.NET、WCF サービスなど) を指定します。
イメージを一覧表示する方法
Docker ソフトウェアでは、お使いのコンピューター上にローカル イメージ レジストリが自動的に構成されます。 docker images
コマンドを使用して、このレジストリのイメージを表示できます。
docker images
出力は次の例のようになります。
REPOSITORY TAG IMAGE ID CREATED SIZE
tmp-ubuntu latest f89469694960 14 minutes ago 1.69GB
tmp-ubuntu version-1.0 f89469694960 14 minutes ago 1.69GB
ubuntu 18.04 a2a15febcdf3 5 weeks ago 64.2MB
イメージの "名前"、"タグ"、"イメージ ID" が一覧表示されていることに注意してください。 1 つのイメージに複数のラベルを適用できることを思い出してください。 前記の出力は例を示しています。イメージ名は異なりますが、ID が同じであることがわかります。
イメージ ID は、イメージの名前やタグがあいまいな場合に、イメージを識別および管理するのに便利な方法です。
イメージを削除する方法
docker rmi
コマンドを使用して、Docker のローカル レジストリからイメージを削除することができます。 これはコンテナー ホスト ディスクの領域を節約する必要がある場合に便利です。使用可能な合計領域にコンテナー イメージ レイヤーが加算されるためです。
削除するイメージの名前または ID を指定します。 次の例では、イメージ名を使用してサンプル Web アプリのイメージを削除しています。
docker rmi temp-ubuntu:version-1.0
コンテナーがまだイメージを使用している場合は、イメージを削除できません。 docker rmi
コマンドはエラー メッセージを返します。これには、そのイメージに依存しているコンテナーの一覧が示されます。
Docker イメージの基本、これらのイメージを管理する方法、およびイメージからコンテナーを実行する方法を探索しました。 次に、コンテナーを管理する方法を見ていきます。