Lesson 4
オリジナルのイメージを作成する
目次
Lesson 4
Chapter 1
Dockerfileの作成
これまでのLessonにより、イメージの取得からコンテナの作成・実行までを行うことができるようになりました。
しかし、コンテナの実行(docker run、docker start
)により何を行うか?ということが指定できませんでした。
docker run hello-world
はHello from Docker!を出力しますが、それはそのようにイメージが作られているからなのです。
オリジナルのイメージを作成するには
自分でオリジナルのイメージを作成するには、Dockerfileという設定ファイルを用意します。
そして、Dockerfileに記述した内容を元にイメージを作成することができます。
Lesson4ではDockerfileを作成し、dockerコマンドにより(1)オリジナルのイメージを作成、(2)コンテナを実行する流れを学習します。
Lesson4で学習する内容
Dockerfileの例
以下に、Dockerfileの簡単な一例を示します。
Dockerfile
FROM ubuntu
RUN apt update
RUN apt install -y vim
ENV DIRPATH=/home
WORKDIR $DIRPATH
COPY myfile.txt .
CMD cat myfile.txt
このように、Dockerfileはいくつかの命令と引数のセットの組み合わせによって構成されており、一行につき一命令で上から順番に実行されます。
Dockerfileからイメージを作成
それでは、このDockerfileを用いてイメージを作成し、コンテナを作成&実行してみましょう。Dockerfileの中身の詳細については以降のchapterで詳しくみていくので、まずは体験してみて下さい。
・ステップ1
まずは作業ディレクトリを作成して下さい。
ここでは、仮にC:\Users\ユーザ名\Desktop\lesson4_1
としましょう。その中にDockerfile
という名前のファイルを作成し、上記のDockerfileの内容をコピーして貼り付けて下さい。
・ステップ2
次に、myfile.txt
という名前のファイルを作成し、以下のテキストを書き込みます。
myfile.txt
This is myfile
・ステップ3
C:\Users\ユーザ名\Desktop\lesson4_1
内にDockefile
とmyfile.txt
というファイルを作成したら、①PowerShellでその作業ディレクトリに移動します。

・ステップ4
作業ディレクトリ内に移動したら、②docker build -t my-first-image .
を実行して下さい。
docker buildコマンド
docker build -t my-first-image .
の最後の.
を忘れないようにして下さい。これにより、イメージをビルドする際に指定するDockerfileの位置をカレントディレクトリに指定しています。
このコマンドは、Dockerfileからmy-first-imageという名前をつけたイメージを作成します。
Dockerfileからイメージを作成
・ステップ5
そして、③docker run my-first-image
を実行して下さい。

myfile.txt
内に記述したテキストを表示することができました。
docker runコマンド
docker run
コマンドは指定したイメージ名を、最初にローカル内から探します。今回の場合はdocker build
コマンドによって作成されたmy-first-imageという名前のイメージからコンテナの作成&実行が行われました。ローカル内に該当のイメージがない場合は、Docker Hubからイメージを検索して取得します。(Docker Hubにmy-first-imageという名前のイメージは存在しないのでエラーが発生します)
以上で、Dockerfileからイメージを作成し、コンテナを作成&実行することができました。
docker container ls -a
でコンテナの一覧を表示してみましょう。

④コンテナが作成されていることが確認できます。
コンテナの実行方法の指定
次にdocker run
コマンドのオプションにより、どのようにコンテナを実行するか指定してみましょう。
・コンテナを実行終了時に破棄する
⑤docker run --rm my-first-image
を実行して下さい。先ほどと同様にmyfile.txt
内のテキストが表示されます。

--rm
オプションをつけると、コンテナは実行終了時に削除されます。よって、上記のコマンドを何回実行してもその度にコンテナが作成され破棄されるので、作成されたコンテナが溜まっていくことがありません。
⑥docker container ls -a
で作成されていないことを確認しておきましょう。
・コンテナの中に入って操作する
いままでのコンテナの実行はテキストを表示して終了するだけで、インタラクティブにコンテナを実行することができませんでした。
次は起動中のコンテナの中に入ってテキストデータの編集をしてみましょう。
⑦docker run -it my-first-image /bin/bash
を実行します。

コンテナ内のhomeディレクトリに入ることができました。
⑧vim myfile.txt
でvimを立ち上げてテキストを編集しましょう。

キーボードのi
を押して編集モードに移行してから、テキストを入力してみて下さい。

テキストを入力したら、キーボードのEsc
を押して通常モードに移行してから⑨:wq
を入力しEnter
でファイルを上書きして保存します。

ターミナル画面に戻ってきたら、⑩exit
でコンテナを終了させましょう。

これでコンテナ内のファイルを編集することができました。
コンテナがホストOSから分離された実行環境であることを確かめるため、ローカルのファイルは書き換えられていないことを確認しましょう。ファイルをダブルクリックでメモ帳を開きます。

確かに、上書きされていないことが確認できます。それでは先ほどファイルを編集して終了したコンテナを立ち上げて、ファイルの中身を見てみましょう。
docker container ls -a
でコンテナIDを確認します。

⑪docker start -a -i [コンテナID]
でコンテナを実行します。

先ほどと同じようにコンテナの中に入れました。vim myfile.txt
でファイルの中身を見てみましょう。

確かに、ファイルが変更されています。⑫:q
でvimを終了し、exitでコンテナから抜け出しましょう。

Lesson 4
Chapter 2
FROM
それでは、ここから続くchapterで、Dockerfileの各命令について学習していきましょう。
FROM
FROM
命令ではベースイメージを指定します。
chapter1の例では①FROM ubuntu
とあるように、ubuntu(ubuntu:latest)
をベースイメージに指定しています。以降の命令によって新しい情報を積み重ねてイメージを構築していく土台となるもので、必ず必要な命令になります。基本的には公開レポジトリにあるイメージを指定します。
ここで以下のような疑問を持たれるかもしれません。
指定したベースイメージのベースイメージは何になっているのでしょうか?
Docker Hubで公開されているイメージもDockerfileで記述されていますので、そのDockerfileを遡って確認してみましょう。
ここではredis
を例に見ていきます。
Docker Hubにアクセスしてredisを検索します。

②Docker Official Imageのものを見てみましょう。

③latestタグのものをクリックします。

Dockerfileが表示されるのでベースイメージを確認すると、④FROM debian:bullseye-slim
となっています。

次にdebianを検索して、⑤Docker Official Imageのものをクリックします。

⑥bullseye-slim
タグのものを見てみましょう。

ベースイメージは⑦FROM scratch
となっています。
今度はscratch
イメージを見にいきます。こちらからアクセスして下さい。

説明を読んでみると、scratch
イメージは空のイメージでベースイメージを構築する際の最小限のものになると書かれています。また、ベースとなる空のイメージであるのでdocker pull
やdocker run
で取得することはできず、DockerfileのFROM
命令で参照することしかできないとあります。
以上を整理してみると以下の図のようになります。
redisイメージの参照元
このようにFROM
命令で指定したベースイメージが参照しているイメージを確認することができました。気になった他のイメージがあればDocker Hubのページから同じように検索して調べてみて下さい。

Lesson 4
Chapter 3
RUN
続いてRUN
命令について学習します。
RUN命令
RUN
命令はイメージの構築時に実行するコマンドを指定します。
太字の強調をしましたが、イメージの構築時というのが大事なポイントです。
Dockerfile
FROM ubuntu
RUN apt update ①
RUN apt install -y vim ①
ENV DIRPATH=/home
WORKDIR $DIRPATH
COPY myfile.txt .
CMD cat myfile.txt
chapter1の例では①2つのRUN
命令によって、FROM
命令で指定したubuntuイメージに対してvimをインストールしています。
これにより構築されたイメージにはvimがインストールされ、このイメージから実行したコンテナ内ではvimが使えるようになっています。
chapter1でコンテナの中に入って操作したときにvimを使ってファイルを編集しましたが、ubuntuイメージには初期でvimはインストールされていないので、RUN
コマンドによりインストールしていたというわけになります。
RUN
命令(やその他のコマンドを指定する命令)にはシェル形式(shell form)と実行形式(exec form)という2つの書き方の形式があります。シェル形式は今回の例で書いた形式になります。
シェル形式と実行形式の書き方の違いは、以下のようになります。
シェル形式 (shell form) | 実行形式 (exec form) |
---|---|
RUN apt install -y vim |
RUN ["apt", "instll", "-y", "vim"] |
また、シェル形式では\(バックスラッシュ)を使うことによりRUN
命令を次の行に続けることができます。今回の例では以下のようになります。
Dockerfile
FROM ubuntu
RUN apt update && \
apt install -y vim
ENV DIRPATH=/home
WORKDIR $DIRPATH
COPY myfile.txt .
CMD cat myfile.txt

Lesson 4
Chapter 4
CMD/ENTRYPOINT
続いて、CMD
命令とENTRYPOINT
命令について学習します。
CMD命令
CMD
命令はコンテナ実行時のデフォルトのコマンドを指定します。chapter1の例を見てみましょう。
Dockerfile
FROM ubuntu
RUN apt update
RUN apt install -y vim
ENV DIRPATH=/home
WORKDIR $DIRPATH
COPY myfile.txt .
CMD cat myfile.txt ①
①CMD cat myfile.txt
とあります。catは指定したファイルの中身を出力するLinuxコマンドになります。
これによりdocker run
でこのコンテナを実行したときにcat myfile.txt
が実行され、コンテナが終了するという流れになっています。
CMD
命令はコンテナの実行時のコマンドを指定するといいましたが、docker run
時の入力によってそれを書き換えることもできます。
docker run [イメージ名] [コマンド]
で、CMD
命令で指定したコマンドを書き換えてコンテナを実行します。
chapter1で、docker run -it my-first-image /bin/bash
としてコンテナを実行したときのことを思い出してみて下さい。
元々のDockerfileで指定したコマンドはcat myfile.txt
でしたが、この場合、それを/bin/bash
に書き換えています。これによりシェルを立ち上げることでコンテナの中に入って操作できるようにしたというわけです。
CMD命令とRUN命令の違い
CMD
命令とRUN
命令の違いについては特に注意して認識して下さい。
命令 | 実行内容 |
---|---|
CMD | コンテナ実行時のコマンドを指定(docker run時のデフォルト実行内容) |
RUN | イメージ構築時のコマンドを指定(docker buildでイメージを構築する時の実行内容) |
それでは、コンテナの実行時に書き換えられずに実行されるコマンドを指定する命令はないのでしょうか?それがENTRYPOINT
命令になります。
ENTRYPOINT命令
ENTRYPOINT
命令で指定したコマンドはコンテナ実行時に書き換えられずに実行されます。
また、docker run [イメージ名]
の後に続く引数はENTRYPOINT
の後に追加されます。少し分かりづらいと思うので具体的に見てみましょう。
作業ディレクトリに移動して、myfile2.txt
を以下の内容で追加します。
myfile2.txt
This is myfile2
Dockerfileを以下のように書き換えます。
Dockerfile
FROM ubuntu
RUN apt update
RUN apt install -y vim
ENV DIRPATH=/home
WORKDIR $DIRPATH
COPY myfile.txt myfile2.txt .
ENTRYPOINT ["cat", "myfile.txt"]
実行形式(exec form)
RUN
命令のときに少し触れましたが、ENTRYPOINT
命令の形式を実行形式(exec form)にしているところに注意して下さい。ENTRYPOINT cat myfile.txt
というシェル形式の書き方だと望む動作が得られません。
これでイメージを再構築してみましょう。docker build -t my-fist-image:2 .
を実行します。

docker buildでのタグ指定
docker build
コマンドではタグを指定してイメージを構築することができます。今回の例ではイメージ名の後ろに:2をつけてタグ名をつけています。
イメージを構築したらdocker run my-first-image:2
でコンテナを実行してみましょう。

ENTRYPOINT
命令で指定したとおり、myfile.txt
の内容が出力されます。
次に、docker run my-first-image:2 myfile2.txt
を実行してみて下さい。

これでdocker run
の後に続く引数をENTRYPOINT
に渡せることができました。実際にコンテナ実行時に実行されたコマンドは、cat myfile.txt myifle2.txt
になります。
docker run [イメージ名] に続く引数がENTRYPOINT命令に対する引数に渡される
このようなイメージで実行されると考えて下さい。

Lesson 4
Chapter 5
ENV
続いてENV
命令について学習します。
ENV命令
ENV
命令は環境変数を設定します。
ENV [キー]=[値]
という形式で指定します。
Dockerfile
FROM ubuntu
RUN apt update
RUN apt install -y vim
ENV DIRPATH=/home ①
WORKDIR $DIRPATH ②
COPY myfile.txt .
CMD cat myfile.txt
chapter1の例では①キーがDIRPATH
で値が/home
という環境変数を設定しています。これにより、Dockerfile内で続く以降の命令や実行したコンテナ内でもこの環境変数を用いることができるようになります。
環境変数を用いる場合は②WORKDIR $DIRPATH
というキー名の頭に$マークをつけた形で使用します。これでWORKDIR /home
と書くのと同じことになります。
また、設定した環境変数がコンテナ内で生きているか確かめてみましょう。
docker run -it my-first-image /bin/bash
でコンテナの中に入ります。
③echo $DIRPATH
を実行してみて下さい。

/homeと表示され、環境変数がコンテナの中でも設定されていることが確認できました。

Lesson 4
Chapter 6
WORKDIR
続いてWORKDIR
命令について学習します。
WORKDIR命令
WORKDIR
命令は作業ディレクトリを指定します。
Dockerfile
FROM ubuntu
RUN apt update
RUN apt install -y vim
ENV DIRPATH=/home
WORKDIR $DIRPATH ①
COPY myfile.txt .
CMD cat myfile.txt
chapter1の例を見てみましょう。①WORKDIR $DIRPATH
により作業ディレクトリを/home
に設定しています。これによってDockerfile内で以降に続く命令の処理が/home
内で行われることになります。
理解を深めるためコンテナの中に入ってubuntuイメージのディレクトリ構造を確かめてみましょう。
docker run -it my-first-image /bin/bash
を実行します。

そうするとカレントディレクトリが②/home
になっています。

③cd ..
で一つ上のディレクトリに戻ってみましょう。そして④ls
コマンドでディレクトリ構造を確認します。
ubuntuイメージでは、このようなディレクトリ構造になっていることが確認できます。
WORKDIR
命令による作業ディレクトリの指定がなければ、このルートディレクトリがデフォルトの作業ディレクトリになるので、続くDockerfileでの命令もコンテナ実行時もこのルートディレクトリから始まることになります。
chapter1の例では、続くCOPY
命令が/home
ディレクトリに対して行われることになります。
このCOPY
命令については次のchapterで見ていきましょう。

Lesson 4
Chapter 7
COPY
続いてCOPY
命令とADD
命令について学習します。
COPY命令
COPY
命令ではファイルやディレクトリをイメージのファイルシステム上に追加します。
COPY [コピー元] [コピー先]
という形式で指定します。
Dockerfile
FROM ubuntu
RUN apt update
RUN apt install -y vim
ENV DIRPATH=/home
WORKDIR $DIRPATH
COPY myfile.txt . ①
CMD cat myfile.txt
chapter1の例では①COPY myfile.txt .
となっているので、ホストOS上でDockerfileを置いているディレクトリ内のmyfile.txt
ファイルをイメージ上のカレントディレクトリにコピーすることになります。
前chapterで学んだように、1つ前のWORKDIR
命令で作業ディレクトリを/home
に設定しているので、以降に続くCOPY
命令の実行におけるカレントディレクトリは/home
になります。
結果として、ホストOS上のmyfile.txt
が構築されるイメージの/home
ディレクトリ内にコピーされます。
ADD命令
ADD
命令もCOPY
命令とほぼ同じように動作しますが、ADD
命令には付加的な2つの機能がついています。
1つ目はtarファイルの展開機能です。ADD somefile.tar .
とするとsomefile.tar
を展開しイメージにコピーします。
2つ目はリモートURLのサポートです。ADD https://example.com/somefile.tar.xz .
のようにリモートURLを指定してファイルを取得することができます。
COPY命令とADD命令の使い分け
ADD
命令によるリモートURLからのファイル取得はイメージサイズが増大する問題があるので、推奨されていません。基本的には、ローカルファイルのコピーにはCOPY
命令を使い、tarファイルの展開にはADD
命令を使うと考えて下さい。

Lesson 4
Chapter 8
イメージとコンテナについて
これまでのLessonで、コンテナとイメージの関係についても理解が進み、dockerコマンドにも少し慣れてもらったかと思います。
そこで、Lesson4最後のchapterでは、コンテナとイメージの実体について、もう少し詳しく見ていきたいと思います。
イメージとレイヤー
これまでのLessonで触れてこなかったことがあります。それはイメージはレイヤーで構成されているということです。1つのレイヤーから成るイメージもあれば、複数のレイヤーを重ねたイメージもあります。
言葉だけの説明では分かりづらいので、具体例を見てみましょう。
Lesson3ではdocker pull
コマンドでイメージを取得しましたが、その出力の詳細を見て下さい。以下はdocker pull mysql
コマンドの出力画面です。

①で示した範囲をご覧下さい。ランダムな英数字の後にPull Completeと書かれている行が複数あると思います。
実は、この各行がそれぞれレイヤーを示しています。1つのイメージの取得時には、複数のレイヤーをそれぞれ個別に取得していることが分かります。
それでは、イメージの構築時にレイヤーがどのように構成されるのか見てみましょう。
Docker Hubのmysqlのページにアクセスします。

②lastetをクリックして下さい。

ここでは③イメージレイヤーの詳細を確認することができます。
20行あり、各行の右側にサイズが書かれています。このサイズが0Bになっているものはイメージのメタデータを変更するもので、新しいレイヤーを作成するものではありません。
サイズがある行を数えてみると全部で11行あり、docker pull mysql
で取得してきたときのPull Completeの行数と一致しています。
それでは、イメージの構築はどのように指定されるのだったでしょうか?
そう、Dockerfileです。今度は④からDockerfileを見にいきましょう。

Githubリポジトリが開き、複雑そうなファイルが確認できると思いますが、命令の種類に注目して下さい。数ある命令のうちレイヤーを作成するのはRUN
、COPY
、ADD
命令のみです。
数えてみると、RUN
とCOPY
命令が合わせて10個あり、これとFROM命令でのベースイメージの指定と合わせて計11個のレイヤーが作成されていることが確認できます。
イメージレイヤー
このように命令1つにつき、1つのレイヤーを作成するということを実感してもらえたと思います。
構築イメージの容量を抑える
Dockerfileの命令を工夫して書くことで、構築されるレイヤーの容量、つまりは最終的に出来上がるイメージの容量を小さくすることができます。イメージが小さくなると、素早い配布が可能になります。ここでは詳述しませんが、この命令とレイヤーの関係を覚えておくと後々役立つことがあるでしょう。
コンテナとレイヤー
上記ではイメージがレイヤーで構成されていることを確認しました。それではコンテナはどのように作られているのでしょうか?
これまでのLessonで、繰り返しコンテナはイメージを元に作成されると述べてきました。
そこから、コンテナはイメージから複製されるものという印象を抱いている方もいるかもしれません。その考え方は基本的には正しいのですが、コンテナとイメージには重要な違いがあります。
それはコンテナにはイメージで構成されたレイヤーの一番上に書き込み可能なレイヤーが存在していることです。
docker run
の実行時に、後ろにコンテナ実行時コマンドをつけて、CMD
命令で指定した命令を書き換えてコンテナを実行した時のことを思い出して下さい。
このような新しい動作の指定やデータの変更などは、全てこの書き込み可能なコンテナレイヤーに保存されます。
コンテナとレイヤー
これにより、1つのイメージから複数のコンテナを作成することができています。
コンテナの削除時は、この一番上の書き込み可能なレイヤーのみが削除されることになります。よって、イメージレイヤーは何も変更されず、そのまま残り続けることができるのです。
まとめ
以上、Lesson4ではDockerfileの書き方の基本をメインにコンテナとイメージの関係についても理解を深めました。
以下の、Lesson4で学習したDockerfileの命令のまとめで復習を行ない、本Lessonを終了したいと思います。
命令 | 実行内容 |
---|---|
FROM | ベースイメージを指定 |
RUN | イメージ構築時のコマンドを指定 |
CMD | コンテナ実行時のコマンドを指定(docker run実行時に書き換え可能) |
ENTRYPOINT | コンテナ実行時の書き換えられないコマンドを指定 |
ENV | 環境変数の設定 |
WORKDIR | 作業ディレクトリの設定 |
COPY | ローカルファイルをイメージにコピー |
ADD | COPY + (tar展開、リモートURLサポート) |
