【Docker使えるようになりたい】【#7 FROM & RUN】Dockerfileの使い方 基本編

Dockerfileとは

イメージはコンテナを作るためのファイルですが、そのイメージをベースイメージをもとにカスタマイズして新しい独自のイメージを生成するための仕様書がDockerfileです。

Docker Hubなどにあるイメージには最低限の機能しか入っていないので、カスタマイズすることを前提としています。

なぜDockerfileを使うのか

Dockerを使う場合、「コンテナ内に自分好みの開発環境や公開環境を構築」したい場合は、ベースイメージのコンテナを生成し、中に入ってapt系のコマンドを自分で打つという、いつものOS上でやるような環境構築の方法ではなく、すでにツールや設定が終わっているイメージを作成するアプローチが一般的

コンテナは自分が使っているパソコン上でしか動かないので、コンテナ自体をカスタマイズしてしまうとほかの人に配布したい場合に無駄な設定やコピーしたくないデータまで入ってしまう可能性があるので、イメージの段階で配布可能な状態にするのが理想です。

Imageはファイル容量が大きくなりがちなので、それぞれの手元でDockerfileからイメージを生成してコンテナを作ってもらうほうがより早く環境をコピーできるという利点もあります。

Dockerfileからイメージを作成する手順

ハンズオン形式で進めていくのでまずは、フォルダの生成とDockerfileの作成を以下のような構造になるように作成します。
ターミナルのカレントディレクトリはDockerTestフォルダにします。

DockerTest/   <- カレントディレクトリ
    - Dockerfile

Dockerfileでは、まず「ベースイメージ」というもとになるイメージを指定する必要があります。

今回は、試しにubuntuバージョン20.04を使用するので、以下の1行をDockerfileに記述します。

FROM ubuntu:20.04
  • FROM : 使用するベースのイメージを指定
    • : 20.04 : そのイメージのタグ(バージョン)を明示的に指定(指定しないと:latestが対象になります)

そして作成したDockerfileから独自のイメージの生成を以下のコマンドを使用して行います。

docker image build {ディレクトリパス}

ディレクトリパスは基本はDockerfileがあるパスを指定します。

今回は、カレントディレクトリの直下にDockerfileを作成しているので、以下のような.だけでディレクトリを指定しています。

docker image build .

buildコマンドで指定するディレクトリは、特別な意味のあるディレクトリになるので、基本はDocker作業用のを作成、移動してから.でカレントディレクトリを指定してあげるのがいいかと思います。

特別な意味のあるディレクトリの詳細な説明は以下の記事で解説しています。
詳しく知りたい方はご覧ください。


TODO 次の記事のURL


無事に自作イメージが生成できれば以下のようなログが流れると思います。

[+] Building 0.2s (5/5) FINISHED                                                                   docker:desktop-linux
 => [internal] load build definition from Dockerfile                                                               0.0s
 => => transferring dockerfile: 54B                                                                                0.0s
 => [internal] load metadata for docker.io/library/ubuntu:20.04                                                    0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => CACHED [1/1] FROM docker.io/library/ubuntu:20.04@sha256:fa17826afb526a9fc7250e0fbcbfd18d03fe7a54849472f86879d  0.0s
 => => resolve docker.io/library/ubuntu:20.04@sha256:fa17826afb526a9fc7250e0fbcbfd18d03fe7a54849472f86879d8bf562c  0.0s
 => exporting to image                                                                                             0.1s
 => => exporting layers                                                                                            0.0s
 => => exporting manifest sha256:61dabcc03fce0d2215eb9b36f0e2dbae6e69a67b8b053ffed0df332ad9724e30                  0.0s
 => => exporting config sha256:ca50bf172a18927296f8d57164b9a553970ac2aaa70d79c7383bf717e085d43e                    0.0s
 => => exporting attestation manifest sha256:814df59e26e5454091cd545d2059370ddf5ba829e85af7b6a9bd644650cbd6ab      0.0s
 => => exporting manifest list sha256:4ea81cedea5b6d3bbc7ec1e7a7511b7666002d62d85a068579e918441e8c8ef0             0.0s
 => => naming to moby-dangling@sha256:4ea81cedea5b6d3bbc7ec1e7a7511b7666002d62d85a068579e918441e8c8ef0             0.0s
 => => unpacking to moby-dangling@sha256:4ea81cedea5b6d3bbc7ec1e7a7511b7666002d62d85a068579e918441e8c8ef0          0.0s

イメージが正常に生成できたか確認するためにdocker image lsコマンドを実行すると、ログの「最後の行に出力されているsha256の先頭文字列と同じ内容のIDを持ったコンテナ」が生成した自作イメージになります。

REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
<none>       <none>    4ea81cedea5b   4 weeks ago     109MB

今回のDockerfileでは自作イメージに対して特別コマンドは実行していないので、中身はベースイメージと同じものが生成されています。

このイメージをよく見ると、REPOSITORYTAG<none>になっているのが確認できると思います。

これは、イメージ生成時に名前をつけていないためこのような表示になっています。

イメージ生成時に名前をつけるオプション : -t {名前:タグ}

イメージ生成時に名前をつけないと、<none>という名前とタグが付いてしまいます。
これの厄介なところは、すべての独自イメージに同じ<none>がついてしまうところです。
違いを判別できるのは、IMAGE IDのみになってしまいます。

イメージ生成時に名前をつけるには、docker image build -t {名前:タグ}を使います
:タグはなくても大丈夫ですが、バージョンが分かりやすくなるように使うのはいいのではないの

docker image build -t test:v1 .

実行後、docker image lsコマンドを実行して状態を確認すると、以下のような表示になり期待通りの命名ができていることが確認できます

REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
test          v1        460e105405c9   8 minutes ago    129MB

RUNを使ってイメージ生成時にコマンドを実行する

RUN命令を使用することでイメージをビルドする際にイメージ内で実行したいコマンドを実行させる事ができます。

つまり、イメージ内で使いたいツールがある場合、RUN apt install 使いたいツールのような記述をすると、「イメージ」の生成時にすでにそのツールをインストールしたイメージを生成できるということです。

例 : Ubuntuにスピートテストツールをインストールする

以下のspeedtest(ネットのスピードを測るツール)をデフォルトでインストールしたイメージを生成したます。

このツールには、curlが必要なので合わせてインストールします。

Dockerfileは以下のように3つのRUNコマンドが入ります。

FROM ubuntu:20.04

RUN apt update
RUN apt install -y curl
RUN curl -s https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh | bash
RUN apt install -y speedtest


最初のコマンドはaptの更新をするためのコマンドです。

-yオプションは、apt installコマンド実行時のインストールしていいですか?プロンプトをyesで答えると事前に指定できるオプションです。
RUN実行時はこちらから入力ができないので、デフォルト動作を設定できないとbuildがそこで止まってしまうか、正常にインストールできない結果になってしまいます。

では、このDockerfileを元にイメージをビルドします。
今回は、イメージ名をspeedとしてタグをv1にしました

docker image build -t speed:v1 .

イメージ生成後、このコンテナを使ってスピードテスを実行してみます。

docker container run -it speed:v1

speedtestというコマンドで実行できます。
実行後ライセンスに同意するとテストが実行されます。

root@6a3b852f58f6:/# speedtest
==============================================================================

You may only use this Speedtest software and information generated
from it for personal, non-commercial use, through a command line
interface on a personal computer. Your use of this software is subject
to the End User License Agreement, Terms of Use and Privacy Policy at
these URLs:

    https://www.speedtest.net/about/eula
    https://www.speedtest.net/about/terms
    https://www.speedtest.net/about/privacy

==============================================================================

Do you accept the license? [type YES to accept]: YES
License acceptance recorded. Continuing.


   Speedtest by Ookla

      Server: i3D.net - Tokyo (id: 21569)
         ISP: Internet Multifeed Co.
Idle Latency:     7.63 ms   (jitter: 0.46ms, low: 6.92ms, high: 8.30ms)
    Download:   178.16 Mbps (data used: 236.9 MB)
                 12.03 ms   (jitter: 4.35ms, low: 6.91ms, high: 71.27ms)
      Upload:   349.27 Mbps (data used: 485.7 MB)
                 19.39 ms   (jitter: 6.90ms, low: 7.10ms, high: 88.79ms)
 Packet Loss:     2.4%
  Result URL: https://www.speedtest.net/result/c/76b35e46-ecf4-4162-a1c1-7e3bc4244cc9

独り言

私は最初この説明を聞いて、「コンテナ実行時にコマンドを実行する」のではなく、「イメージ生成時にコマンドを実行する」ことに、違和感を少し覚えました。
コマンドの実行は「コンテナになってから行う」のかと思ったからです。

イメージ生成時にコマンドを実行するとファイルが増えたりしてイメージサイズが大きくなるのではないかと思いました。

イメージの時点でそのイメージをコンテナとして使う際に必要なツールや情報は入れておくのがDockerの思想らしいので、こうなっているらしい。

つまりは、「コンテナはすぐに実行できる状態」で生成されないと行けないということだと思う

私の疑問でも結局はイメージかコンテナかどちらかの生成時にツールや情報は入れないといけないとは思っていたので、そしたらコンテナを作るときに毎回ツールをインストールするよりそれをインストールしてあるイメージから作り上げたほうが効率的なのはなんとなく理解できる。(イメージの時点で情報を入れておけば一度イメージを作れれば、ツールのダウンロードリンク切れとかは、コンテナ生成時には発生しなさそうだし)

まとめ

今回はDockerとDockerfileの基本をまとめました。

Dockerの思想をきちんと理解することでより正しく効率的な使い方をできるようになると思うので、ツールの使い方としてだけではなく、そのツールの設計思想を理解することを心掛けていく必要もあると考えるようになりました。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA