Translate

2015年3月12日木曜日

The Docker User Guide: Working with Docker Images を翻訳してみる



 本ページは、以下のサイトを翻訳したものです。
 Working with Docker Images
 https://docs.docker.com/userguide/dockerimages/



このサイトを翻訳中にDockerfileチューとリアルへのリンクが出てきて
ついそっちを先に訳してしまいました。

以下、翻訳したものです(参照の際は at your own risk でネ)。

-------

Docker イメージの動作


イントロダクションでは、Dockerイメージはコンテナのベースであることを議論しました。前セクションでは、例えばubuntuイメージや training/webapp イメージのような、既存のDockerイメージを使用しました。

Dockerホスト上のイメージをダウンロードしたDockerストアも学習しました。イメージがホスト上に存在しない場合、レジストリ(デフォルトではDocker Hub レジストリ)からダウンロードして使用しました。

このセクションでは、次のようなDockerイメージを探検します:

Dockerホスト上のローカルイメージの管理および動作
基本イメージの作成;
Docker Hub リポジトリへのイメージのアップロード


ホスト上のイメージのリスト


ローカルホスト上に保持しているイメージをリスト表示してみましょう。docker imagesコマンドを次のように使います:

 $ sudo docker images
 REPOSITORY       TAG      IMAGE ID      CREATED      VIRTUAL SIZE
 training/webapp  latest   fc77f57ad303  3 weeks ago  280.5 MB
 ubuntu           13.10    5e019ab7bf6d  4 weeks ago  180 MB
 ubuntu           saucy    5e019ab7bf6d  4 weeks ago  180 MB
 ubuntu           12.04    74fe38d11401  4 weeks ago  209.6 MB
 ubuntu           precise  74fe38d11401  4 weeks ago  209.6 MB
 ubuntu           12.10    a7cf8ae4e998  4 weeks ago  171.3 MB
 ubuntu           quantal  a7cf8ae4e998  4 weeks ago  171.3 MB
 ubuntu           14.04    99ec81b80c55  4 weeks ago  266 MB
 ubuntu           latest   99ec81b80c55  4 weeks ago  266 MB
 ubuntu           trusty   99ec81b80c55  4 weeks ago  266 MB
 ubuntu           13.04    316b678ddf48  4 weeks ago  169.4 MB
 ubuntu           raring   316b678ddf48  4 weeks ago  169.4 MB
 ubuntu           10.04    3db9c44f4520  4 weeks ago  183 MB
 ubuntu           lucid    3db9c44f4520  4 weeks ago  183 MB

ユーザガイドでこれまでに使用したイメージを参照することができます。どのイメージも起動の際にDocker Hubからダウンロードしてきたものです。

リスト上には3つの重要なイメージ情報を読み取ることができます。

  • リポジトリの出自、例「ubuntu
  • 各イメージのタグ、例「14.04
  • 各イメージのID


リポジトリは潜在的に複数の異なる版のイメージを保持しています。このubuntuイメージのケースでは、Ubuntu 10.04、12.04、12.10、13.04、13.10、そして 14.04というバージョンをカバーしています。各バージョンはタグによって特定づけており、次のようなタグづけされたイメージで参照する事ができます:

 ubuntu:14.04

次のように、タグイメージを参照してコンテナを実行します:

 $ sudo docker run -t -i ubuntu:14.04 /bin/bash

もしかわりに「Ubuntu 12.04」イメージを使いたいのであれば:

 $ sudo docker run -t -i ubuntu:12.04 /bin/bash

もしバージョンを特定しないのであれば、ubuntuを使う例として、普通は「ubuntu:latest」イメージを使います。

 Tips:
 「ubuntu:12.04」のような特定タグのイメージの使用を推奨します。いつも使っているイメージのバージョンが何か明確にすることができます。


新しいイメージの取得


新しいイメージをどうやって取得するのでしょうか?Dockerは、ホスト上に存在しないイメージは自動的にダウンロードします。
ただしコンテナの起動の際に時々潜在的に追加されます。もしイメージの事前ダウンロードを実行したい場合は、docker pullコマンドを使います。「centos」イメージをダウンロードシてみましょう。

 $ sudo docker pull centos
 Pulling repository centos
 b7de3133ff98: Pulling dependent layers
 5cc9e91966f7: Pulling fs layer
 511136ea3c5a: Download complete
 ef52fb1fe610: Download complete
 ...
 
 Status: Downloaded newer image for centos

それぞれのレイヤのイメージがダウンロードされ、イメージのダウンロードするまで待機せずにイメージを実行することが可能になります。

 $ sudo docker run -t -i centos /bin/bash
 bash-4.1#


イメージの検索


Dockerの機能の一つは、たくさんの人が様々な目的で構築されたDockerイメージがあります。多くはDocker Hubへアップロードサれています。Docker Hub Webサイト上でこれらのイメージを検索することができます。



 

docker searchコマンドを使えば、コマンドラインからでも検索は可能です。Webアプリケーション開発で使用するRubyとSinatraがインストールされたイメージを探してみましょう。docker searchコマンドを使って、sinatraという用語が含まれるすべてのイメージを検索することができます。


 $ sudo docker search sinatra
 NAME                                   DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
 training/sinatra                       Sinatra training image                          0                    [OK]
 marceldegraaf/sinatra                  Sinatra test app                                0
 mattwarren/docker-sinatra-demo                                                         0                    [OK]
 luisbebop/docker-sinatra-hello-world                                                   0                    [OK]
 bmorearty/handson-sinatra              handson-ruby + Sinatra for Hands on with D...   0
 subwiz/sinatra                                                                         0
 bmorearty/sinatra                                                                      0
 ...


sinatra」という単語を使っているたくさんのイメージを見つけることができました。docker searchコマンドの結果として、イメージの名前、説明、スター数(イメージの社会的人気度-イメージを気に入ったらユーザがスターを与えることができる)、オフィシャル、そして自動化(Automated)ビルドステータスのリストが返ってきます。オフィシャルリポジトリはStackbrewプロジェクトによって構築・管理されています。また自動化(Automated)リポジトリとはイメージのソースや内容が実証されている自動化されたビルド(Automated Builds)です。


ここでは、有効なイメージ群をレビューして「training/sinatra」を使うことを決めました。これまで、2つのイメージリポジトリのタイプを学習してきました。1つは「ubuntu」イメージのような、ベースイメージもしくはルートイメージと呼ばれるものです。これらのイメージは Docker Inc により構築・検証・サポートされています。これらのイメージは単一の単語の名前により識別することができます。

もうひとつは、今回選択した「training/sinatra」イメージのような、ユーザイメージです。ユーザイメージはDockerコミュニティのメンバに所属し、構築・管理されています。ユーザイメージは、ここでは「training」のように、構築した人のユーザ名をプレフィックスとして識別することができます。


イメージのダウンロード(pulling)


docker pull コマンドを使って適当なイメージ、ここでは「training/sinatra」、を識別してダウンロードを実行することができます。

 $ sudo docker pull training/sinatra

チームは自身のコンテナを実行することでイメージを使用することができます。

 $ sudo docker run -t -i training/sinatra /bin/bash
 root@a8cb6ce02d85:/#


自分たちのイメージの作成


チームは「training/sinatra」イメージがかなり使いやすいことがわかりました。しかし、それは彼らが必要とするものではありませんでした。彼らは「training/sinatra」イメージに若干の変更を必要としています。イメージの変更・作成する2つの方法が有ります。
 

  1. イメージから作成したコンテナを変更して新たなイメージとしてコミットする
  2. イメージを作成する手順を定義したDockerfileを使う


イメージの変更およびコミット


イメージを変更するために、最初に更新対象のコンテナを作成する必要があります。


 $ sudo docker run -t -i training/sinatra /bin/bash
 root@0b2616b0e5a8:/#

 注意:
 すぐに必要となるので、作成したコンテナID(0b2616b0e5a8)を書き留めておいてください。

コンテナ上で json gem を追加します。

 root@0b2616b0e5a8:/# gem install json

希望する変更をコンテナにくわえたら、exitコマンドを使ってコンテナから出ましょう。

コンテナには希望する変更を加えたので、docker commitコマンドを使ってコンテナのコピーをイメージとしてコミットすることができます。

 $ sudo docker commit -m "Added json gem" -a "Kate Smith" \
 0b2616b0e5a8 ouruser/sinatra:v2
 4f177bd27a9ff0f6dc2a830403925b5360bfe0b93d476f7fc3231110e7f71b1c

上記のように docker commit コマンドを使いました。その際に「-m」と「-a」の2つのフラグを指定しました。「-m」フラグは、バージョン管理システム上のコミットのように、コミットメッセージの指定を許可します。「-a」フラグは変更者の指定を許可します。

また、(先ほど書き留めたID)0b2616b0e5a8により、作成したいイメージのコンテナを指定します。そしてイメージのターゲットを指定します:

 ouruser/sinatra:v2

このターゲットを詳しく見ていきましょう。我々が書き込んでいるイメージは、新規ユーザ"outeruser"として編成しています。またイメージ名として、ここではオリジナルイメージ名である「sinatra」を指定しました。最後にあるイメージのタグは「v2」と指定しました。

docker imageコマンドを使って新イメージ「ouruser/sinatra」を参照することができます。

 $ sudo docker images
 REPOSITORY          TAG     IMAGE ID       CREATED       VIRTUAL SIZE
 training/sinatra    latest  5bc342fa0b91   10 hours ago  446.7 MB
 ouruser/sinatra     v2      3c59e02ddd1a   10 hours ago  446.7 MB
 ouruser/sinatra     latest  5db5f8471261   10 hours ago  446.7 MB

新イメージを使って新たなコンテナを作成するには、次のように実行します:

 $ sudo docker run -t -i ouruser/sinatra:v2 /bin/bash
 root@78e82f680994:/#

Dockerfileからイメージを構築


docker commitコマンドの利用は、とても簡単なイメージ拡張方法ですが、チーム間でのイメージを開発プロセスで共有するには少々厄介で簡単ではありません。代わりに新しいコマンド、docker build、を使って新規イメージをスクラッチから構築することができます。

docker buildコマンドを実行するには、Dockerにイメージの構築方法を伝えるためのインストラクションの集まりで構成されたDockerfileを作成します。

まず最初にディレクトリを作成しDockerfileを作成しましょう。

 $ mkdir sinatra
 $ cd sinatra
 $ touch Dockerfile

それぞれのインストラクションはイメージの新たなレイヤを作成します。開発チームにおけるSinatraイメージの構築のための簡単な例を見てみましょう。

 # This is a comment
 FROM ubuntu:14.04
 MAINTAINER Kate Smith
 RUN apt-get update && apt-get install -y ruby ruby-dev
 RUN gem install sinatra

Dockerfileが何をしているか見てください。それぞれのインストラクションは文(statement)の先頭にあり、大文字で書かれています。

 INSTRUCTION statement

 注意:
 #を使ってコメントを表示できます。

最初のインストラクション"FROM"はDockerにイメージの元をがなにかを示しています。この場合は「Ubuntu 14.04」をイメージのベースとしています。

次のインストラクション"MAINTAINER"は誰が新イメージを管理しているかを指定しています。

最後に2つのインストラクション"RUN"を定義しています。RUNインストラクションは、パッケージのインストールのような、イメージ内でコマンドを実行します。ここではAPTキャッシュの更新、RubyおよびRubyGemsのインストール、そして sinatora gem をインストールしています。

 注意:
 Dockerfileにはもっとたくさんのインストラクションが使えます




では、ここまでのDockerfiledocker buildコマンドでイメージをビルドしてみましょう。

 $ sudo docker build -t ouruser/sinatra:v2 .
 Sending build context to Docker daemon 2.048 kB
 Sending build context to Docker daemon
 Step 0 : FROM ubuntu:14.04
  ---> e54ca5efa2e9
 Step 1 : MAINTAINER Kate Smith
  ---> Using cache
  ---> 851baf55332b
 Step 2 : RUN apt-get update && apt-get install -y ruby ruby-dev
  ---> Running in 3a2558904e9b
 Selecting previously unselected package libasan0:amd64.
 (Reading database ... 11518 files and directories currently installed.)
 Preparing to unpack .../libasan0_4.8.2-19ubuntu1_amd64.deb ...
 Unpacking libasan0:amd64 (4.8.2-19ubuntu1) ...
 Selecting previously unselected package libatomic1:amd64.
 Preparing to unpack .../libatomic1_4.8.2-19ubuntu1_amd64.deb ...
 Unpacking libatomic1:amd64 (4.8.2-19ubuntu1) ...
 Selecting previously unselected package libgmp10:amd64.
 Preparing to unpack .../libgmp10_2%3a5.1.3+dfsg-1ubuntu1_amd64.deb ...
 Unpacking libgmp10:amd64 (2:5.1.3+dfsg-1ubuntu1) ...
 Selecting previously unselected package libisl10:amd64.
 Preparing to unpack .../libisl10_0.12.2-1_amd64.deb ...
 Unpacking libisl10:amd64 (0.12.2-1) ...
 Selecting previously unselected package libcloog-isl4:amd64.
 Preparing to unpack .../libcloog-isl4_0.18.2-1_amd64.deb ...
 Unpacking libcloog-isl4:amd64 (0.18.2-1) ...
 Selecting previously unselected package libgomp1:amd64.
 Preparing to unpack .../libgomp1_4.8.2-19ubuntu1_amd64.deb ...
 Unpacking libgomp1:amd64 (4.8.2-19ubuntu1) ...
 Selecting previously unselected package libitm1:amd64.
 Preparing to unpack .../libitm1_4.8.2-19ubuntu1_amd64.deb ...
 Unpacking libitm1:amd64 (4.8.2-19ubuntu1) ...
 Selecting previously unselected package libmpfr4:amd64.
 Preparing to unpack .../libmpfr4_3.1.2-1_amd64.deb ...
 Unpacking libmpfr4:amd64 (3.1.2-1) ...
 Selecting previously unselected package libquadmath0:amd64.
 Preparing to unpack .../libquadmath0_4.8.2-19ubuntu1_amd64.deb ...
 Unpacking libquadmath0:amd64 (4.8.2-19ubuntu1) ...
 Selecting previously unselected package libtsan0:amd64.
 Preparing to unpack .../libtsan0_4.8.2-19ubuntu1_amd64.deb ...
 Unpacking libtsan0:amd64 (4.8.2-19ubuntu1) ...
 Selecting previously unselected package libyaml-0-2:amd64.
 Preparing to unpack .../libyaml-0-2_0.1.4-3ubuntu3_amd64.deb ...
 Unpacking libyaml-0-2:amd64 (0.1.4-3ubuntu3) ...
 Selecting previously unselected package libmpc3:amd64.
 Preparing to unpack .../libmpc3_1.0.1-1ubuntu1_amd64.deb ...
 Unpacking libmpc3:amd64 (1.0.1-1ubuntu1) ...
 Selecting previously unselected package openssl.
 Preparing to unpack .../openssl_1.0.1f-1ubuntu2.4_amd64.deb ...
 Unpacking openssl (1.0.1f-1ubuntu2.4) ...
 Selecting previously unselected package ca-certificates.
 Preparing to unpack .../ca-certificates_20130906ubuntu2_all.deb ...
 Unpacking ca-certificates (20130906ubuntu2) ...
 Selecting previously unselected package manpages.
 Preparing to unpack .../manpages_3.54-1ubuntu1_all.deb ...
 Unpacking manpages (3.54-1ubuntu1) ...
 Selecting previously unselected package binutils.
 Preparing to unpack .../binutils_2.24-5ubuntu3_amd64.deb ...
 Unpacking binutils (2.24-5ubuntu3) ...
 Selecting previously unselected package cpp-4.8.
 Preparing to unpack .../cpp-4.8_4.8.2-19ubuntu1_amd64.deb ...
 Unpacking cpp-4.8 (4.8.2-19ubuntu1) ...
 Selecting previously unselected package cpp.
 Preparing to unpack .../cpp_4%3a4.8.2-1ubuntu6_amd64.deb ...
 Unpacking cpp (4:4.8.2-1ubuntu6) ...
 Selecting previously unselected package libgcc-4.8-dev:amd64.
 Preparing to unpack .../libgcc-4.8-dev_4.8.2-19ubuntu1_amd64.deb ...
 Unpacking libgcc-4.8-dev:amd64 (4.8.2-19ubuntu1) ...
 Selecting previously unselected package gcc-4.8.
 Preparing to unpack .../gcc-4.8_4.8.2-19ubuntu1_amd64.deb ...
 Unpacking gcc-4.8 (4.8.2-19ubuntu1) ...
 Selecting previously unselected package gcc.
 Preparing to unpack .../gcc_4%3a4.8.2-1ubuntu6_amd64.deb ...
 Unpacking gcc (4:4.8.2-1ubuntu6) ...
 Selecting previously unselected package libc-dev-bin.
 Preparing to unpack .../libc-dev-bin_2.19-0ubuntu6_amd64.deb ...
 Unpacking libc-dev-bin (2.19-0ubuntu6) ...
 Selecting previously unselected package linux-libc-dev:amd64.
 Preparing to unpack .../linux-libc-dev_3.13.0-30.55_amd64.deb ...
 Unpacking linux-libc-dev:amd64 (3.13.0-30.55) ...
 Selecting previously unselected package libc6-dev:amd64.
 Preparing to unpack .../libc6-dev_2.19-0ubuntu6_amd64.deb ...
 Unpacking libc6-dev:amd64 (2.19-0ubuntu6) ...
 Selecting previously unselected package ruby.
 Preparing to unpack .../ruby_1%3a1.9.3.4_all.deb ...
 Unpacking ruby (1:1.9.3.4) ...
 Selecting previously unselected package ruby1.9.1.
 Preparing to unpack .../ruby1.9.1_1.9.3.484-2ubuntu1_amd64.deb ...
 Unpacking ruby1.9.1 (1.9.3.484-2ubuntu1) ...
 Selecting previously unselected package libruby1.9.1.
 Preparing to unpack .../libruby1.9.1_1.9.3.484-2ubuntu1_amd64.deb ...
 Unpacking libruby1.9.1 (1.9.3.484-2ubuntu1) ...
 Selecting previously unselected package manpages-dev.
 Preparing to unpack .../manpages-dev_3.54-1ubuntu1_all.deb ...
 Unpacking manpages-dev (3.54-1ubuntu1) ...
 Selecting previously unselected package ruby1.9.1-dev.
 Preparing to unpack .../ruby1.9.1-dev_1.9.3.484-2ubuntu1_amd64.deb ...
 Unpacking ruby1.9.1-dev (1.9.3.484-2ubuntu1) ...
 Selecting previously unselected package ruby-dev.
 Preparing to unpack .../ruby-dev_1%3a1.9.3.4_all.deb ...
 Unpacking ruby-dev (1:1.9.3.4) ...
 Setting up libasan0:amd64 (4.8.2-19ubuntu1) ...
 Setting up libatomic1:amd64 (4.8.2-19ubuntu1) ...
 Setting up libgmp10:amd64 (2:5.1.3+dfsg-1ubuntu1) ...
 Setting up libisl10:amd64 (0.12.2-1) ...
 Setting up libcloog-isl4:amd64 (0.18.2-1) ...
 Setting up libgomp1:amd64 (4.8.2-19ubuntu1) ...
 Setting up libitm1:amd64 (4.8.2-19ubuntu1) ...
 Setting up libmpfr4:amd64 (3.1.2-1) ...
 Setting up libquadmath0:amd64 (4.8.2-19ubuntu1) ...
 Setting up libtsan0:amd64 (4.8.2-19ubuntu1) ...
 Setting up libyaml-0-2:amd64 (0.1.4-3ubuntu3) ...
 Setting up libmpc3:amd64 (1.0.1-1ubuntu1) ...
 Setting up openssl (1.0.1f-1ubuntu2.4) ...
 Setting up ca-certificates (20130906ubuntu2) ...
 debconf: unable to initialize frontend: Dialog
 debconf: (TERM is not set, so the dialog frontend is not usable.)
 debconf: falling back to frontend: Readline
 debconf: unable to initialize frontend: Readline
 debconf: (This frontend requires a controlling tty.)
 debconf: falling back to frontend: Teletype
 Setting up manpages (3.54-1ubuntu1) ...
 Setting up binutils (2.24-5ubuntu3) ...
 Setting up cpp-4.8 (4.8.2-19ubuntu1) ...
 Setting up cpp (4:4.8.2-1ubuntu6) ...
 Setting up libgcc-4.8-dev:amd64 (4.8.2-19ubuntu1) ...
 Setting up gcc-4.8 (4.8.2-19ubuntu1) ...
 Setting up gcc (4:4.8.2-1ubuntu6) ...
 Setting up libc-dev-bin (2.19-0ubuntu6) ...
 Setting up linux-libc-dev:amd64 (3.13.0-30.55) ...
 Setting up libc6-dev:amd64 (2.19-0ubuntu6) ...
 Setting up manpages-dev (3.54-1ubuntu1) ...
 Setting up libruby1.9.1 (1.9.3.484-2ubuntu1) ...
 Setting up ruby1.9.1-dev (1.9.3.484-2ubuntu1) ...
 Setting up ruby-dev (1:1.9.3.4) ...
 Setting up ruby (1:1.9.3.4) ...
 Setting up ruby1.9.1 (1.9.3.484-2ubuntu1) ...
 Processing triggers for libc-bin (2.19-0ubuntu6) ...
 Processing triggers for ca-certificates (20130906ubuntu2) ...
 Updating certificates in /etc/ssl/certs... 164 added, 0 removed; done.
 Running hooks in /etc/ca-certificates/update.d....done.
  ---> c55c31703134
 Removing intermediate container 3a2558904e9b
 Step 3 : RUN gem install sinatra
  ---> Running in 6b81cb6313e5
 unable to convert "\xC3" to UTF-8 in conversion from ASCII-8BIT to UTF-8 to US-ASCII for README.rdoc, skipping
 unable to convert "\xC3" to UTF-8 in conversion from ASCII-8BIT to UTF-8 to US-ASCII for README.rdoc, skipping
 Successfully installed rack-1.5.2
 Successfully installed tilt-1.4.1
 Successfully installed rack-protection-1.5.3
 Successfully installed sinatra-1.4.5
 4 gems installed
 Installing ri documentation for rack-1.5.2...
 Installing ri documentation for tilt-1.4.1...
 Installing ri documentation for rack-protection-1.5.3...
 Installing ri documentation for sinatra-1.4.5...
 Installing RDoc documentation for rack-1.5.2...
 Installing RDoc documentation for tilt-1.4.1...
 Installing RDoc documentation for rack-protection-1.5.3...
 Installing RDoc documentation for sinatra-1.4.5...
  ---> 97feabe5d2ed
 Removing intermediate container 6b81cb6313e5
 Successfully built 97feabe5d2ed

docker buildコマンドの引数に「-t」フラグを使って新規イメージは「ouruser」に所属し、「sinatra」というリポジトリ名でタグを「v2」と指定しました。

また「.」を使ってDockerfileのロケーションをカレントディレクトリ上のDockerfileを指定しました。

 注意:
 Dockerfileのパスについても指定可能です。


では、動作時のビルドプロセスについてみていきましょう。Dockerはまず最初にビルドコンテキスト(基本的にはビルドしているディレクトリのコンテンツ)をアップロードします。これは、Dockerデーモンが実際にイメージのビルドを実行するのでローカルコンテキストが必要になるためです。

次に、Dockerfile内のインストラクションが順番に実行されるところをみていきましょう。各ステップで、新規コンテナを構築し、そのコンテナ内でインストラクションを実行し、変更をコミットするところが確認できます-ちょうどdocker commit ワークフローを早い段階で確認できました。すべてのインストラクションの実行がおわると、97feabe5d2ed というイメージ( ouruser/sinatra:v2 としてもタグ付けされる)がのこり、すべての中間コンテナがクリンナップのために削除されました。

 注意:
 ストレージドライバとは関係なく、イメージは最大127レイヤまでしか保持できません。
 この制限は、イメージサイズ全体の最適化をうながすためにグローバルに設定されています。

新しいイメージからコンテナをこうつくできるようになりました。


 $ sudo docker run -t -i ouruser/sinatra:v2 /bin/bash
 root@8196968dac35:/#

 注意:
 ここではイメージ生成のための短い概要だけ紹介しています。
 利用可能な他のインストラクションについては飛ばしました。
 ガイドの後ろのほうでよりおおくのインストラクションについて触れます。
 また、各インストラクションのより詳細な説明や例はDockerfileリファレンスにて
 参照できます。
 明確で、読みやすく、保守しやすいDockerfileの書き方は、
 Dockerfile ベストプラクティスガイドを参照してください。


さらに


さらにもっと学習したい方は、Dockerチュートリアルをご利用ください。


イメージ上にタグをセット


コミット後やビルド後に既存のイメージに対してタグを追加することも可能です。「docker tag」を使います。ouruser/sinatra イメージに新規タグを追加してみましょう。

 $ sudo docker tag 5db5f8471261 ouruser/sinatra:devel

docker tag」コマンドはイメージID(ここでは 5db5f8471261)、ユーザ名、リポジトリ名、新規タグ名が必要です。

docker image」コマンドを使って新しいタグを確認しましょう。

 $ sudo docker images ouruser/sinatra
 REPOSITORY          TAG     IMAGE ID      CREATED        VIRTUAL SIZE
 ouruser/sinatra     latest  5db5f8471261  11 hours ago   446.7 MB
 ouruser/sinatra     devel   5db5f8471261  11 hours ago   446.7 MB
 ouruser/sinatra     v2      5db5f8471261  11 hours ago   446.7 MB


イメージをDocker Hubへプッシュ

ビルドや新規生成した新規イメージを 「docker push」コマンドを使って Docker Hub へプッシュすることができます。 公的あるいは個人的なリポジトリにプッシュして、他の人とイメージを共有することができます。

 $ sudo docker push ouruser/sinatra
 The push refers to a repository [ouruser/sinatra] (len: 1)
 Sending image list
 Pushing repository ouruser/sinatra (3 tags)
 ...


ホストからイメージを削除


コンテナの場合と似たような方法である「docker rmi」コマンドを使って、Dockerホスト上のイメージを削除することもできます。

これ以上必要ないので「training/sinatra」イメージを削除してみましょう。

 $ sudo docker rmi training/sinatra
 Untagged: training/sinatra:latest
 Deleted: 5bc342fa0b91cabf65246837015197eecfa24b2213ed6a51a8974ae250fedd8d
 Deleted: ed0fffdcdae5eb2c3a55549857a8be7fc8bc4241fb19ad714364cbfd7a56b22f
 Deleted: 5c58979d73ae448df5af1d8142436d81116187a7633082650549c52c3a2418f0

 注意:
 ホストからイメージを削除するために、
 「training/sinatra」をベースとする実行中のコンテナがないことを確認して下さい。

次のステップ


これまでは、Dockerコンテナ内の個々のアプリケーションのビルド方法について学習してきました。つぎにDockerコンテナ同士をリンクさせてアプリケーションスタック全体のビルド方法を学習しましょう。

DockerチュートリアルでDockerfileの知識をテストしてみましょう。


コンテナのリンクへ進む。


Dockerfile リファレンスを翻訳してみた

Dockerをはじめた人は自分でイメージを作りたくなると思います。
ユーザガイドによれば、作成には2つの選択肢、シェルをrunしてインストール手順を手動で実行して最後commitするか、Dockerfileでドカっとつくるかのどちらかになります。

で近年偉い人がおっしゃる継続的デプロイっていうやつを実現するには、Dockerfileの書き方を勉強しなくてはなりません。

でも..日本語情報が少ない..

..ので本家サイトにある以下のページを翻訳してみました。

 Docker: Dockerfile Reference
 https://docs.docker.com/reference/builder/


翻訳してわかったことは幾つもありました。

  • キャッシュの動きを理解しないとyum update -y/apt-get dist-upgrade -yが..
  • ENV指定とOS側の環境変数が混同しやすい
  • どうもビルドコンテキストというのはADDやCOPYする元ディレクトリ/ファイル群
  • ビルドコンテキストの指定でのWORkdirの取り扱いに注意
  • VOLUMEでホスト側ファイルシステムをマウントする
  • ビルド時、コンテナとして実行時に実行するコマンドの使い分けを理解してないとやばい
  • shellフォームとexecフォームは書式の違いだけでないこと
  • ADDやCOPY時のUID/GIDのパーミッションがどうなるか
  • CMD/ENTRYPOINTで実行されるプロセスのPIDがどうなるか
  • そしてCMD/ENTRYPOINTにスクリプトをかませるとき、Unixのシグナルをプロセスに認識させるためexecやgosuを使わないとダメ
  • ベースイメージを作成するDockerfileをつくるにはONBUILDも駆使しないといけないかも





っていうか、VMwareやXen、kvmなんかで作成する仮想マシンのまるまる代替に
Dockerコンテナがそのままなるわけないことを改めて理解させられた..


以下、翻訳した日本語です。
長文だったので、結構疲れている時間の翻訳が超微妙です。
誤りなどがあればコメントにて指摘してください。

あと、参考にする場合は At your own risk でおねがいします。

なお、Dockerユーザガイドの勝手翻訳も有ります。

-----

Dockerfile リファレンス


DockerはDockerfileからインストラクションを読み込んでイメージ度自動ビルドすることができます。Dockerfileはテキストファイルで、Dockerイメージを通常の手動ビルドするすべてのコマンドが含まれています。ターミナルから docker buildコマンドを呼び出すことで、連続でインストラクションを実行し段階的にイメージをビルドすることができます。

このページではDockerfileに記述可能なすべてのインストラクションについて説明します。
明確に、読みやすい、メンテナンスしやすいDockerfileを書くための更なるヘルプのために、Dockerfileベストプラクティスガイドも執筆しました。最後に、Dockerfileチュートリアルを使って、あなたのDockerfileに関する知識をテストすることができます。

訳者注:
上記リンクの「Dockerfileチュートリアル」は
本当にテスト問題が出題されます。


使い方


ソースリポジトリからイメージをビルドするために、あなたのリポジトリのルートにDockerfileと呼ばれる記述ファイルを作成します。このファイルにはイメージを組み立てるための手順を記述します。

そして、docker buildコマンドの引数としてソースリポジトリへのパスを指定して呼び出します(例: .):

 $ sudo docker build .

ソースリポジトリへのパスはビルドのコンテキストがどこにあるかを定義します。ビルドは、CLIではなく、Dockerデーモンにより実行されます。このためすべてのコンテキストはデーモンへ転送されるべきです。Docker CLI はコンテキストをデーモンへ送信される際に"Sending build context to Docker daemon(ビルドコンテキストをDockerデーモンへ送信中)"とレポートします。

 警告:
 ソースリポジトリとしてルートディレクトリ「/」の使用は避けてください。
 docker build コマンドは、ビルドコンテキストとしてのDockerfileを含む
 どんなディレクトリでも(すべてのサブディレクトリを含む)使用します。
 ビルドコンテキストはイメージをビルドする前にDockerデーモンへ送信します。
 そこで/をソースリポジトリとして使う場合、あなたのハードドライブのすべての
 コンテンツををデーモン(デーモンが実行中のマシン)へ送信します。
 それはおそらくあなたが望まないことでしょう。

一般的には、空のディレクトリ上にそれぞれのDockerfileを置くことがもっともよい方法です、そしてDockerfileをおいたディレクトリにビルドに必要なファイル群(ADD元のファイルなど)を配置するだけです。将来のビルドのスピード向上のために、同じディレクトリに .dockerignore ファイルを追加することでファイルやディレクトリを除くことが可能です。

ビルドが成功した場合新規イメージを保存するリポジトリやタグを指定することができます:

 $ sudo docker build -t shykes/myapp .

Dockerデーモンは一つづつステップを実行します、そして最後に新規イメージのIDを出力する前に、必要な場合は結果を新規イメージとしてコミットします。Dockerデーモンは送信したコンテキストを自動でクリーンナップします。

それぞれのインストラクションは独立して実行していることに注意してください、そしてこのことは作成された新規イメージで発生します-このため「RUN cd /tmp」は次のインストラクションに反映しません。

Dockerは可能な限り中間イメージを再利用します、これにより docker build コマンドはかなり高速化します(ビルド中に「Using cache」と表示されます-詳細はDockerfile ベストプラクティスガイドを参照のこと):

 $ sudo docker build -t SvenDowideit/ambassador .
 Uploading context 10.24 kB
 Uploading context
 Step 1 : FROM docker-ut
  ---> cbba202fe96b
 Step 2 : MAINTAINER SvenDowideit@home.org.au
  ---> Using cache
  ---> 51182097be13
 Step 3 : CMD env | grep _TCP= | sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/'  | sh && top
  ---> Using cache
  ---> 1a5ffc17324d
 Successfully built 1a5ffc17324d

ビルド終了したら、リポジトリからレジストリへの push を調べる準備ができます。

フォーマット


Dockerfileのフォーマットは以下のとおりです:

 # Comment
 INSTRUCTION arguments

インストラクションには大文字小文字の区別はありませんが、より簡単に項目(arguments)と区別するために大文字での記述が慣例となっています。

DockerはDockerfileを上から順番に実行します。最初のインストラクションはベースイメージの指定のための"FROM"であるべきです。

Dockerは#で始まる行をコメントとして扱います。#は行内のどこでも項目(arguments)とみなされます。次のような文章も許可されます:

 # Comment
 RUN echo 'we are running some # of cool things'

イメージのビルドのためにDockerfileで使うことのできるインストラクション群を紹介します。

環境変数の置換



 注意:
 バージョン1.3より前では、Dockerfile環境変数は、
 後述のように置換される点では、
 同様に取り扱われていました。
 しかしインストラクションとしての環境変数の
 置換の正式な定義がありませんでした。
 1.3より後のバージョンでは、
 この振る舞いは維持されており、正式なものです。

(ENV文で定義された)環境変数は、Dockerfileにより解釈される変数として特定のインストラクションも使用できます。エスケープ故事もまた文章内の変数のような構文を含めるために取り扱われます。


環境変数は、Dockerfile内では$variable_name もしくは ${variable_name}のどちらか一方で記述されます。それらは同等に扱われます。そして中括弧構文は一般的に問題に対処するために、${foo}_barのように、空白無しの変数名で使用されます。


エスケープ処理は変数の前に\を追加することで可能です:例として、\$foo もしくは \${foo}$foo${foo} というリテラルに各々置き換えられます。

例(解釈後の環境変数置換は #の後に表示):

 FROM busybox
 ENV foo /bar
 WORKDIR ${foo}   # WORKDIR /bar
 ADD . $foo       # ADD . /bar
 COPY \$foo /quux # COPY $foo /quux

Dockerfile内で環境変数を取り扱うインストラクションは、次の通り:

  • ENV
  • ADD
  • COPY
  • WORKDIR
  • EXPOSE
  • VOLUME
  • USER

ONBUILDインストラクションは(上記のインストラクションでさえ)環境変数の置換をサポートしていません。

.dockerignore ファイル


.dockerignore と名付けられたファイルがソースリポジトリ上に存在するならば、改行でセパレートされた除外パターンのリストと解釈されます。除外パターンとマッチしたソースディレクトリのファイルやディレクトリはコンテキストから外されます。その際にはGoのfilepath.Matchルールが使用されます。

 注意:
 .dockerignore ファイルは、
 Dockerfileや.dockerignoreを無視のためでも使用可能です。
 これは、ビルドコンテキストのルートからファイルを
 新規コンテナへコピーする際に、Dockerfile.dockerignore
 含めたくない場合(例: ADD . /someDir/)に役に立ちます。

次の例では、.dockerignoreファイルにて.gitディレクトリをコンテキストから外しています。これはコンテキストのアップロードのサイズ変更に効果が有ります。

 $ sudo docker build .
 Uploading context 18.829 MB
 Uploading context
 Step 0 : FROM busybox
  ---> 769b9341d937
 Step 1 : CMD echo Hello World
  ---> Using cache
  ---> 99cc1ad10469
 Successfully built 99cc1ad10469
 $ echo ".git" > .dockerignore
 $ sudo docker build .
 Uploading context  6.76 MB
 Uploading context
 Step 0 : FROM busybox
  ---> 769b9341d937
 Step 1 : CMD echo Hello World
  ---> Using cache
  ---> 99cc1ad10469
 Successfully built 99cc1ad10469


FROM



 FROM

もしくは

 FROM :

FROMインストラクションは後続のインストラクション軍に対してベースイメージをセットします。このように、正しいDockerfileは、最初のインストラクションとしてFROMを指定しなくてはなりません。イメージは有効であればどんなものでもかまいません-最も簡単な方法は公式リポジトリからイメージをpullして始めることです。

FROMは、Dockerfile 内で最初の非コメントのインストラクションでなければなりません。

複数のイメージを構築する場合は単一のDockerfileに複数回FROMが登場することが有ります。それぞれのFROMコマンドの前のコミット処理による最後のイメージIDアウトプットを書き留めておいてください。

もしFROMインストラクションにタグをしてしなければ、latestを指定したことになります。また指定したタグが存在しないものであった場合、エラーとなります。

MAINTAINER



 MAINTAINER <氏名>

MAINTAINERインストラクションはイメージを作成した著者名フィールドのセットを許可します。

RUN


RUN には2つのフォームがあります:

RUN <コマンド> (コマンドはシェル上 /bin/sh -c で実行される:shellフォーム)
RUN ["executable", "param1", "param2"] (execフォーム)

RUNインストラクションは現在のイメージのトップ上の新規レイヤでコマンドを実行し、結果をコミットします。結果がコミットされたイメージはDockerfileの次のステップで使用されます。

ソースコントロールのように、Dockerのコアコンセプトに従ったレイヤ化RUNインストラクションやコミット生成は低コストで、コンテナはイメージヒストリのどのポイントからも生成できます。

execフォームは、シェルストリングを台無しにすることの回避を可能にします、また /bin/sh を含まないベースイメージを使ってコマンドをRUNすることを可能にします。

 注意:
 (/bin/sh以外の)異なるシェルを使うために、
 希望するシェルを指定したexecフォームを使います。
 例: RUN ["/bin/bash", "-c", "echo hello"]


 注意:
 exec フォームはJSON配列として構文解釈されます、
 文字の前後にシングルクォート(')ではなく
 ダブルクォート(")を必ず使用してください。


 注意:
 execフォームは、shellフォームとは異なり、
 コマンドシェルを呼び出しません。
 これは通常のシェル実行が発生しないことを意味します。
 例えば、RUN [ "echo", "$HOME" ] における $HOME は変数値に置換されません。
 もしシェル実行シたいのであればshellフォームか、シェルの直接実行
 (例:RUN [ "sh", "-c", "echo", "$HOME" ])のどちらかを使いましょう。

RUNインストラクションのキャッシュは次のビルドの間自動的に無効ではなくなります。「RUN apt-get dist-upgrade -y」のようなインストラクションのキャッシュは次のビルドでも再利用されます。RUNインストラクションのキャッシュは、例えば「docker build --no-cache」のように、「--no-cache」フラグを使うことで無効にすることができます。

詳細は Dockerfile ベストプラクティスを参照してください。

RUN インストラクションのキャッシュは、ADD インストラクションにより無効にすることができます。詳細はADDセクションを確認して下さい。

既知の問題(RUN)


Issue 783は、AUFS ファイルシステム使用の際に発生するファイルパーミッションに関する問題についてです。たとえば、rmコマンドによるファイル削除中に気づくかもしれません。Issue783 には回避策の記述があります。

CMD


CMDインストラクションは3つのフォームがあります。

CMD ["executable","param1","param2"] (exec フォーム、おすすめ)
CMD ["param1","param2"] (ENTRYPOINTへのデフォルトパラメータとして)
CMD command param1 param2 (shell フォーム)

Dockerfileには1つだけCMDインストラクションが存在できます。もし1つ以上のCMDを記述した場合、最後のCMDインストラクションが有効になります。

CMDの主な目的は、実行コンテナのためのデフォルトを提供するためです。これらのデフォルトは実行可能なものを含みます、もしくは実行可能なものを省略可能です、そしてその場合には同様にENTRYPOINTインストラクションを指定しなくてはなりません。

 注意:
 もしENTRYPOINTインストラクションのデフォルト引数を
 提供するためにCMDを使用したならば、
 CMDENTRYPOINT 両方のインストラクションは
 JSON配列フォーマットで指定すべきです。


 注意:
 execフォームはJSON配列として構文解析されます。
 そしてそれはシングルクォート(')ではなく
 ダブルクォート(")を使用しなければならないことを意味しています。


 注意:
 shellフォームとは異なり、execフォームはコマンドシェルを呼び出しません。
 これは通常のシェル実行が発せしないことを意味しています。
 例えば、CMD [ "echo", "$HOME" ] における$HOMEは変数値に置換されません。
 もしシェル実行したいのであれば、shellフォームか、
 CMD [ "sh", "-c", "echo", "$HOME" ] のようにシェルを直接実行するか
 どちらかを使用してください。

shell もしくは exec フォーマットで使用された場合、CMD インストラクションはイメージ動作時に実行されるコマンドをセットします。

CMDのshellフォームを使うのであれば、コマンド(CMDの次の項目)は「/bin/sh -c」上で実行します:

 FROM ubuntu
 CMD echo "This is a test." | wc -

もしシェルなしでコマンドを実行したのであれば、JSON 配列形式として表現し、実行可能ファイルをフルパスで指定しなくてはなりません。この配列形式はCMDの推奨フォーマットです。どんな追加のパラメータも配列内の文字列として独立して表現すべきです:

 FROM ubuntu
 CMD ["/usr/bin/wc","--help"]

もしコンテナで毎回同じ実行可能ファイルを実行するのであれば、CMD と組み合わせて ENTRYPOINT を使うことを考慮すべきです。

もし docker run の引数として指定した場合、CMD内に指定したデフォルトをオーバライドします。

 注意:
 RUNCMD を混同しないでください。
 RUNは実際にコマンドを実行し、結果をコミットします;
 CMD はビルド時には何も実行しませんが、
 イメージのために意図されたコマンドを指定します。


EXPOSE



 EXPOSE [...]

EXPOSE インストラクションは、Dockerに実行中コンテナがlistenしているネットワークポートを知らせます。Dockerはこの情報を使ってリンク(Dockerユーザガイド参照)を使ってコンテナと内部連結します。そして「-P」フラグ使用の際にどのポートをホストへ露出させるかを定義します。

 注意:
 EXPOSEは、ホストへ露出されるポートがどれか、
 もしくはデフォルトでホストからアクセス可能なポートについては、
 定義しません。


ENV



 ENV
 ENV = ...

ENV インストラクションは環境変数とその値をセットします。この値はすべての"子孫"のDockerfileコマンドの環境変数となります、そしてそれらの多くはインラインで置き換え可能です。

ENV インストラクションには2つのフォームがあります。最初のフォーム、「ENV 」は、単一の環境変数に1つの値をセットします。最初の空白の後のすべての(空白やクォートのようなキャラクタを含む)文字列はとして扱われます。

2番めのフォーム、「ENV =...」は一度に複数の値をセットできます。2番めのフォームは等号(=)を構文中に使用します、この点が最初のフォームと異なります。コマンドラインにおける構文解析のように、値の中に空白を含めるためにクォートやバックスラッシュが使用できます。

 例:
 ENV myName="John Doe" myDog=Rex\ The\ Dog \
     myCat=fluffy

および

 例:
 ENV myName John Doe
 ENV myDog Rex The Dog
 ENV myCat fluffy

は最終的に同じ結果となりますが、最初のフォームは1つのレイヤ内ですべて処理します。

ENV を使った環境変数セットは、イメージが生じてコンテナが実行されている間永続化されます。docker inspectコマンドを使って値を確認することができます。また「docker run --env =」を使用して変更することができます。

 注意:
 環境変数の永続性は予想外の影響を起こすことがあります。
 例えば、「ENV DEBIAN_FRONTEND noninteractive」は
 Debianベースのイメージの apt-get ユーザを
 混乱させることがあります。
 単一のコマンドに対する環境変数をセットするには、
 「RUN = 」を使用してください。


ADD


ADD には2つのフォームがあります:

 ADD ...
 ADD [""... ""] (このフォームの場合は、空白を含むパスも指定可能)

ADD インストラクションは から新規ファイル、ディレクトリ、リモートファイルのURLフォームを、コンテナ上のファイルシステムのパス へコピーします。

複数の リソースを指定することができますが、もしそれらがファイルもしくはディレクトリであれば、ビルドされた(ビルドのコンテキスト)ソースディレクトリへ関連付けされるべきです。

それぞれの はワイルドカードを含めることができ、Go の filepath.Match ルールを使ったマッチングしたものに対して実行します。多くのコマンドラインの用途のために、これは予想どおりに振る舞うべきです。例えば:

 ADD hom* /mydir/        # "hom"で始まるすべてのファイルを追加する
 ADD hom?.txt /mydir/    # ?は適当な1文字に置換される

は絶対パス、もしくは WORKDIR と関連したパスで、ソースが対象のコンテナ内へコピーされます。

 ADD test aDir/          # "test" を `WORKDIR`/aDir/ へ追加する

すべての新規のファイルおよびディレクトリは、UIDおよびGIDが0(スーパーユーザ)で作成されます。

がリモートファイルURLである場合、追加先はパーミッションが600(ユーザのみ読み書き可能)となります。もし取得したリモートファイルがHTTP Last-Modified ヘッダを保有していたら、ヘッダのタイムスタンプは追加先のファイル上のmtimeの値として使用されます。そして、ADD 中に処理される他のどんなファイルも、mtime はいつファイルが変更されたかどうかやキャッシュが更新されたかの決定に使用されます。

 注意:
 もし標準入力慶友でDockfileを指定してビルド
 (docker build - < somefile)した場合、
 ビルドコンテキストがありません。
 そして DockerfileADD インストラクションベースの
 URL でのみ構成されます。
 また標準入力経由で圧縮アーカイブも指定でき
 (docker build - < archive.tar,gz)、
 アーカイブのルートの Dockerfile やアーカイブの残りは
 ビルドのコンテキストとして使用されます。


 注意:
 URL ファイルが認証によりプロテクトされているのであれば、
 ADD インストラクションは認証をサポートしていないため、
 RUN wgetRUN curl もしくはそのほかのコンテナ上のツールを
 使う必要があります。


 注意:
 もし コンテンツが変更されているならば、
 一番最初に ADD インストラクションに遭遇するとすべての後続の
 Dockerfile上のインストラクションに対してキャッシュを無効化します。
 これはRUNインストラクションのキャッシュ無効化を含みます。
 詳細はDockerfileベストプラクティスガイドを参照してください。

コピーは、以下の規則に従います:

  • パスはビルドコンテキストの内部を指定すべきです:「ADD ../something /something」は実行できません、これはdocker buildの最初のステップが、コンテキストディレクトリ(およびサブディレクトリ)をdockerデーモンへ送信するためです。


  • もし URL であり の最後がスラッシュで終わっていないならば、ファイルはURLからダウンロードされ へコピーします。


  • もし URL であり の最後がスラッシュで終わっているならば、filenameURLから推断され、ファイルは / へダウンロードされます。例えば、「ADD http://example.com/foobar /」はファイル「/foobar」を作成します。この場合(http://example.com では動作しません)、適切な filename が発見できるように、URLは浅薄ではないパスを指定しなくてはなりません。


  • もし がディレクトリであれば、ファイルシステムのメタデータを含む、ディレクトリのコンテンツすべてがコピーされます。


 注意:
 ディレクトリ自身はコピーされません、コンテンツだけです。


  • もし がローカルの認められた圧縮フォーマット(identity、gzip、bzip2、もしくはxz)tarアーカイブであるならば、ディレクトリとして解凍されます。リモートURLからのリソースは解凍されません。ディレクトリがコピーもしくは回答されたら、同じ振る舞い(tar -x)を実行します:結果は以下の集合になります:

  1. 追加先パスに存在するなんでも、そして
  2. ソースツリーのコンテンツ(ファイル対ファイルの基本に則って競合を解決する)


  • もし が他の種類のファイルであるならば、メタデータとともに個別にコピーされます。この場合、もし がスラッシュ(/)で終わっているならば、ディレクトリとして扱われます、そして のコンテンツは/ベース()へ書き込まれます。


  • もしリソースが、ディレクトもしくはワイルドカードを使って、複数指定されているならば、 はディレクトリであるべきです、そしてスラッシュ(/)で終わっていなければなりません。


  • もし がスラッシュで終わっていなければ、通常のファイルとして扱われます、そして のコンテンツが へ書き込まれます。


  • もし が存在しないならば、パス内のすべての存在しないディレクトリとともに作成されます。


COPY


COPY には以下の2つのフォームがあります:

 COPY ...
 COPY [""... ""] (このフォームはパスに空白文字を含めることができます)

COPY インストラクションはから新たにファイルやディレクトリをコピーし、コンテナ上のファイルシステムの パスに追加します。

複数の リソースを指定することもできます、がビルドされたソースディレクトリ(ビルドコンテキスト)に関連付けしなければなりません。

それぞれの にはワイルドカードを含めることができます、そしてそれらはGoのfilepath.Matchルールに従ってマッチングします。多くのコマンドラインの使い方のように予想された動作をします、例えば:

 COPY hom* /mydir/        # "hom"で始まるすべてのファイルをコピーする
 COPY hom?.txt /mydir/    # ? は任意の1文字に置換される

は絶対パス、もしくはWORKDIRに関連づいたパスです。ソースはコピー先のコンテナ内部にコピーされます。

 COPY test aDir/          # `WORKDIR`/aDir/ に "test"を追加する

すべての新規のファイルやディレクトリはUIDおよびGIDが0(スーパーユーザ)として作成されます。

 注意:
 もし標準出力を使ってビルドする(docker build - < somefile)ならば、
 ビルドコンテキストが存在しないので、COPY が使用できません。

コピーは次のルールに従います:

  • パスはビルドコンテキスト内部を指定しなければなりません:「COPY ../something /something」と記述することはできません、なぜならdocker buildコマンドの最初のステップはコンテキストの(サブディレクトリを含む)ディレクトリをdockerデーモンへ送信するためです。


  • もし がディレクトリであれば、ディレクトリのコンテンツすべてがコピーされます。


 注意:
 ディレクトリ自身はコピーされません、コンテンツだけです。


  • もし その他の種類のファイルであるならば、メタデータと一緒に個別にコピーされます。このケースで、 がスラッシュ(/)で終わっているのであれば、ディレクトリとして取り扱い、 のコンテンツが /ベース()へ書き込まれます。


  • ディレクトリもしくはワイルドカード使用のどちらかで複数の リソースを指定した場合は、 はディレクトリであるべきです、そして指定の最後はスラッシュ(/)で終わっているべきです。


  • もし の指定がスラッシュで終わっていない場合は、通常のファイルとして取り扱い のコンテンツが へ書き込まれます。


  • もし が存在しない場合は、パス内のすべての存在しないディレクトリが作成されます。


ENTRYPOINT


ENTRYPOINT には2つのフォームがあります:

 ENTRYPOINT ["executable", "param1", "param2"] (推奨: exec フォーム)
 ENTRYPOINT command param1 param2 (shell フォーム)

ENTRYPOINT は実行可能なイメージとしてコンテナ実行の設定を許可します。

次の例は、デフォルトで nginx を開始し、ポート80番で待ち受けます:

 docker run -i -t --rm -p 80:80 nginx

docker run 」のコマンドライン引数は、ENTRYPOINT execフォームのすべての要素の後に追加されます、そしてCMDを使って指定したすべての要素をオーバライドします。引数をエントリーポイントに追加することを許可します。例:「docker run -d」は、「-d」の引数をエントリーポイントへ追加します。「docker run --entrypoint」フラグを使うとENTRYPOINTインストラクションをオーバライドすることができます。

shell フォームは、CMD やコマンドラインの引数が使用されることを防ぎますが、ENTRYPOINTを「/bin/sh -c」のサブコマンドとして開始(シグナルをパスしない)する欠点があります。これは、コンテナのPID1にならない-そして、UNIXシグナルを受け取れない-ことを意味します。このため、SIGTERMを「docker stop <コンテナ>」から受け取れません。

Dockerfile の最後の ENTRYPOINT インストラクションだけ有効です。

exec フォーム ENTRYPOINT サンプル


ほぼ安定したデフォルトコマンドやパラメータを指定する際には、exec フォームで ENTRYPOINTを指定します。CMDのどちらかのフォームを使って変更のありそうなデフォルト値を設定します。

 FROM ubuntu
 ENTRYPOINT ["top", "-b"]
 CMD ["-c"]

コンテナ実行した際、topではプロセスだけ参照することができます:

 $ docker run -it --rm --name test  top -H
 top - 08:25:00 up  7:27,  0 users,  load average: 0.00, 0.01, 0.05
 Threads:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
 %Cpu(s):  0.1 us,  0.1 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
 KiB Mem:   2056668 total,  1616832 used,   439836 free,    99352 buffers
 KiB Swap:  1441840 total,        0 used,  1441840 free.  1324440 cached Mem

   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
     1 root      20   0   19744   2336   2080 R  0.0  0.1   0:00.04 top

結果について更に調べるには、「docker exec」を使用します:


 $ docker exec -it test ps aux
 USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
 root         1  2.6  0.1  19752  2352 ?        Ss+  08:24   0:00 top -b -H
 root         7  0.0  0.1  15572  2164 ?        R+   08:25   0:00 ps aux

そして、topに対して「docker stop test」を使ってエレガントにシャットダウンを求めることができます。

次のDockerfileでは、ENTRYPOINTを使ってフォアグラウンドでApacheを実行しています(PID 1として):

 FROM debian:stable
 RUN apt-get update && apt-get install -y --force-yes apache2
 EXPOSE 80 443
 VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
 ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

もし単一の実行可能イメージのためにスタータースクリプトが必要であれば、「exec」と「gosu」コマンドを使えばUnixシグナルを最終実行対象が受け取ることを確実にすることができます:

 #!/bin/bash
 set -e

 if [ "$1" = 'postgres' ]; then
     chown -R postgres "$PGDATA"

     if [ -z "$(ls -A "$PGDATA")" ]; then
         gosu postgres initdb
     fi

     exec gosu postgres "$@"
 fi

 exec "$@"


最後に、もしシャットダウン時にいくつかの追加のクリンナップ(もしくは、他のコンテナとの通信)が必要であれば、もしくは1つ以上の実行コンテナと同期しているのであれば、ENTRYPOINT スクリプトはUnixシグナルを受け取りを確実にしなくてはなりません、シグナルを渡して、次にいくつかの仕事をします:

 #!/bin/sh
 # 注意:shを使って書かれています、このためbusyboxコンテナでも動作します

 # サービス停止後マニュアルクリンナップが必要であれば、
 #、もしくは1つのコンテナで複数のサービスを開始する必要があれば
 # trapを使ってください。
 trap "echo TRAPed signal" HUP INT QUIT KILL TERM

 # ここでサービスをバックグラウンドで開始します
 /usr/sbin/apachectl start

 echo "[hit enter key to exit] or run 'docker stop '"
 read

 # サービスを停止してクリンナップをここで実施してます
 echo "stopping apache"
 /usr/sbin/apachectl stop

 echo "exited $0"

このイメージを「docker run -it --rm -p 80:80 --name test apache」で実行するならば、「docker exec」もしくは「docker top」コマンドでコンテナのプロセスを解決することができます、そしてApache停止のスクリプトへ問い合わせてください:

 $ docker exec -it test ps aux
 USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
 root         1  0.1  0.0   4448   692 ?        Ss+  00:42   0:00 /bin/sh /run.sh 123 cmd cmd2
 root        19  0.0  0.2  71304  4440 ?        Ss   00:42   0:00 /usr/sbin/apache2 -k start
 www-data    20  0.2  0.2 360468  6004 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
 www-data    21  0.2  0.2 360468  6000 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
 root        81  0.0  0.1  15572  2140 ?        R+   00:44   0:00 ps aux
 $ docker top test
 PID                 USER                COMMAND
 10035               root                {run.sh} /bin/sh /run.sh 123 cmd cmd2
 10054               root                /usr/sbin/apache2 -k start
 10055               33                  /usr/sbin/apache2 -k start
 10056               33                  /usr/sbin/apache2 -k start
 $ /usr/bin/time docker stop test
 test
 real    0m 0.27s
 user    0m 0.03s
 sys 0m 0.03s


 注意:
 「--entrypoint」でENTRYPOINT設定をオーバライド可能ですが、
 これはバイナリに対してexec(sh -cを使ってではなく)する場合のみ可能です。


 注意:
 execフォームはJSONフォームとして解釈されます。
 そしてそれは文字の前後にシングルクォート(')ではなく、
 ダブルクォート(")を使わなければならないことを意味します。

 注意:
 shellフォームとは異なり、execフォームはコマンドシェルを起動しません。
 これは通常のシェル実行が発生しないことを意味しています。
 例えば「ENTRYPOINT [ "echo", "$HOME" ] 」では、$HOMEの環境変数値へ
 置換しないことを意味しています。
 もしshell実行を望むのであれば、shellフォームを使用するか、
 直接shellを実行するかのどちらかです
 (例: ENTRYPOINT [ "sh", "-c", "echo", "$HOME" ])。
 ENVを使っているDockerfileで定義した変数は、
 Dockerfileパーサーにより置換されます

Shell フォーム ENTRYPOINT サンプル


シェル実行を使用してシェル環境変数を置換するために、ENTRYPOINT に明確な文字列を指定して「/bin/sh -c」を実行します。そして、CMD や「docker run」のコマンドライン引数を無視します。
docker stop」がどんなに長く実行している ENTRYPOINT の実行対象に対しても正確なシグナル送信を確実にするために、「exec」を使って開始することを忘れないで下さい:

 FROM ubuntu
 ENTRYPOINT exec top -b


このイメージを実行する場合は、PID 1のプロセスを確認します:

 $ docker run -it --rm --name test top
 Mem: 1704520K used, 352148K free, 0K shrd, 0K buff, 140368121167873K cached
 CPU:   5% usr   0% sys   0% nic  94% idle   0% io   0% irq   0% sirq
 Load average: 0.08 0.03 0.05 2/98 6
   PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
     1     0 root     R     3164   0%   0% top -b

docker stop」上でとちらがきれいにexitしたか:

 $ /usr/bin/time docker stop test
 test
 real    0m 0.20s
 user    0m 0.02s
 sys 0m 0.04s

もしENTRYPOINTのはじめに「exec」追加を忘れたら:

 FROM ubuntu
 ENTRYPOINT top -b
 CMD --ignored-param1

次のように動作します(次のステップで名前を与えます):

 $ docker run -it --name test top --ignored-param2
 Mem: 1704184K used, 352484K free, 0K shrd, 0K buff, 140621524238337K cached
 CPU:   9% usr   2% sys   0% nic  88% idle   0% io   0% irq   0% sirq
 Load average: 0.01 0.02 0.05 2/101 7
   PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
     1     0 root     S     3168   0%   0% /bin/sh -c top -b cmd cmd2
     7     1 root     R     3164   0%   0% top -b

topの出力結果からENTRYPOINTPID1ではないことがわかります。

もし「docker stop test」を実行したら、コンテナはきれいに終了しません-「stop」コマンドによりタイムアウト後にSIGKILL送信を強制されます:

 $ docker exec -it test ps aux
 PID   USER     COMMAND
     1 root     /bin/sh -c top -b cmd cmd2
     7 root     top -b
     8 root     ps aux
 $ /usr/bin/time docker stop test
 test
 real    0m 10.19s
 user    0m 0.04s
 sys 0m 0.03s


VOLUME



 VOLUME ["/data"]

VOLUME インストラクションは、指定した名前のマウントポイントを作成し、そしてホストやその他のコンテナからボリュームの外部マウントを維持することを示しています。設定値は、「VOLUME ["/var/log/"]」のようなJSON配列、もしくは「VOLUME /var/log」や「VOLUME /var/log /var/db」のような複数の引数の文字です。より詳しい情報/例や、Dockerクライアント経由のマウントインストラクションはドキュメント「Share Directories via Volumes(ボリューム経由のディレクトリ共有)」を参照してください。

 注意:
 リストはJSON配列として解釈されます、
 そしてそれは単語の前後にはシングルクォート(')ではなく
 ダブルクォート(")を使わなくてはならないことを意味します。


USER



 USER daemon

USER インストラクションは、イメージ実行や Dockerfile RUN CMDENTRYPOINT インストラクションの実行時使用するユーザ名もしくは UID を指定します。

WORKDIR



 WORKDIR /path/to/workdir

WORKDIR インストラクションは、DockerfileRUNCMDENTRYPOINT COPYADD インストラクションのためのワーキングディレクトリを指定します。

1つのDockerfile 内で複数回使用できます。相対パスであれば、前のWORKDIR インストラクションのパスに対する相対パスとなります。例えば:

 WORKDIR /a
 WORKDIR b
 WORKDIR c
 RUN pwd

この Dockerfile の最後の「pwd」コマンドは「/a/b/c」と出力します。

WORKDIR インストラクションはその前にENVで指定した環境変数を解決することができます。Dockerfile内で明確に環境変数だけを使うことができます。例えば:

 ENV DIRPATH /path
 WORKDIR $DIRPATH/$DIRNAME
 RUN pwd

この Dockerfile の最後の「pwd」コマンドは「/path/$DIRNAME」と出力します。

ONBUILD



 ONBUILD [INSTRUCTION]

その他のビルドのためにベースとして使使用されるイメージの場合、ONBUILD インストラクションはイメージへあとで実行するためのトリガインストラクションを追加します。トリガは、下流のDockerfileFROMインストラクションの直後に挿入されたかのように、下流のビルドのコンテキスト内で実行されます。

どんなビルドコンストラクションもトリガとして登録されます。

これは、例えばアプリケーションビルド環境やユーザ個別に設定するデーモンなど、ほかのイメージをビルドするためのベースとして使用されるイメージをビルドする場合、とても便利です。

例えば、特定のディレクトリへアプリケーションソースコードの追加して後で呼び出されるビルドスクリプトが必要となる、再利用可能なPythonアプリケーションビルダである場合のイメージです。ADDRUNを今すぐに実行できません、なぜならまだアプリケーションソースコードにアクセスしません、そして各アプリケーションビルドによって異なるからです。単純にアプリケーションをコピー&ペーストするためのボイれープレートDockerfileを使ってアプリケーション開発者に提供することはできました、しかしそれは能率が悪く、エラーを起こしやすく、更新が難しいです。なぜなら、アプリケーション固有のコードがミックスされるからです。


解決策として、次のビルドステージの間に、後で実行するために事前にインストラクションを登録するためにONBUILDを使います。

どのように動作するかについてはこちら:

  1. ONBUILD インストラクションに遭遇すると、ビルダは構築されたイメージのメタデータにトリガを追加します。インストラクションはそのほかには現在のビルドに影響を及ぼしません。
  2. ビルドの終わりに、すべてのトリガのリストは、キーOnBuildの下の、イメージマニフェスト内に格納されます。それらは「docker inspect」コマンドで調べることができます。
  3. FROMインストラクションを使うことで、後で新規のビルドのためのベースとしてイメージを作成することができます。FROMインストラクション処理の一部として、下流のビルダはONBUILDトリガを探し、登録されたものと同じ命令を処理します。もしいくつかのトリガが失敗したら、FROMインストラクションを、ビルドが失敗する原因が順番に中止されます。すべてのトリガが成功したら、FROM インストラクションを完了し、通常通りビルドを継続します。
  4. トリガは、実行後最終イメージからクリアされます。別の言い方をすると、"grand-children(孫)"のビルドには継承されません。

たとえば、次のように追加します:

 [...]
 ONBUILD ADD . /app/src
 ONBUILD RUN /usr/local/bin/python-build --dir /app/src
 [...]

 警告:
 「ONBUILD ONBUILD」を使ったONBUILDインストラクションの
 チェーンは許可されません。


 警告:
 ONBUILD インストラクションは FROM
 MAINTAINER インストラクションのトリガになりません。


Dockerfile の例



 # Nginx
 #
 # VERSION               0.0.1

 FROM      ubuntu
 MAINTAINER Victor Vieux

 RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server

 # Firefox over VNC
 #
 # VERSION               0.3

 FROM ubuntu

 # 'ニセ'のディスプレイおよびfirefoxの生成のためにvnc, xvfbをインストール
 RUN apt-get update && apt-get install -y x11vnc xvfb firefox
 RUN mkdir ~/.vnc
 # パスワードのセットアップ
 RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
 # firefoxを自動起動(最良の方法ではありませんが、あえてトリックを使っています)
 RUN bash -c 'echo "firefox" >> /.bashrc'

 EXPOSE 5900
 CMD    ["x11vnc", "-forever", "-usepw", "-create"]

 # 複数イメージサンプル
 #
 # VERSION               0.1

 FROM ubuntu
 RUN echo foo > bar
 # 907ad6c2736fのようなものが出力される

 FROM ubuntu
 RUN echo moo > oink
 # 695d7793cbe4 のようなものが出力される

 # 2つのイメージ、/bar の 907ad6c2736f と /oink の 695d7793cbe4

-----

...~つーか、gosuって、何?
とおもって検索したら、みつかった、gosu

もう翻訳飽きたのでgosuのサイトは翻訳する気無いけど..
dockerがgoベースだからたぶんgosuも使えるようになってるみたい..


Google Colab相当の環境をローカルPC上のDocker Composeで実現する

 Docker Composeの有料版に、お金を払いたくない ^H^Hが使えない ため古いゲーミングPC(GeForce3080)にDocker Composeを入れてその上のコンテナでGoogle Colab相当のノート操作ができないかためしてみた: コンテナイメージとして a...