【 docker入門 】 dockerイメージ の概要と Dockerfile の書き方を解説

2022年2月19日コンテナ

コンテナ基礎 Dockerfileからイメージの作り方

docker入門 第二弾です。

第一弾では、docker hub で公開されているdockerイメージを使ってコンテナを作成する方法を解説しました。

今回は、自分で作成したdockerイメージからコンテナを起動してみましょう!というのを目標に解説していきます。

dockerイメージ の概要

docker が作成するコンテナの元となるものです。

実態は、UnionFileSystemと言う特殊なファイルシステムになっていて必要な情報が層になって保存されています。

この層をレイヤーと言いdockerはdocker hubからコンテナを起動するために必要なレイヤーを取得し、Dockerイメージとして保存します。

レイヤーは全てReadOnlyとなっておりDockerイメージの中身を書き換えることはできません。

自分でDockerイメージを構築する場合は、そのDockerイメージでコンテナを起動し、コンテナレイヤーと言われるRead/Write可能なレイヤーを作ります。

そこでの変更をDockerイメージとして保存することでDockerイメージにレイヤーを追加できます。

docker入門 イメージの図

色々書きましたが、最初のうちは、

dockerイメージとは

  • コンテナを作る元
  • 読み取り専用の層になっている特殊なファイルシステム
  • 変更するときは、新しい層を上に積む

というようなイメージでOKかと思います。

Dockefile から dockerイメージ を 作成する

Dockerfile とは、先程の画像でいうところのコンテナレイヤー(変更可能なレイヤー)でどんな変更を行うのかを定義するファイルです。

以前の、「dockerでコンテナを作ってアクセスする手順とコマンドのまとめ」でも少し触れた、dockerデーモンがDockerfileを参照して新しいdockerイメージを作成します。

今回は、docker社の提供するwhalesayというdockerイメージををベースイメージとしてその上にfortuneという格言を表示するコマンドをインストールします。

DockerHubから取得したwhalesayイメージをそのまま使うと以下の感じ
cowsayのあとに 入力した文字をクジラのアスキーアートが喋ってくれます。
これにfortunesをインストールして自動で格言を喋ってもらう様にします。

まずは、docher hubからベースイメージとなるwhalesayを取得してそのまま実行してみます。

結果は以下の通り

$ docker run --rm docker/whalesay cowsay hello
Unable to find image 'docker/whalesay:latest' locally
latest: Pulling from docker/whalesay
Image docker.io/docker/whalesay:latest uses outdated schema1 manifest format. Please upgrade to a schema2 image for better future compatibility. More information at https://docs.docker.com/registry/spec/deprecated-schema-v1/
e190868d63f8: Already exists
909cd34c6fd7: Already exists
0b9bfabab7c1: Already exists
a3ed95caeb02: Pull complete
00bf65475aba: Pull complete
c57b6bcc83e3: Pull complete
8978f6879e2f: Pull complete
8eed3712d2cf: Pull complete
Digest: sha256:178598e51a26abbc958b8a2e48825c90bc22e641de3d31e18aaf55f3258ba93b
Status: Downloaded newer image for docker/whalesay:latest
 _______
< hello >
 -------
    \
     \
      \
                    ##        .
              ## ## ##       ==
           ## ## ## ##      ===
       /""""""""""""""""___/ ===
  ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
       \______ o          __/
        \    \        __/
          \____\______/

以前の記事でもご紹介した$ docker run コマンドによってdocker hub からイメージを取得して実行しています。

後ろについている、cowsay helloは実行されたコンテナのプロセスID(PID)1として実行されるコマンドを引数として渡しています。

今回の場合、cowsayというコマンドがPID1で実行され、そのコマンドにhelloという引数を渡しています。

出力結果の、鯨のアスキーアート(AA)部分は、cawsayの出力結果で、helloは引数の部分になります。

Dockerfileの作成

先に今回使うDockerfileをご紹介します。

FROM docker/whalesay:latest
RUN apt-get -y update && apt-get install -y fortunes 
CMD /usr/games/fortune | cowsay

行頭のFROMRUNなど大文字で記述されたところが命令としてdockerデーモンが認識する語句になっています。

それぞれ以下のような意味になっています。

FROM

Dockerイメージのベースイメージを指定します。

この例では、whalesayイメージのlatestタグがついているベースイメージを指定しています。

RUN

冒頭の図にある、コンテナレイヤーで実行するコマンド、即ちイメージの変更内容を記述します。

今回は、apt-getコマンドを使ってfortunesというパッケージをインストールし、fortuneコマンドを使えるようにしています。

ここの内容が、コンテナレイヤーに書き込まれます。

CMD

コンテナが起動された時に実行するコマンドを指定していする命令です。

今回は、cowsayコマンドにfortuneコマンドの結果を引数として渡してあげています。

ベースイメージのDockerfileを覗いてみる

理解を深めるため、ベースイメージとなっているwhalesayイメージのDockerfileも覗いてみましょう。

docker hubの配布ページから見ることができます。

FROM ubuntu:14.04

# install cowsay, and move the "default.cow" out of the way so we can overwrite it with "docker.cow"
RUN apt-get update && apt-get install -y cowsay --no-install-recommends && rm -rf /var/lib/apt/lists/* \
    && mv /usr/share/cowsay/cows/default.cow /usr/share/cowsay/cows/orig-default.cow

# "cowsay" installs to /usr/games
ENV PATH $PATH:/usr/games

COPY docker.cow /usr/share/cowsay/cows/
RUN ln -sv /usr/share/cowsay/cows/docker.cow /usr/share/cowsay/cows/default.cow

CMD ["cowsay"]

whalesayイメージのベースイメージはubuntuということが分かります。

先程、自前で作ったDockerfileではRUN命令のところで、apt-getコマンドを実行しているのを見て、「おや?」と思って方もいるかと思いますが、ベースイメージのベースイメージがubuntuだったから使えていたということになります。

このことからも、dockerイメージが層になっているという想像がしやすいかと思います。

また、自作のDockerfileでは出てこなかったENV命令環境変数を設定していたり、COPY命令ローカルからイメージ内にファイルをコピーしていたりします。

この辺りのコマンドは、記事の最後にまとめています。

コピーしているファイルは、鯨のAA部分になります。本来cowsayコマンドは以下のように牛のAAがしゃべるコマンドなのですが、ファイルを読み込ませることで別のAAを表示することができます。

$ cowsay hello                                                                                                                                                                                                                            2451ms  土  2/12 23:21:48 2022
 _______
< hello >
 -------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

Dockerfileからdockerイメージを作成(ビルド)

Dockerfileの準備ができたら$ docker buildコマンドでイメージを作成していきます。

 $ docker build -t my-whale .

-tオプションを付けることで作成するイメージにタグをつけることができます。

最後の「.」はビルドコンテキストというものになります。

難しそうな名前ですが、意味はシンプルで参照するDockerfileがどこにあるかを指定するものになります。

まあ、Dockerfileのパスの指定ですね。

実行結果

docker build -t my-whale .                                                                                                                                                                                                       1.7m  土  2/12 23:00:15 2022
[+] Building 32.8s (6/6) FINISHED
 => [internal] load build definition from Dockerfile                                                                                                                                                                                                                       0.1s
 => => transferring dockerfile: 162B                                                                                                                                                                                                                                       0.0s
 => [internal] load .dockerignore                                                                                                                                                                                                                                          0.0s
 => => transferring context: 2B                                                                                                                                                                                                                                            0.0s
 => [internal] load metadata for docker.io/docker/whalesay:latest                                                                                                                                                                                                          0.0s
 => [1/2] FROM docker.io/docker/whalesay:latest                                                                                                                                                                                                                            0.3s
 => [2/2] RUN apt-get -y update && apt-get install -y fortunes                                                                                                                                                                                                            31.5s
 => exporting to image                                                                                                                                                                                                                                                     0.8s
 => => exporting layers                                                                                                                                                                                                                                                    0.7s
 => => writing image sha256:cd3fcaba765d5a5c8f011053d4a25318b6cf74df1c1a4e34ea9add31b8708203                                                                                                                                                                               0.0s
 => => naming to docker.io/library/my-whale                                                                                                                                                                                                                                0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

長めの出力が返ってきますが分解してみていきます。

dockerデーモンへの転送

$ docker buildコマンドを実行すると コマンドの裏で一 生懸命働いているdockerデーモンにDockerfileの情報を転送します。

出力の冒頭部分ですね。

$ docker build -t my-whale .     
=> [internal] load build definition from Dockerfile                                                                                                                                                                                                                       0.1s
 => => transferring dockerfile: 162B                                                                                                                                                                                                                                       0.0s
 => [internal] load .dockerignore                                                                                                                                                                                                                                          0.0s
 => => transferring context: 2B                               

FROM命令の処理

Dockerfileの転送が終わると、ファイル内の処理が始まります。

最初はFROM命令の処理をしてベースイメージを取得します。

 => [1/2] FROM docker.io/docker/whalesay:latest         

ここでFROMに指定したdocker/whalesayのイメージを取得していることがわかります。

今回は、冒頭のお試し実行でdocker/whalesay:latestのイメージを取得していますのですぐ完了します。

ここで、イメージがローカルPCに存在しない場合は例のごとくdocker hubから取得してきます。

RUN命令の実行

RUN命令の処理は、以下の箇所です。

 => [2/2] RUN apt-get -y update && apt-get install -y fortunes                                                                                                                                                                                                            31.5s
 => exporting to image                                                                                                                                                                                                                                                     0.8s
 => => exporting layers                                                                                                                                                                                                                                                    0.7s
 => => writing image sha256:cd3fcaba765d5a5c8f011053d4a25318b6cf74df1c1a4e34ea9add31b8708203                                                                                                                                                                               0.0s
 => => naming to docker.io/library/my-whale

この時、ベースイメージが一時コンテナとして起動しておりその中でRUN命令に記載されている処理が実行されます。

ベースイメージでRUN命令が実行されたものを新しいdockerイメージとして出力されているというわけです。

作成したイメージの確認

作成したイメージは、$ docker images コマンドで確認できます。

$ docker images                                                                                                                                                                                                                   35.1s  日  2/13 10:16:15 2022
REPOSITORY   TAG    IMAGE ID       CREATED        SIZE
my-whale    latest  cd3fcaba765d   11 hours ago   278MB

これでイメージの作成は完了です!

ここまでのdockerイメージの構成

今回のDockerfileを使ってDockerイメージを作成するとベースイメージを含めDockerイメージの構成は以下の様になっています。

docker入門 イメージビルド時の概要

作成したイメージからコンテナを作成

dockerイメージができたらあとは実行するだけです。

コマンドは過去の記事でご紹介していますので詳しいご紹介は省略します。

$ docker run --rm --name whale my-whale                                                                                                                                                                                         808ms  日  2/13 10:29:23 2022
 ________________________________________
/ The only winner in the War of 1812 was \
| Tchaikovsky.                           |
|                                        |
\ -- David Gerrold                       /
 ----------------------------------------
    \
     \
      \
                    ##        .
              ## ## ##       ==
           ## ## ## ##      ===
       /""""""""""""""""___/ ===
  ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
       \______ o          __/
        \    \        __/
          \____\______/

無事動きましたね〜

Dockerfileの命令

今回の例では、Dockerfile内で、FROM/RUN/CMD命令のみを利用しました。

実際は他にも命令がありまるのでまとめておきます。

FROMベースイメージを指定します。
RUNコマンドを実行して、コンテナレイヤーに新しいパッケージなどを追加します。
CMDコンテナにデフォルトのコマンドと引数を設定できます。コマンドは省略して引数だけを指定することもできますが、その場合後述のENTORYPOINTもでコマンドを指定する必要があります。
CMDで指定された値は、引数によって上書きすることができます。
LAVELkey-valueの形式でdockerイメージに情報を付与することができます。
docker inspect コマンドでイメージの情報を表示した際に見ることができます。
EXPOSEポートの設定ができます。
ここに記載されてポートが、コンテナでListenされます。
ENVコンテナの環境変数を設定できます。
ADDローカル側のファイルをコンテナにコピーします。
対象がtarファイルなどの圧縮された形式の場合、展開してものをコピーします。
また、対象がローカル側にない場合、コンテナ側にはディレクトリだけ作られます。
COPYローカル側のファイルをコンテナにコピーします。
ADD命令と同じですが余計なものまでコピーしてしまう可能性があるため、COPY命令の方が推奨されているようです。
ENTRYPOINTコンテナにデフォルトのコマンドと引数を設定できます。
CMDとは違い引数で上書きすることができません。
上書きするには、--entrypointオプションを付けてコンテナを実行する必要があります。
VOLUMEローカル側のボリュームにマウントするための命令です。
コンテナが削除されても、ローカル側に保存されたファイルは残り続けます。
USERRUN/CMD/ENTRYPOINT命令を実行するユーザを指定します。
WORKDIRRUN/CMD/ENTRYPOINT命令を実行する際のカレントディレクトリを指定します。
ARGDockerefile内で扱う変数名を定義します。
例えば、ARG hogeと記述するこで $docker build ./ --build-arg hoge=helloのように、ビルド時に変数に値を渡すことができます。
ONBUILDこの命令が記述されたDockerfileをビルドした時は、特に何も起こりません。
ビルドしたイメージをベースイメージとして別のイメージを作成した時にONBUILD命令に記述されたコマンドが実行されます。
STOPSIGNALコンテナを停止するためのシグナルを指定します。
HEALTHCHECKコンテナの正常確認を実行できます。
例えば、
数秒ごとに特定のURLにcurlを実行して200が返って来れば正常。数回連続で200以外なら異常のように設定することができる。
SHELLこの命令を使うと、RUN命令で実行されるコマンドがshellで実行されるようになります。

参考リンク

コンテナ

Posted by kotaro