最適なDockerfileの作成方法
10526 ワード
Dockerfileの構文は非常に簡単ですが、ミラーの構築速度を速めるには、Dockerミラーのサイズを減らすには直感的ではなく、実践的な経験が必要です.このブログはDockerfileを書くテクニックを素早く身につけるのに役立ちます.
可読性を保証するために、本文は直訳ではなく意訳を採用する.また,本稿の著作権は原作者の所有であり,翻訳は学習にのみ用いられる.
Dockerを使ってしばらく経ちましたが、Dockerfileの作成は非常に重要な仕事です.このブログでは、より良いDockerfileを書くためのアドバイスを共有するつもりです.
ターゲット:より高速な構築速度 より小さいDockerミラーサイズ より少ないDockerミラー層 ミラーキャッシュ を活用する. Dockerfile可読性 を増加 Dockerコンテナをより簡単に使用できる まとめ作成.dockerignoreファイル コンテナは、単一アプリケーション のみを実行する.複数のRUN命令を1つの に統合する.ベースミラーのラベルlatest を使用しないでください RUN指令毎に余分なファイル を削除する.適切なベースミラー(alpineバージョンがベスト) を選択 WORKDIRおよびCMD を設定する ENTRYPOINT(オプション) を使用 entrypointスクリプトでexec を使用 COPYとADDは前者の を優先的に使用する. COPYとRUNの順序を合理的に調整する デフォルトの環境変数、マッピングポート、およびデータボリューム を設定します. LABELを使用するミラーメタデータ を設定する. HEALTHCHECK を追加
例
例Dockerfileはほとんどの間違いを犯しました(もちろんわざとです).次に、一歩一歩最適化します.Dockerを使用してNodeを実行する必要があるとします.jsアプリケーションは、以下がDockerfileです(CMD命令は複雑すぎるので、簡略化しました.これはエラーで、参考までにしています).
ミラーの構築:
1.作成dockerignoreファイル
ミラーを構築する場合、Dockerはまずcontextを準備し、必要なすべてのファイルをプロセスに収集する必要があります.デフォルトのcontextにはDockerfileディレクトリのすべてのファイルが含まれていますが、実際には必要ありません.gitディレクトリ、node_modulesディレクトリなどの内容..dockerignoreの役割と文法は似ている.gitignoreでは、不要なファイルを無視することで、Dockerミラーのサイズを削減しながら、ミラー構築時間を効率的に短縮できます.例は次のとおりです.
2.コンテナは単一のアプリケーションのみを実行
技術的には、Dockerコンテナで複数のプロセスを実行できます.データベース、フロントエンド、バックエンド、ssh、supervisorを同じDockerコンテナで実行できます.しかし、これはあなたを非常に苦しめます.
非常に長い構築時間(フロントエンドを変更した後、バックエンド全体を再構築する必要がある)非常に大きなミラーサイズの複数のアプリケーションのログは処理しにくい(stdoutを直接使用することはできません.そうしないと、複数のアプリケーションのログが混在します)横方向に拡張すると、リソースが浪費されます(異なるアプリケーションで実行するコンテナの数が異なります)ゾンビプロセスの問題-適切なinitプロセスを選択する必要があります.アプリケーションごとに個別のDockerミラーを構築し、Docker Componentを使用して複数のDockerコンテナを実行することをお勧めします.
今、Dockerfileから不要なインストールパッケージを削除します.また、SSHはdocker execで代用できます.例は次のとおりです.
3.複数のRUN命令を一つにまとめる
Dockerミラーリングは階層化されており、以下の知識点が重要です.
Dockerfileの各コマンドは、新しいミラーレイヤを作成します.ミラーレイヤがキャッシュされ、多重化されますDockerfileの命令が変更され、コピーされたファイルが変更されたり、ミラーを構築する際に指定された変数が異なり、対応するミラーレイヤキャッシュがレイヤのミラーキャッシュが無効になったりすると、その後のミラーレイヤキャッシュが無効になりますミラーレイヤは可変ではありません.レイヤにファイルを追加して次のレイヤで削除すると、ミラーにはファイルが含まれます(Dockerコンテナでは表示されません).Dockerミラーはタマネギに似ています.たくさんの層があります内層を修正するためには、外の層をすべて削除する必要があります.それを覚えておけば、他の内容はよく理解できます.
今、私たちはすべてのRUN命令を1つに統合します.同時にapt-get upgradeを削除します.ミラー構築が非常に不確定になるためです(ベースミラーの更新に依存するだけでいいです)
変化周波数のような命令を統合するしかないことを覚えておいてください.node.jsのインストールがnpmモジュールのインストールと一緒になると、ソースコードを変更するたびにnodeを再インストールする必要がある.js、これは明らかに適切ではありません.したがって、正しい書き方は次のようになります.
4.ベースミラーのラベルはlatestを使用しないミラーにラベルが指定されていない場合、latestラベルがデフォルトで使用されます.したがって,FROM ubuntu命令はFROM ubuntu:latestと同等である.ミラーが更新されるとlatestラベルが異なるミラーを指し、ミラーの構築に失敗する可能性があります.最新版のベースミラーを使用する必要がある場合は、latestラベルを使用します.そうでない場合は、特定のミラーラベルを指定したほうがいいです.
例Dockerfileはラベルとして16.04を使用する必要があります.
5.各RUN命令の後、余分なファイルを削除し、apt-getソースを更新したと仮定し、ダウンロード、解凍、インストールしたパッケージが/var/lib/apt/lists/ディレクトリに保存されている.ただし、これらのファイルは、アプリケーションの実行時にDockerミラーには必要ありません.Dockerミラーが大きくなるので削除したほうがいいです.
例Dockerfileでは、/var/lib/apt/lists/ディレクトリのファイルを削除できます(apt-get updateによって生成されます).
6.適切なベースミラーを選択する(alpineバージョンが望ましい)
例では、ubuntuをベースミラーとして選択します.しかし、nodeプログラムを実行するだけで、共通のベースミラーを使用する必要がありますか?Nodeミラーはより良い選択であるべきです.
より良い選択はalpineバージョンのnodeミラーです.Alpineは極小化したLinuxリリース版で、4 MBしかないので、ベースミラーとして非常に適しています.
apkはAlpineのパッケージ管理ツールです.apt-getとは少し違いますが、とても使いやすいです.さらに、no-cacheやvirtualオプションなど、ミラーのサイズを減らすのに役立つ機能もあります.
7.WORKDIRとCMDの設定
WORKDIR命令は、デフォルトディレクトリ、すなわちRUN/CMD/ENTRYPOINT命令を実行する場所を設定することができる.
CMDコマンドは、コンテナ作成が実行されるデフォルトコマンドを設定できます.また、コマンドは1つの配列に書かれています.配列の各要素はコマンドの各単語です(公式ドキュメントを参照).
8.ENTRYPOINTの使用(オプション)
複雑さが増すため、ENTRYPOINT命令は必須ではありません.ENTRYPOINTは、デフォルトで実行され、指定されたコマンドがパラメータをエラーするスクリプトです.通常、実行可能なDockerミラーを構築するために使用されます.entrypoint.shは以下の通りである.
例Dockerfile:
ミラーを実行するには、次のコマンドを使用します.
9.entrypointスクリプトでexecを使用前文のentrypointスクリプトでexecコマンドを使用してnodeアプリケーションを実行しました.execを使用しないと、SIGTERM信号がbashスクリプトプロセスに飲み込まれるため、コンテナをスムーズに閉じることはできません.execコマンドで起動したプロセスは、スクリプトプロセスに取って代わることができるため、すべての信号が正常に動作します.
10.COPYおよびADDは、前者のCOPY命令を優先的に使用することが非常に簡単であり、ファイルをミラーにコピーするためにのみ使用される.ADDは比較的複雑で、リモートファイルのダウンロードや圧縮パッケージの解凍(公式ドキュメント参照)に使用できます.
11.COPYとRUNの順序を合理的に調整するには、最も変化の少ない部分をDockerfileの前に置くべきで、ミラーキャッシュを十分に利用することができます.
例では、ソースコードが頻繁に変化するため、ミラーを構築するたびにNPMモジュールを再インストールする必要があります.これは明らかに望ましくありません.まずpackageをコピーすることができますjsonは、NPMモジュールをインストールし、残りのソースコードをコピーします.これにより,ソースコードが変化してもNPMモジュールを再インストールする必要はない.
12.デフォルトの環境変数、マッピングポート、およびデータボリュームの設定
Dockerコンテナを実行するには、いくつかの環境変数が必要になる可能性があります.Dockerfileでデフォルトの環境変数を設定するのは良い方法です.また、Dockerfileでマッピングポートとデータボリュームを設定する必要があります.例は次のとおりです.
ENV命令で指定した環境変数はコンテナで使用できます.ミラーを構築する変数を指定する必要がある場合は、ARGコマンドを使用します.
13.LABELを使用してミラーメタデータを設定LABELコマンドを使用して、ミラー作成者やミラーの説明など、ミラーのメタデータを設定できます.旧バージョンのDockerfile構文では、MAINTAINERコマンドを使用してミラー作成者を指定していますが、すでに破棄されています.一部の外部プログラムでは、nvidia-dockerなどのミラーのメタデータを使用する必要がある場合がある.nvidia.volumes.needed.例は次のとおりです.
14.HEALTHCHECK実行コンテナを追加する場合、--restart alwaysオプションを指定できます.そうすると、コンテナがクラッシュしたときにDockerデーモン(docker daemon)がコンテナを再起動します.このオプションは、長時間実行するコンテナに便利です.しかし、容器が確実に動いているが、(デッドサイクルに陥り、配置が間違っている)ことができない場合はどうすればいいのでしょうか.HEALTHCHECKコマンドを使用すると、Dockerが容器の健康状態を周期的に検査することができます.コマンドを指定するだけで、すべてが正常であれば0を返し、そうでなければ1を返します.HEALTHCHECKに興味があれば、このブログを参考にすることができます.例は次のとおりです.
リクエストに失敗すると、curl--failコマンドは0以外のステータスを返します.
原文:How to write excellent Dockerfiles
訳者:Fundebug
可読性を保証するために、本文は直訳ではなく意訳を採用する.また,本稿の著作権は原作者の所有であり,翻訳は学習にのみ用いられる.
Dockerを使ってしばらく経ちましたが、Dockerfileの作成は非常に重要な仕事です.このブログでは、より良いDockerfileを書くためのアドバイスを共有するつもりです.
ターゲット:
例
例Dockerfileはほとんどの間違いを犯しました(もちろんわざとです).次に、一歩一歩最適化します.Dockerを使用してNodeを実行する必要があるとします.jsアプリケーションは、以下がDockerfileです(CMD命令は複雑すぎるので、簡略化しました.これはエラーで、参考までにしています).
FROM ubuntu
ADD . /app
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y nodejs ssh mysql
RUN cd /app && npm install
# this should start three processes, mysql and ssh
# in the background and node app in foreground
# isn't it beautifully terrible? <3
CMD mysql & sshd & npm start
ミラーの構築:
docker build -t wtf .
1.作成dockerignoreファイル
ミラーを構築する場合、Dockerはまずcontextを準備し、必要なすべてのファイルをプロセスに収集する必要があります.デフォルトのcontextにはDockerfileディレクトリのすべてのファイルが含まれていますが、実際には必要ありません.gitディレクトリ、node_modulesディレクトリなどの内容..dockerignoreの役割と文法は似ている.gitignoreでは、不要なファイルを無視することで、Dockerミラーのサイズを削減しながら、ミラー構築時間を効率的に短縮できます.例は次のとおりです.
.git/
node_modules/
2.コンテナは単一のアプリケーションのみを実行
技術的には、Dockerコンテナで複数のプロセスを実行できます.データベース、フロントエンド、バックエンド、ssh、supervisorを同じDockerコンテナで実行できます.しかし、これはあなたを非常に苦しめます.
非常に長い構築時間(フロントエンドを変更した後、バックエンド全体を再構築する必要がある)非常に大きなミラーサイズの複数のアプリケーションのログは処理しにくい(stdoutを直接使用することはできません.そうしないと、複数のアプリケーションのログが混在します)横方向に拡張すると、リソースが浪費されます(異なるアプリケーションで実行するコンテナの数が異なります)ゾンビプロセスの問題-適切なinitプロセスを選択する必要があります.アプリケーションごとに個別のDockerミラーを構築し、Docker Componentを使用して複数のDockerコンテナを実行することをお勧めします.
今、Dockerfileから不要なインストールパッケージを削除します.また、SSHはdocker execで代用できます.例は次のとおりです.
FROM ubuntu
ADD . /app
RUN apt-get update
RUN apt-get upgrade -y
# we should remove ssh and mysql, and use
# separate container for database
RUN apt-get install -y nodejs # ssh mysql
RUN cd /app && npm install
CMD npm start
3.複数のRUN命令を一つにまとめる
Dockerミラーリングは階層化されており、以下の知識点が重要です.
Dockerfileの各コマンドは、新しいミラーレイヤを作成します.ミラーレイヤがキャッシュされ、多重化されますDockerfileの命令が変更され、コピーされたファイルが変更されたり、ミラーを構築する際に指定された変数が異なり、対応するミラーレイヤキャッシュがレイヤのミラーキャッシュが無効になったりすると、その後のミラーレイヤキャッシュが無効になりますミラーレイヤは可変ではありません.レイヤにファイルを追加して次のレイヤで削除すると、ミラーにはファイルが含まれます(Dockerコンテナでは表示されません).Dockerミラーはタマネギに似ています.たくさんの層があります内層を修正するためには、外の層をすべて削除する必要があります.それを覚えておけば、他の内容はよく理解できます.
今、私たちはすべてのRUN命令を1つに統合します.同時にapt-get upgradeを削除します.ミラー構築が非常に不確定になるためです(ベースミラーの更新に依存するだけでいいです)
FROM ubuntu
ADD . /app
RUN apt-get update \
&& apt-get install -y nodejs \
&& cd /app \
&& npm install
CMD npm start
変化周波数のような命令を統合するしかないことを覚えておいてください.node.jsのインストールがnpmモジュールのインストールと一緒になると、ソースコードを変更するたびにnodeを再インストールする必要がある.js、これは明らかに適切ではありません.したがって、正しい書き方は次のようになります.
FROM ubuntu
RUN apt-get update && apt-get install -y nodejs
ADD . /app
RUN cd /app && npm install
CMD npm start
4.ベースミラーのラベルはlatestを使用しないミラーにラベルが指定されていない場合、latestラベルがデフォルトで使用されます.したがって,FROM ubuntu命令はFROM ubuntu:latestと同等である.ミラーが更新されるとlatestラベルが異なるミラーを指し、ミラーの構築に失敗する可能性があります.最新版のベースミラーを使用する必要がある場合は、latestラベルを使用します.そうでない場合は、特定のミラーラベルを指定したほうがいいです.
例Dockerfileはラベルとして16.04を使用する必要があります.
FROM ubuntu:16.04 # it's that easy!
RUN apt-get update && apt-get install -y nodejs
ADD . /app
RUN cd /app && npm install
CMD npm start
5.各RUN命令の後、余分なファイルを削除し、apt-getソースを更新したと仮定し、ダウンロード、解凍、インストールしたパッケージが/var/lib/apt/lists/ディレクトリに保存されている.ただし、これらのファイルは、アプリケーションの実行時にDockerミラーには必要ありません.Dockerミラーが大きくなるので削除したほうがいいです.
例Dockerfileでは、/var/lib/apt/lists/ディレクトリのファイルを削除できます(apt-get updateによって生成されます).
FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install -y nodejs \
# added lines
&& rm -rf /var/lib/apt/lists/*
ADD . /app
RUN cd /app && npm install
CMD npm start
6.適切なベースミラーを選択する(alpineバージョンが望ましい)
例では、ubuntuをベースミラーとして選択します.しかし、nodeプログラムを実行するだけで、共通のベースミラーを使用する必要がありますか?Nodeミラーはより良い選択であるべきです.
FROM node
ADD . /app
# we don't need to install node
# anymore and use apt-get
RUN cd /app && npm install
CMD npm start
より良い選択はalpineバージョンのnodeミラーです.Alpineは極小化したLinuxリリース版で、4 MBしかないので、ベースミラーとして非常に適しています.
FROM node:7-alpine
ADD . /app
RUN cd /app && npm install
CMD npm start
apkはAlpineのパッケージ管理ツールです.apt-getとは少し違いますが、とても使いやすいです.さらに、no-cacheやvirtualオプションなど、ミラーのサイズを減らすのに役立つ機能もあります.
7.WORKDIRとCMDの設定
WORKDIR命令は、デフォルトディレクトリ、すなわちRUN/CMD/ENTRYPOINT命令を実行する場所を設定することができる.
CMDコマンドは、コンテナ作成が実行されるデフォルトコマンドを設定できます.また、コマンドは1つの配列に書かれています.配列の各要素はコマンドの各単語です(公式ドキュメントを参照).
FROM node:7-alpine
WORKDIR /app
ADD . /app
RUN npm install
CMD ["npm", "start"]
8.ENTRYPOINTの使用(オプション)
複雑さが増すため、ENTRYPOINT命令は必須ではありません.ENTRYPOINTは、デフォルトで実行され、指定されたコマンドがパラメータをエラーするスクリプトです.通常、実行可能なDockerミラーを構築するために使用されます.entrypoint.shは以下の通りである.
#!/usr/bin/env sh
# $0 is a script name,
# $1, $2, $3 etc are passed arguments
# $1 is our command
CMD=$1
case "$CMD" in
"dev" )
npm install
export NODE_ENV=development
exec npm run dev
;;
"start" )
# we can modify files here, using ENV variables passed in
# "docker create" command. It can't be done during build process.
echo "db: $DATABASE_ADDRESS" >> /app/config.yml
export NODE_ENV=production
exec npm start
;;
* )
# Run custom command. Thanks to this line we can still use
# "docker run our_image /bin/bash" and it will work
exec $CMD ${@:2}
;;
esac
例Dockerfile:
FROM node:7-alpine
WORKDIR /app
ADD . /app
RUN npm install
ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]
ミラーを実行するには、次のコマンドを使用します.
#
docker run our-app dev
#
docker run our-app start
# bash
docker run -it our-app /bin/bash
9.entrypointスクリプトでexecを使用前文のentrypointスクリプトでexecコマンドを使用してnodeアプリケーションを実行しました.execを使用しないと、SIGTERM信号がbashスクリプトプロセスに飲み込まれるため、コンテナをスムーズに閉じることはできません.execコマンドで起動したプロセスは、スクリプトプロセスに取って代わることができるため、すべての信号が正常に動作します.
10.COPYおよびADDは、前者のCOPY命令を優先的に使用することが非常に簡単であり、ファイルをミラーにコピーするためにのみ使用される.ADDは比較的複雑で、リモートファイルのダウンロードや圧縮パッケージの解凍(公式ドキュメント参照)に使用できます.
FROM node:7-alpine
WORKDIR /app
COPY . /app
RUN npm install
ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]
11.COPYとRUNの順序を合理的に調整するには、最も変化の少ない部分をDockerfileの前に置くべきで、ミラーキャッシュを十分に利用することができます.
例では、ソースコードが頻繁に変化するため、ミラーを構築するたびにNPMモジュールを再インストールする必要があります.これは明らかに望ましくありません.まずpackageをコピーすることができますjsonは、NPMモジュールをインストールし、残りのソースコードをコピーします.これにより,ソースコードが変化してもNPMモジュールを再インストールする必要はない.
FROM node:7-alpine
WORKDIR /app
COPY package.json /app
RUN npm install
COPY . /app
ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]
12.デフォルトの環境変数、マッピングポート、およびデータボリュームの設定
Dockerコンテナを実行するには、いくつかの環境変数が必要になる可能性があります.Dockerfileでデフォルトの環境変数を設定するのは良い方法です.また、Dockerfileでマッピングポートとデータボリュームを設定する必要があります.例は次のとおりです.
FROM node:7-alpine
ENV PROJECT_DIR=/app
WORKDIR $PROJECT_DIR
COPY package.json $PROJECT_DIR
RUN npm install
COPY . $PROJECT_DIR
ENV MEDIA_DIR=/media \
NODE_ENV=production \
APP_PORT=3000
VOLUME $MEDIA_DIR
EXPOSE $APP_PORT
ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]
ENV命令で指定した環境変数はコンテナで使用できます.ミラーを構築する変数を指定する必要がある場合は、ARGコマンドを使用します.
13.LABELを使用してミラーメタデータを設定LABELコマンドを使用して、ミラー作成者やミラーの説明など、ミラーのメタデータを設定できます.旧バージョンのDockerfile構文では、MAINTAINERコマンドを使用してミラー作成者を指定していますが、すでに破棄されています.一部の外部プログラムでは、nvidia-dockerなどのミラーのメタデータを使用する必要がある場合がある.nvidia.volumes.needed.例は次のとおりです.
FROM node:7-alpine
LABEL maintainer "[email protected]"
...
14.HEALTHCHECK実行コンテナを追加する場合、--restart alwaysオプションを指定できます.そうすると、コンテナがクラッシュしたときにDockerデーモン(docker daemon)がコンテナを再起動します.このオプションは、長時間実行するコンテナに便利です.しかし、容器が確実に動いているが、(デッドサイクルに陥り、配置が間違っている)ことができない場合はどうすればいいのでしょうか.HEALTHCHECKコマンドを使用すると、Dockerが容器の健康状態を周期的に検査することができます.コマンドを指定するだけで、すべてが正常であれば0を返し、そうでなければ1を返します.HEALTHCHECKに興味があれば、このブログを参考にすることができます.例は次のとおりです.
FROM node:7-alpine
LABEL maintainer "[email protected]"
ENV PROJECT_DIR=/app
WORKDIR $PROJECT_DIR
COPY package.json $PROJECT_DIR
RUN npm install
COPY . $PROJECT_DIR
ENV MEDIA_DIR=/media \
NODE_ENV=production \
APP_PORT=3000
VOLUME $MEDIA_DIR
EXPOSE $APP_PORT
HEALTHCHECK CMD curl --fail http://localhost:$APP_PORT || exit 1
ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]
リクエストに失敗すると、curl--failコマンドは0以外のステータスを返します.
原文:How to write excellent Dockerfiles
訳者:Fundebug