ユーザガイドによれば、作成には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を使用したならば、
CMD と ENTRYPOINT 両方のインストラクションは
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内に指定したデフォルトをオーバライドします。
注意:
RUN と CMD を混同しないでください。
RUNは実際にコマンドを実行し、結果をコミットします;
CMD はビルド時には何も実行しませんが、
イメージのために意図されたコマンドを指定します。
EXPOSE
EXPOSE[ ...]
EXPOSE インストラクションは、Dockerに実行中コンテナがlistenしているネットワークポートを知らせます。Dockerはこの情報を使ってリンク(Dockerユーザガイド参照)を使ってコンテナと内部連結します。そして「-P」フラグ使用の際にどのポートをホストへ露出させるかを定義します。
注意:
EXPOSEは、ホストへ露出されるポートがどれか、
もしくはデフォルトでホストからアクセス可能なポートについては、
定義しません。
ENV
ENV
ENV= ...
ENV インストラクションは環境変数
ENV インストラクションには2つのフォームがあります。最初のフォーム、「ENV
2番めのフォーム、「ENV
例:
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 インストラクションは
複数の
それぞれの
ADD hom* /mydir/ # "hom"で始まるすべてのファイルを追加する
ADD hom?.txt /mydir/ # ?は適当な1文字に置換される
ADD test aDir/ # "test" を `WORKDIR`/aDir/ へ追加する
すべての新規のファイルおよびディレクトリは、UIDおよびGIDが0(スーパーユーザ)で作成されます。
注意:
もし標準入力慶友でDockfileを指定してビルド
(docker build - < somefile)した場合、
ビルドコンテキストがありません。
そして Dockerfile は ADD インストラクションベースの
URL でのみ構成されます。
また標準入力経由で圧縮アーカイブも指定でき
(docker build - < archive.tar,gz)、
アーカイブのルートの Dockerfile やアーカイブの残りは
ビルドのコンテキストとして使用されます。
注意:
URL ファイルが認証によりプロテクトされているのであれば、
ADD インストラクションは認証をサポートしていないため、
RUN wget、RUN curl もしくはそのほかのコンテナ上のツールを
使う必要があります。
注意:
もしコンテンツが変更されているならば、
一番最初に ADD インストラクションに遭遇するとすべての後続の
Dockerfile上のインストラクションに対してキャッシュを無効化します。
これはRUNインストラクションのキャッシュ無効化を含みます。
詳細はDockerfileベストプラクティスガイドを参照してください。
コピーは、以下の規則に従います:
パスはビルドコンテキストの内部を指定すべきです:「ADD ../something /something」は実行できません、これはdocker buildの最初のステップが、コンテキストディレクトリ(およびサブディレクトリ)をdockerデーモンへ送信するためです。
- もし
が URL であり へコピーします。
- もし
が URL であり / へダウンロードされます。例えば、「ADD http://example.com/foobar /」はファイル「/foobar」を作成します。この場合(http://example.com では動作しません)、適切な filename が発見できるように、URLは浅薄ではないパスを指定しなくてはなりません。
- もし
注意:
ディレクトリ自身はコピーされません、コンテンツだけです。
- もし
- 追加先パスに存在するなんでも、そして
- ソースツリーのコンテンツ(ファイル対ファイルの基本に則って競合を解決する)
- もし
のコンテンツは / ベース()へ書き込まれます。
- もし
リソースが、ディレクトもしくはワイルドカードを使って、複数指定されているならば、 はディレクトリであるべきです、そしてスラッシュ(/)で終わっていなければなりません。
- もし
のコンテンツが
- もし
が存在しないならば、パス内のすべての存在しないディレクトリとともに作成されます。
COPY
COPY には以下の2つのフォームがあります:
COPY...
COPY [""... " "] (このフォームはパスに空白文字を含めることができます)
COPY インストラクションは
複数の
それぞれの
COPY hom* /mydir/ # "hom"で始まるすべてのファイルをコピーする
COPY hom?.txt /mydir/ # ? は任意の1文字に置換される
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」のサブコマンドとして開始(シグナルをパスしない)する欠点があります。これは、コンテナのPIDが1にならない-そして、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の出力結果からENTRYPOINTはPIDが1ではないことがわかります。
もし「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、 CMD、 ENTRYPOINT インストラクションの実行時使用するユーザ名もしくは UID を指定します。
WORKDIR
WORKDIR /path/to/workdir
WORKDIR インストラクションは、Dockerfile の RUN、 CMD、 ENTRYPOINT、 COPY、 ADD インストラクションのためのワーキングディレクトリを指定します。
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 インストラクションはイメージへあとで実行するためのトリガインストラクションを追加します。トリガは、下流のDockerfileのFROMインストラクションの直後に挿入されたかのように、下流のビルドのコンテキスト内で実行されます。
どんなビルドコンストラクションもトリガとして登録されます。
これは、例えばアプリケーションビルド環境やユーザ個別に設定するデーモンなど、ほかのイメージをビルドするためのベースとして使用されるイメージをビルドする場合、とても便利です。
例えば、特定のディレクトリへアプリケーションソースコードの追加して後で呼び出されるビルドスクリプトが必要となる、再利用可能なPythonアプリケーションビルダである場合のイメージです。ADDやRUNを今すぐに実行できません、なぜならまだアプリケーションソースコードにアクセスしません、そして各アプリケーションビルドによって異なるからです。単純にアプリケーションをコピー&ペーストするためのボイれープレートDockerfileを使ってアプリケーション開発者に提供することはできました、しかしそれは能率が悪く、エラーを起こしやすく、更新が難しいです。なぜなら、アプリケーション固有のコードがミックスされるからです。
解決策として、次のビルドステージの間に、後で実行するために事前にインストラクションを登録するためにONBUILDを使います。
どのように動作するかについてはこちら:
- ONBUILD インストラクションに遭遇すると、ビルダは構築されたイメージのメタデータにトリガを追加します。インストラクションはそのほかには現在のビルドに影響を及ぼしません。
- ビルドの終わりに、すべてのトリガのリストは、キーOnBuildの下の、イメージマニフェスト内に格納されます。それらは「docker inspect」コマンドで調べることができます。
- FROMインストラクションを使うことで、後で新規のビルドのためのベースとしてイメージを作成することができます。FROMインストラクション処理の一部として、下流のビルダはONBUILDトリガを探し、登録されたものと同じ命令を処理します。もしいくつかのトリガが失敗したら、FROMインストラクションを、ビルドが失敗する原因が順番に中止されます。すべてのトリガが成功したら、FROM インストラクションを完了し、通常通りビルドを継続します。
- トリガは、実行後最終イメージからクリアされます。別の言い方をすると、"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も使えるようになってるみたい..
0 件のコメント:
コメントを投稿