簡単な更新作業でDockerイメージとレイヤー管理を理解する方法

Docker公式ロゴ1b
©2023 Docker Inc. All rights reserved

 Dockerの仮想環境であるDockerコンテナは、Dockerイメージを指定して起動します。

 DockerにとってDockerイメージはとても重要で、選択次第では構築するシステムにかなりの影響をもたらすものだと私は考えます。

 ですので、Dockerイメージに関する基礎的な部分はキチンと理解していたほうが後々役立つでしょう。

 本記事では、既存のDockerイメージを入手して、そのDockerイメージを更新した後に、最初に入手したDockerイメージと中身を比較する作業について解説しています。

 これによって、Dockerイメージとはどのようなものかご理解いただけると思います。

 Dockerイメージをもう少し詳しくご理解いただくきっかけになれば幸いです。

Dockerイメージとは

 Dockerイメージは、Dockerコンテナの雛形となるファイル群です。Dockerイメージの中には、仮想環境の初期状態のディスクイメージが格納されてます。

 Dockerの仮想環境であるDockerコンテナは、このDockerイメージを使用して起動します。

 Dockerコンテナ内に存在するDockerイメージ部分はReadOnly(読み込み専用)となってまして、更新することはできません。

 でも実際は、Dockerイメージ内のファイルは更新できるように見えます。

 これに関しましては後ほど解説します。

 それでは、このDockerイメージについて、もう少し詳細に見ていきましょう。

読み込み専用で複数レイヤ構成のDockerイメージ

 Dockerイメージは、Dockerコンテナが使用するディスクに相当するものなのですが、実は読み取り専用(リードオンリー)です。

 更に、Dockerイメージは、イメージレイヤと呼ばれる、これまた読み取り専用のディスクイメージを複数積み重ねて作られてます。

 以下は、Ubuntuバージョン16.04のDockerイメージを入手した際の出力内容です。

$ docker pull ubuntu:16.04
Using default tag: latest
16.04: Pulling from library/ubuntu
952132ac251a: Pull complete
82659f8f1b76: Pull complete
c19118ca682d: Pull complete
8296858250fe: Pull complete
24e0251a0e2c: Pull complete
Digest: sha256:f4691c96e6bbaa99d99ebafd9af1b68ace2aa2128ae95a60369c506dd6e6f6ab
Status: Downloaded newer image for ubuntu:16.04

 出力内容に、952132ac251a、82659f8f1b76、c19118ca682d、8296858250fe、24e0251a0e2cの文字列がありますが、この1つ1つがイメージレイヤになります。

 この複数のイメージレイヤを1つに合わせて、Ubuntuバージョン16.04のDockerイメージ「ubuntu:16.04」として利用します。

Dockerイメージの作成履歴をDockerコマンドで見る方法

 あるDockerイメージをベースイメージとして新たなDockerイメージを作成した場合は、ベースとして利用したDockerイメージのレイヤに新たなイメージレイヤが追加されます。

 Dockerコマンドに「docker history」があります。これはDockerイメージの作成履歴を出力するためのコマンドです。

 このコマンドを使用して、実際にDockerイメージのイメージレイヤを覗いてみたいと思います。

Ubuntuの公式Dockerイメージを入手する

 UbuntuのDockerイメージを使用して確認してみます。

 まずは、公式のUbuntuのDockerイメージを入手してみましょう。

$ docker pull ubuntu:16.04

 バージョン16.04を入手してみました。

 早速「docker history」コマンドで確認してみます。

$ docker history ubuntu:16.04

以下のように出力されたと思います。

IMAGE         CREATED      CREATED BY                          SIZE COMMENT
bd3d4369aebc  4 days ago   /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B
<missing>     4 days ago   /bin/sh -c mkdir -p /run/systemd && echo 'doc 7 B
<missing>     4 days ago   /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/ 1.895 kB
<missing>     4 days ago   /bin/sh -c rm -rf /var/lib/apt/lists/* 0 B
<missing>     4 days ago   /bin/sh -c set -xe && echo '#!/bin/sh' > /u 745 B
<missing>     4 days ago   /bin/sh -c #(nop) ADD file:902bff94e00fb3d9eb 126.6 MB

 一番左はイメージレイヤのIDになります。

 「<missing>」となっている部分は、イメージIDが表示されていません。これはDockerの仕様によるものです。

 以前(Docker ver1.10未満)は全ての情報が出力されていたのですが、バージョン1.10からDockerのストレージに関する仕様が変更になり、表示されない箇所も出てくるようになりました。

 上の出力内容を見ますと、6層分のイメージレイヤがあることが解ります。

 これを踏まえて、今入手したUbuntuのDockerイメージにイメージレイヤを追加してみたいと思います。

入手したDockerイメージを更新する

 任意の空のディレクトリを作成し、そのディレクトリ内に、以下の内容のDockerfileを作成します。

FROM ubuntu:16.04

RUN echo "Hello world" > /usr/helloworld.txt

 2行目の「RUN」は、使用するDockerイメージ(今回はUbuntuバージョン16.04)に対して、「"Hello world" > /usr/helloworld.txt」を実行する命令になります。

 この命令によって、Dockerイメージ内に「/usr/helloworld.txt」が作成され、Dockerイメージ「ubuntu:16.04」が更新されることになります。

 次に、Dockerfileを作成したディレクトリをカレントディレクトリとして、以下のDockerコマンドを実行します。

$ docker build --rm -t testimages .

 以下のような内容が出力されます。

Sending build context to Docker daemon 2.048 kB
Step 1 : FROM ubuntu:16.04
 ---> bd3d4369aebc
Step 2 : RUN echo "Hello world" > /usr/helloworld.txt
 ---> Running in 10196cb4b7fb
 ---> 6d71c7c98d2d
Removing intermediate container 10196cb4b7fb
Successfully built 6d71c7c98d2d

 上の内容を簡単に説明します。

 まずStep1でベースイメージとなる「ubuntu:16.04」が表示されてます。

 このDockerイメージがローカルに存在しない場合は、DockerHUBから入手する処理が行われます。既に入手済みの場合は行われません。

 Step1の次の行に「---> bd3d4369aebc」が出力されてます。

 ここで、「docker images」コマンドを実行してください。

$ docker images
REPOSITORY      TAG       IMAGE ID         CREATED       SIZE
ubuntu          16.04     bd3d4369aebc     4 days ago    126.6 MB

 ubuntuバージョン16.04のイメージIDは「bd3d4369aebc」です。step1で表示されたイメージレイヤのIDと同じ文字列になっています。

 これによって、この作業に使用したDockerイメージは、先ほど入手したUbuntuのDockerイメージであることがわかります。

 次にstep2として、Dockerfileに記載した「RUN」命令が出力されてます。

 これによって、ベースイメージ内に/usr/helloworld.txtファイルが作成されまして、新しいID「6d71c7c98d2d」が付与されていることがわかります。

 つまり、ベースイメージの上に新しいイメージレイヤーが作成されたことになるのです。

 最後に「Successfully built 6d71c7c98d2d」と出力されてますが、「RUN」命令で付与されたIDと同じですね。

 最終的に付与されたイメージIDが、作成したDockerイメージのイメージIDになります。

新しく作成したDockerイメージの内容を確認する

 では、作成した新しいDockerイメージを確認してみたいと思います。

 まずは、「docker images」コマンドです。

$ docker images
REPOSITORY     TAG      IMAGE ID        CREATED           SIZE
testimages     latest   6d71c7c98d2d    16 minutes ago    126.6 MB
ubuntu         16.04    bd3d4369aebc    4 days ago        126.6 MB

 「docker build」コマンドで指定した「testimages」が作成されていることが確認できます。

 次に「docker history」コマンドで「testimages」を確認してみましょう。

$ docker history testimages
IMAGE        CREATED        CREATED BY                    SIZE COMMENT
6d71c7c98d2d 21 minutes ago /bin/sh -c echo "Hello world" > /usr/hellowor 12 B
bd3d4369aebc 4 days ago     /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B
<missing>    4 days ago     /bin/sh -c mkdir -p /run/systemd && echo 'doc 7 B
<missing>    4 days ago     /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/ 1.895 kB
<missing>    4 days ago     /bin/sh -c rm -rf /var/lib/apt/lists/* 0 B
<missing>    4 days ago     /bin/sh -c set -xe && echo '#!/bin/sh' > /u 745 B
<missing>    4 days ago     /bin/sh -c #(nop) ADD file:902bff94e00fb3d9eb 126.6 MB

 一番上の行のイメージレイヤIDは「6d71c7c98d2d」と出力されてます。

 先ほど「docker build」を行った際の出力内容を再度確認してください。step2で出力されたIDと同じであることが確認できますね。

 また、「RUN」命令で指定した内容も出力されていることも確認できます。

 更に、上記出力内容の「6d71c7c98d2d」の次の行から下の内容と、前に確認したUbuntuのDockerイメージの「docker history」の出力内容を確認してみてください。

 全く同じですね。

 このことから、最初に入手したUbuntuのDockerイメージに、Dockerfileを使用して更新した新しいイメージレイヤが追加されて、新しいDockerイメージが作成されていることがわかると思います。

 このように、Dockerイメージは、更新したい内容のイメージレイヤを積み重ねて新しいDockerイメージを作成していくことになります。

おわりに

 本記事では以下のことを実際に行っていただきました。

  • ベースとなるDockerイメージを入手する
  • Dockerイメージを更新する
  • 更新したDockerイメージの内容を確認する

 シンプルな例でしたが、Dockerイメージとはどんなものか、イメージレイヤーとはどのようなものかについて、感じをつかんでいただけたのではないかと思います。

 本記事の内容がおわかりですと、あなたが実際にDockerイメージを作成するときに、よりサイズが小さくて、より効率的なものを作る工夫ができるようになるでしょう。

 最後までお読みいただきありがとうございました。

コメント