Docker イメージというと、一般的には既存の Docker イメージをベースにして作る機会が多い。
そうしたとき Dockerfile にはベースとなるイメージを FROM
命令で指定する。
とはいえ、既存のイメージをベースにしない、まっさらな状態からイメージを作ることもできる。
それが FROM
命令に scratch
を指定した場合になる。
今回は FROM scratch でまっさらな状態から Docker イメージを作ってみることにする。
試した環境は次の通り。
$ docker version Client: Version: 18.01.0-ce API version: 1.35 Go version: go1.9.2 Git commit: 03596f5 Built: unknown-buildtime OS/Arch: darwin/amd64 Experimental: false Orchestrator: swarm Server: Engine: Version: 18.01.0-ce API version: 1.35 (minimum version 1.12) Go version: go1.9.2 Git commit: 03596f5 Built: Wed Jan 10 20:13:12 2018 OS/Arch: linux/amd64 Experimental: false
Ubuntu 16.04 LTS の Docker イメージを作ってみる
Docker コンテナというのは、結局のところシステムから隔離された Linux の一プロセスに過ぎない。 そのプロセスが動作するのに必要なファイルをまとめたものが Docker イメージということになる。 つまり、例えば特定の OS のルートファイルシステム一式さえあれば、その OS の Docker イメージが作れることになる。 ここでは例として Ubuntu 16.04 LTS の Docker イメージを作ってみることにする。
まずは公式で公開されている Ubuntu 16.04 LTS のルートファイルシステム一式をダウンロードしてくる。
$ wget http://cdimage.ubuntu.com/ubuntu-base/releases/16.04/release/ubuntu-base-16.04.3-base-amd64.tar.gz
あとは、それをファイルシステムのルートに展開した Dockerfile を用意すれば良い。
ADD
命令を使うと tar.gz ファイルは第二引数のパスに展開される。
$ cat << 'EOF' > Dockerfile FROM scratch ADD ubuntu-base-16.04.3-base-amd64.tar.gz / EOF
上記の Dockerfile をビルドする。
$ docker build -t example/scratch-ubuntu1604 . Sending build context to Docker daemon 46.12MB Step 1/2 : FROM scratch ---> Step 2/2 : ADD ubuntu-base-16.04.3-base-amd64.tar.gz / ---> 2e6f55bc5efd Successfully built 2e6f55bc5efd Successfully tagged example/scratch-ubuntu1604:latest
ちゃんと Docker イメージが登録された。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
example/scratch-ubuntu1604 latest 2e6f55bc5efd 15 seconds ago 120MB
上記でビルドした Docker イメージからコンテナを起動してみよう。 起動するプログラムは bash にした。
$ docker run -it example/scratch-ubuntu1604 /bin/bash root@f3359e8630cc:/#
どうやら、ちゃんと動作している。
root@f3359e8630cc:/# ls / bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var root@f3359e8630cc:/# cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=16.04 DISTRIB_CODENAME=xenial DISTRIB_DESCRIPTION="Ubuntu 16.04.3 LTS"
もちろん実用という面では他にも色々とケアすべきところはあるだろうけど、これだけ単純な作業で作ることができた。
シングルバイナリだけから成る Docker イメージを作ってみる
前述した通り Docker イメージというのはコンテナとして起動する Linux プロセスの動作に必要なファイル一式を指す。 逆説的には、起動する Linux プロセスの動作に必要ないファイルというのはイメージの中で無駄ということになる。 つまり、究極的にはプロセスの動作に必要なファイル一式がシングルバイナリにまとめられていれば、そのファイルだけあれば良いことになる。 とはいえそんなことができるのか?というと Golang を使えば意外とできてしまう。 Golang は基本的に外部のライブラリに依存せず、動作に必要な全てを自前で用意している。 そのため、ビルド後のバイナリは動作に libc すら必要としない。 さすが世界で最もコンテナを活発に利用している企業がデザインした言語という感じがする。
前置きが多少長くなったけど、ここからは実際にシングルバイナリだけから成るイメージを作っていく。 まずは Golang のサンプルコードを用意する。 内容は、単なるハローワールドにした。
$ cat << 'EOF' > helloworld.go package main import "fmt" func main() { fmt.Printf("Hello, World!\n") } EOF
上記をビルドする。
$ go build helloworld.go
ここで注意すべきなのは動作させる Docker ホストと同じアーキテクチャの Linux 上でビルドすること。 当たり前だけど OS やアーキテクチャが異なる環境でビルドしたバイナリだと動かないので。
$ file helloworld
helloworld: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
あとはビルドしたバイナリを組み込んだ Docker イメージを作るだけ。 次のようにシンプル極まりない Docker ファイルを用意した。
$ cat << 'EOF' > Dockerfile FROM scratch ADD helloworld / CMD ["/helloworld"] EOF
上記をビルドして Docker イメージを作る。
$ docker build -t example/scratch-go . Sending build context to Docker daemon 2.292MB Step 1/3 : FROM scratch ---> Step 2/3 : ADD helloworld / ---> a2e0629ddc0c Step 3/3 : CMD ["/helloworld"] ---> Running in e61813649513 Removing intermediate container e61813649513 ---> 898df177330d Successfully built 898df177330d Successfully tagged example/scratch-go:latest
登録されたイメージを確認すると 2.29MB という小ささに収まっている。
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE example/scratch-go latest 898df177330d 20 seconds ago 2.29MB example/scratch-ubuntu1604 latest 2e6f55bc5efd About a minute ago 120MB
登録されたイメージを元にコンテナを起動してみよう。
$ docker run -t example/scratch-go Hello, World!
ちゃんとメッセージが表示されて上手くいったようだ。
めでたしめでたし。
- 作者: W. Richard Stevens,Stephen A. Rago
- 出版社/メーカー: 翔泳社
- 発売日: 2014/06/05
- メディア: Kindle版
- この商品を含むブログ (7件) を見る
スマートPythonプログラミング: Pythonのより良い書き方を学ぶ
- 作者: もみじあめ
- 発売日: 2016/03/12
- メディア: Kindle版
- この商品を含むブログ (1件) を見る