[初心者向け] Dockerコンテナの内側

コンテナに纏るお話を思いついたので書いてみます。コンテナに関する理解を深めるのが狙いです。順を追って進めますので、技術的な側面がよく解らない方でも何となく雰囲気が掴めるようにしていきたいと思います。なお、細かい用語は解説していないので適時調べてみてください。また、読み進めるための前提知識としてコンテナの概要について学ぶことをお勧めします。

では、はじまりはじまり。

いつものデモから

私はしばしばコンテナに関するデモを行う機会があります。その時は以下のようなコマンドをクラウド上のサーバで実行しております。

$ sudo docker run --rm -p 80:80 nginx:latest

このコマンドを実行すると、黒い画面の裏側では次のような作業が実施されます。

  1. Nginxの最新版がセットアップされたコンテナイメージがサーバにダウンロードされる
  2. コンテナイメージからコンテナが作り出されて稼働する

デモでは次にブラウザを開き、サーバのポート80番へアクセスをします。そうすると、Welcome to Nginxとブラウザに表示されコンテナの稼働が確認できましたね、コンテナってすごいですねー、と言う流れです。

このデモで実感してもらいたいことは

  1. コマンド1発でNginxというWebサーバが稼働しているという簡易さ
  2. あっという間にサーバの稼働までたどり着くスピード感
  3. 何度やっても同じ結果が得られるところ

になります。

では、この時使われているコンテナイメージ、つまりnginx:latestのサイズはどのくらいか見てみましょう。

先ほどのdocker runコマンドでは、イメージの取得とコンテナの作成、稼働が一気に行われましたが、次はステップを踏んで作業してみます。

まずdocker pull nginx:latestでコンテナイメージ取得のみを実施します。

~/d/nginx ❯❯❯ docker pull nginx:latest
latest: Pulling from library/nginx

efd26ecc9548: Pull complete  
a3ed95caeb02: Pull complete  
83f52fbfa5f8: Pull complete  
fa664caa1402: Pull complete  
Digest: sha256:12127e07a75bda1022fbd4ea231f5527a1899aad4679e3940482db3b57383b1d  
Status: Downloaded newer image for nginx:latest  

次にdocker imagesでサーバが保持しているイメージの一覧を確認してみます。

~/d/nginx ❯❯❯ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE  
nginx               latest              eb4a127a1188        3 days ago          182.7 MB  

補足:>>>なんていう妙なコマンドプロンプトが気になる方はこちら。(http://ohmyz.sh/)

最後を見ると182.7MBとなっております。VMを作ってNginxをインストールした場合に比べ明らかに小さいという印象です。なぜなら、VMを作った場合はOSが全て入っています。そもそもVMの場合はディスクイメージですから大きくなってしまいます。一方、上記のコンテナイメージはあくまでアプリケーションが稼働するために必要となるものしか入っていないので、圧倒的に小さいです。

では、ここからちょっと掘り下げてみます。そもそも、このコンテナイメージはどこからやってきたのでしょうか。

docker pullというコマンドはDocker Hubで公開されているイメージを取得するコマンドです。つまり、Nginxの公式イメージを取得していたことになります。場所はこちら。

https://hub.docker.com/_/nginx/

このページにアクセスするとDocker Pull Commandにはdocker pull nginxと書かれています。先ほど実行したコマンドではnginx:latestとしましたが、酷似していますね。この:latestはタグと呼ばれるものです。同じイメージでも、例えばバージョン違いであったりと対象を切り替えるのに使います。上記URL先の公式ページをみるとlatest以外にもタグがあることがわかります。

ということで、pullコマンドを使って取得したイメージはDocker Hubで配布されているものであることが解りました。

では、さらに掘り下げていきましょう。

公式Nginxコンテナはどのように作られているのか

次にnginx:latestはどのように作られているのかを確認したいと思います。

latestのタグに関するドキュメントを見てみると、Githubへのリンクがあります。

https://github.com/nginxinc/docker-nginx/blob/19799fa644461ed6c5ea07c0bc0ea0cc277c2d77/mainline/jessie/Dockerfile

リンク先はDockerfileというものです。このDockerfileというものはdocker buildというコンテナイメージを作るコマンドにより参照が行われます。そして、このファイルに書かれている指示に従ってコンテナイメージが作られます。いわば作業指示ファイルです。

Dockerfileの先頭を見るとFROM debian:jessieと書かれています。つまりnginx:latestイメージはdebian:jessieというイメージをもとに、いくつかの作業(今回はnginxのインストール)が行われて作られているということになります。

ここでもう一つのページを見ておきます。先ほど紹介したDocker HubのNginxのページにはImageLayers.io 183MB/8Layerというリンクがありました。 こちらも開いてみてください。

https://imagelayers.io/?images=nginx:latest,nginx:stable,nginx:mainline-alpine,nginx:stable-alpine

このImage Layersでは、Dockerfileにより行われた作業の結果をグラフィカルに見るができます。各コンテナイメージがどのように作成されていて、かつその手順でどのくらいファイルサイズが膨らんでいるかが解るというサービスです。

nginx:latestは183MBとなっており、docker pullで取得後docker imagesで確認したサイズと同じです。

Githubで公開されているDockerfileとImagesLayersで確認できる各Layerを見るとコンテナイメージがどのように構成されているのかが解ります。

小さいコンテナ

ここで、ちょっと気になることが見つかりました。ImageLayersのページでは複数のタグも表示されています。nginx:latestは183MBになっておりますが、ここで気になるのは、nginx:stable-alpineというイメージです。サイズはなんと15MB、10分の1以下です。

つまり、nginx:latestをpullすると183MBのダウンロードが発生しましたが、nginx:stable-alpineに替えると15MBで済んでしまうことになります。この差は大きい。なぜこの差が生まれるのでしょう。

答えはLayerの最初にあります。

nginx:latestは最初のLayerが125MBになっており、nginx:stable-alpineは5MBです。この時点で120MBも差が付いています。このLayerは何なのでしょうか。

Githubで確認したDockerfileの先頭はFROM debian:jessieと書かれていました。これが最初のLayerの正体です。では、nginx:stable-alpineのDockerfileを見てみましょう。

https://github.com/nginxinc/docker-nginx/blob/19799fa644461ed6c5ea07c0bc0ea0cc277c2d77/stable/alpine/Dockerfile

こちらを見てみるとFROM alpine:3.3となっています。

つまり、AlpineというLinuxをベースにして作られたコンテナイメージであるということです。

なお、Alpine Linuxのページはこちら( http://www.alpinelinux.org/

Alpine LinuxのHPにあるaboutを読むと、どのようなディストリビューションなのか解りますので、気になる方は目を通しておきましょう。

そもそもAlpine Linuxが目指しているものがシンプルでコンパクトなLinuxのようなので、コアが小さいということです。ただし、便利なツールが入っていません。ここまでご紹介したnginx:latestのDockerfileとnginx:stable-alpineのDockerfileを見比べてみてください。

latestのDockerfileは全体で20行、stable-alpineは100行です。また、中身をみてもそれぞれのLinuxの差が色濃く反映しています。

一番の違いはlatestがapt-getを使ってセットアップをしているのに対して、alpineの方はapkというツールを使って準備を整え、Nginxのソースを取得しコンパイルを行っております。

今回のまとめ

ということで、少しコンテナの中身をみてみました。

色々な気付きがあったかと思います。

Dockerのコンテナはベースとなるイメージを選び、そこに必要なものをセットアップして作られています。つまり、この手順を変更すれば独自のコンテナを作る事ができます。色々なDockerfileを読んだり、公式ドキュメントを読むと作り方を学ぶ事ができます。

また、作り方によってコンテナのサイズは大きく変わる事もわかりました。コンテナのサイズを小さくすることは大きなメリットを享受できます。例えば、latestイメージから100個のコンテナを作った場合とstable-alpineから100個作った場合では、消費されるリソースの量が圧倒的に違います。また、作成から展開までの速度についても差が生まれることも容易に想像できます。

一方、小さいコンテナを作るにはそれなりの技術力が必要だということも痛感できたかと思います。