こんにちは。Яeiです。
今回は、現役エンジニアの私がDockerfileのFROMの書き方について記事にしようと思います。
FROM句はDockerfileを記載する上で基礎中の基礎になりますので覚えておいて下さい。
当記事は以下の公式リファレンスを元に記載しております。
Dockerfile reference >>
目次
結論:FROMの書き方
書き方は以下の3通り可能となります。
FROM [–platform=<プラットフォーム>] <イメージ名> [AS <名前>]
または
FROM [–platform=<プラットフォーム>] <イメージ名>[:<タグ>] [AS <名前>]
または
FROM [–platform=<プラットフォーム>] <イメージ名>[@<ダイジェスト>] [AS <名前>]
例:nginxの最新のオフィシャルイメージを指定する場合
FROM nginx:latest
詳細:FROMの書き方
概要
DockerfileのFROM句では作成するコンテナのベースとなるイメージを指定します。
ベースとなるイメージにはdebianなどのLinuxディストリビューションを指定することも出来ますし、
nginxやPythonなどといったアプリケーションをインストールしてくれているイメージを指定することも出来ます。
このようなセットアップ済みのイメージは公式イメージとしてDocker Hubにアップロードされております。
つまり、用途がハッキリしている場合は、こうしたイメージを利用することで環境構築が簡単にできるようになるのです。
Docker Hub:
https://hub.docker.com/
ただし、少し注意点として、オフィシャルイメージはその軽量さからalpine linuxと呼ばれるディストリビューションが採用されていることが多々あります。
コンテナの特性上、イメージサイズが軽量であることが美のように崇められてきました。
そのため、alpine linux(かなり軽量なLinuxで最低限の機能しか入っていないイメージ)がとても活用されてきましたが、以下記事に挙げられているような問題点も報告されております。
軽量Dockerイメージに安易にAlpineを使うのはやめたほうがいいという話
https://blog.inductor.me/entry/alpine-not-recommended
要約すると、Ruby、Python、Node.jsなどでNativeモジュールをバンドルしているアプリケーションの場合、パフォーマンスの劣化や互換性の問題にぶつかりますよ、というもの。
その他、vimすら入っていないという軽量化の徹底ぶりですので、alpine linuxを許容するか否かは要検討してみて下さい。
基本形
上記結論で記載した3パターンはどれもオプションを記載しているためややこしい形になっております。
しかし、実際に覚えるのは以下のように簡単な構造になります。
FROM <イメージ名>
つまり、利用したいイメージを指定するだけとなります。
例えば、IT業界お馴染みの「Hello World!」みたいなのを表示したいな、と思ったとしましょう。
先ほどのDockerHubにて公式イメージ「hello-world」を見つけることができました(公式イメージはイメージ名の横に印がついております)
$ cat Dockerfile
FROM hello-world
※ DockerHubのオフィシャルイメージはレジストリ「docker.io/library/」にあるため本来であれば「FROM docker.io/library/hello-world」のように指定が必要なのですが、
以下記事にある通り、レジストリ部分は省略できます(省略したものがこちらのショートカットになっているようです)。
docker.io/library/をを指定しないでもDockerHubからイメージプルできる理由
このDockerfileをビルドしてみます。
$ docker image build -t test_hello .
出来上がったイメージを元にコンテナ起動すると簡単にHello Worldを出力できます。
$ docker image ls test_hello
REPOSITORY TAG IMAGE ID CREATED SIZE
test_hello latest bb31f47d8cce 3 months ago 13.3kB
$ docker container run test_hello:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
こんな感じで、先人が用意してくれたイメージを使うことで簡単にコンテナを起動することができるのです。
※ 今回のDockerfileでは「FROM」のみの指定ですので、以下のようにコンテナ起動コマンドだけでも再現できます。
$ docker container run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Already exists
Digest: sha256:2498fce14358aa50ead0cc6c19990fc6ff866ce72aeb5546e1d59caac3d0d60f
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
バージョン指定
イメージを利用する際に、先ほどのイメージ名だけの指定では困るケースが出てきます。
例えば、Pythonの公式イメージを利用しようとした際に、DockerHubでイメージを確認すると以下のようにたくさんのイメージがあります。
これは、ベースとなるOSの違いやバージョンによる違いとなっております。
例えば、debianの安定版(2021年現在)であるbullseyeを使いたい場合、debianの指定だけだとどのイメージが取得されるのか分かりません。
そこで、「タグ」を指定することができます。
FROM <イメージ名>[:<タグ>]
「タグ」とは任意に付けることが出来るのですが、基本的にはバージョン情報を付与することが多いようです。
そのため、「イメージ名+バージョン情報」で取得したいイメージを指定することができるのです。
なお、先ほどのタグを指定しない書き方をした場合、latestつまり最新が取得されますのでご注意下さい。
$ cat Dockerfile
FROM python:latest
$ docker image build -t python_test .
イメージが出来上がったらコンテナを起動してログインしてみます。
$ docker container run --rm -it python_test bash
root@65145d30947b:/# python
Python 3.10.1 (main, Dec 21 2021, 09:01:08) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 1+1
2
>>>
ちなみに、latestのバージョンは以下の通りでした。
root@d57853d5f83e:/# cat /etc/debian_version
11.2
次に、以下の通りバージョン指定してみます。
$ cat Dockerfile
FROM python:buster
同様にイメージビルドしてコンテナログインしてバージョン確認してみます。
root@13310db2f6ea:/# cat /etc/debian_version
10.11
busterは最新に比べて少し古くなっていることが分かりますね。
このように、公式イメージではタグを用いてバージョンの違いやベースとなるディストリビューションの違いを表しております。
自分が何を使いたいのか意識する必要がある方は是非覚えておいて下さい。
基本的にDockerHubに明記されております。
また、自分がイメージを作成する側だった場合、こういった点を意識してタグ付けを行って下さい。
ダイジェスト指定
ダイジェスト指定も可能となります。
FROM <イメージ名>[@<ダイジェスト>]
そもそもダイジェストって何?という話ですが。
ダイジェスト値とはイメージに割り当てられる識別子でして、sha256ハッシュ関数で採番されるようです。
試しにdocker imagesコマンドのオプションでイメージに割り振られたダイジェスト値を確認してみましょう。
ただし、あまり活用されているところは見たことがありません。
少なくとも個人利用の場合は上述のタグ指定しか活用しませんので、こんな指定ができるんだな程度に理解しておけば良さそうです。
その他
FROM句で指定できるものとして、あとは二つ触れていないものがありました。
・[–platform=<プラットフォーム>]
・[AS <名前>]
–platform指定では特定のプラットフォーム向けイメージを指定可能となります。
「プラットフォーム?」と聞き馴染のない方もいらっしゃるかもしれませんが、CPUアーキテクチャの種類と思って頂いて良さそうです。
利用者観点ですとあまり意識することはないと思いますのでざっくりとした説明になりますが、armはARM社が開発したもので、amdはIntel社が開発したものとなります。
自分が使っているマシンのCPUアーキテクチャを調べたい場合は、Linuxコマンド「uname -m」で調査できます。
これもDocker Hubの公式イメージを見てもらうのが早いのですが、以下のようにプラットフォーム毎にイメージを用意してくれていたりします。
なぜ、利用者はあまり意識する必要がないと記載したかですが、DockerHubに挙げられているイメージは基本的にマルチアーキテクチャイメージと呼ばれる仕組みでイメージ作成されてます。
これは、利用者側はpullするだけで、利用者PCに応じたイメージを取得してくれるようになっているのです。
ここら辺は難しい話になりますので別の機会に説明しようと思います。
次にASですが、これは主にマルチステージビルドを実施する際に利用します。
マルチステージビルドとはDockerfile内でビルドステージを区切るビルド方法となります。
例えば以下のようにDockerfileを作成します。
$ cat Dockerfile
# 前半
FROM python:bullseye AS sample
RUN echo "test" > /test.txt
# 後半
FROM debian:latest
COPY --from=sample /test.txt /root/text.txt
一つのDockerfileにFROMが二つ出現します。
前半部分ではtest.txtを作成します。後半では前半で作成したtest.txtを自分のイメージにビルドします。
そして、最終的に作成されるイメージは後半のイメージになるのです。
今回の例ではありがたみが皆無なのですが、例えば、ビルドが必要なアプリケーションの場合、
ビルド前の資材は往々にして不要となります。
不要な資材を実行環境に入れると容量の圧迫や脆弱性に繋がりかねません。
そのため、マルチステージビルドを用いて、イメージサイズの軽量化や脆弱性対策ができるのです。
マルチステージビルドはイメージサイズの軽量化を突き詰めていくと必須技術になってきますので、ASは覚えておくと良いと思います。
その他2(git bashを使っていて困ったこと)
git bashを使っていて、コンテナにログインしようとすると以下のエラーに見舞われます。
$ docker container run --rm -it sha_test bash
the input device is not a TTY. If you are using mintty, try prefixing the command with 'winpty'
警告の通り「winpty」を先頭に付けてあげると問題無く動きます。
$ winpty docker container run --rm -it multi_test bash
root@c6627b3c3144:/# cd /root/
詳細は以下の記事が分かりやすかったので参考にしてみて下さい。
参考
【Git for Windows】tty/mintty/winptyとは何なのか?【Gitbash】unrealMan’s blog
当記事は以上となります。
Docker命令はシンプルですが、意外にも奥が深い物です。
今後のますますの発展が期待されますので是非とも覚えておくとよいでしょう。
長々とお疲れさまでした。