私のDockerfileは次のようなものです
FROM my/base
ADD . /srv
RUN pip install -r requirements.txt
RUN python setup.py install
ENTRYPOINT ["run_server"]
新しいイメージを作成するたびに、依存関係を再インストールする必要がありますが、これは私の地域では非常に遅くなる可能性があります。
インストール済みのcache
パッケージを考える1つの方法は、my/base
次のような新しい画像を含む画像:
docker build -t new_image_1 .
docker tag new_image_1 my/base
そのため、次回このDockerfileを使用してビルドするとき、my/baseには既にいくつかのパッケージがインストールされています。
ただし、このソリューションには2つの問題があります。
それでは、この問題を解決するために、より良いソリューションを使用できますか?
私のマシンのドッカーに関するいくつかの情報:
☁ test docker version
Client version: 1.1.2
Client API version: 1.13
Go version (client): go1.2.1
Git commit (client): d84a070
Server version: 1.1.2
Server API version: 1.13
Go version (server): go1.2.1
Git commit (server): d84a070
☁ test docker info
Containers: 0
Images: 56
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Dirs: 56
Execution Driver: native-0.2
Kernel Version: 3.13.0-29-generic
WARNING: No swap limit support
以下のDockerfileでビルドしてみてください。
FROM my/base
WORKDIR /srv
ADD ./requirements.txt /srv/requirements.txt
RUN pip install -r requirements.txt
ADD . /srv
RUN python setup.py install
ENTRYPOINT ["run_server"]
.
(プロジェクト)に何らかの変更がある場合、ドッカーはキャッシュを使用してpip install
行をスキップします。
Dockerは、requirements.txtファイルを編集するときに、ビルド時にpip install
のみを実行します。
簡単なHello, World!
プログラムを作成します。
$ tree
.
├── Dockerfile
├── requirements.txt
└── run.py
0 directories, 3 file
# Dockerfile
FROM dockerfile/python
WORKDIR /srv
ADD ./requirements.txt /srv/requirements.txt
RUN pip install -r requirements.txt
ADD . /srv
CMD python /srv/run.py
# requirements.txt
pytest==2.3.4
# run.py
print("Hello, World")
以下は出力です。
Step 1 : WORKDIR /srv
---> Running in 22d725d22e10
---> 55768a00fd94
Removing intermediate container 22d725d22e10
Step 2 : ADD ./requirements.txt /srv/requirements.txt
---> 968a7c3a4483
Removing intermediate container 5f4e01f290fd
Step 3 : RUN pip install -r requirements.txt
---> Running in 08188205e92b
Downloading/unpacking pytest==2.3.4 (from -r requirements.txt (line 1))
Running setup.py (path:/tmp/pip_build_root/pytest/setup.py) Egg_info for package pytest
....
Cleaning up...
---> bf5c154b87c9
Removing intermediate container 08188205e92b
Step 4 : ADD . /srv
---> 3002a3a67e72
Removing intermediate container 83defd1851d0
Step 5 : CMD python /srv/run.py
---> Running in 11e69b887341
---> 5c0e7e3726d6
Removing intermediate container 11e69b887341
Successfully built 5c0e7e3726d6
Run.pyのみを更新し、再度ビルドを試みます。
# run.py
print("Hello, Python")
以下は出力です。
Sending build context to Docker daemon 5.12 kB
Sending build context to Docker daemon
Step 0 : FROM dockerfile/python
---> f86d6993fc7b
Step 1 : WORKDIR /srv
---> Using cache
---> 55768a00fd94
Step 2 : ADD ./requirements.txt /srv/requirements.txt
---> Using cache
---> 968a7c3a4483
Step 3 : RUN pip install -r requirements.txt
---> Using cache
---> bf5c154b87c9
Step 4 : ADD . /srv
---> 9cc7508034d6
Removing intermediate container 0d7cf71eb05e
Step 5 : CMD python /srv/run.py
---> Running in f25c21135010
---> 4ffab7bc66c7
Removing intermediate container f25c21135010
Successfully built 4ffab7bc66c7
上記のように、Dockerはビルドキャッシュを使用します。そして、今回はrequirements.txtを更新します。
# requirements.txt
pytest==2.3.4
ipython
以下は出力です。
Sending build context to Docker daemon 5.12 kB
Sending build context to Docker daemon
Step 0 : FROM dockerfile/python
---> f86d6993fc7b
Step 1 : WORKDIR /srv
---> Using cache
---> 55768a00fd94
Step 2 : ADD ./requirements.txt /srv/requirements.txt
---> b6c19f0643b5
Removing intermediate container a4d9cb37dff0
Step 3 : RUN pip install -r requirements.txt
---> Running in 4b7a85a64c33
Downloading/unpacking pytest==2.3.4 (from -r requirements.txt (line 1))
Running setup.py (path:/tmp/pip_build_root/pytest/setup.py) Egg_info for package pytest
Downloading/unpacking ipython (from -r requirements.txt (line 2))
Downloading/unpacking py>=1.4.12 (from pytest==2.3.4->-r requirements.txt (line 1))
Running setup.py (path:/tmp/pip_build_root/py/setup.py) Egg_info for package py
Installing collected packages: pytest, ipython, py
Running setup.py install for pytest
Installing py.test script to /usr/local/bin
Installing py.test-2.7 script to /usr/local/bin
Running setup.py install for py
Successfully installed pytest ipython py
Cleaning up...
---> 23a1af3df8ed
Removing intermediate container 4b7a85a64c33
Step 4 : ADD . /srv
---> d8ae270eca35
Removing intermediate container 7f003ebc3179
Step 5 : CMD python /srv/run.py
---> Running in 510359cf9e12
---> e42fc9121a77
Removing intermediate container 510359cf9e12
Successfully built e42fc9121a77
また、Dockerはビルドキャッシュを使用しません。動作しない場合は、ドッカーのバージョンを確認してください。
Client version: 1.1.2
Client API version: 1.13
Go version (client): go1.2.1
Git commit (client): d84a070
Server version: 1.1.2
Server API version: 1.13
Go version (server): go1.2.1
Git commit (server): d84a070
ネットワークアクティビティを最小限に抑えるには、pip
がホストマシンのキャッシュディレクトリを指すようにします。
ホストのpipキャッシュディレクトリバインドをコンテナのpipキャッシュディレクトリにマウントして、Dockerコンテナを実行します。 docker run
コマンドは次のようになります。
docker run -v $HOME/.cache/pip/:/root/.cache/pip image_1
次に、DockerfileにENTRYPOINT
コマンドではなく、CMD
ステートメント(またはRUN
ステートメント)の一部として要件をインストールします。 (コメントで指摘されているように)イメージの構築中(RUN
ステートメントが実行されるとき)にマウントが使用できないため、これは重要です。 Dockerファイルは次のようになります。
FROM my/base
ADD . /srv
ENTRYPOINT ["sh", "-c", "pip install -r requirements.txt && python setup.py install && run_server"]
おそらく、ホストシステムのデフォルトのpipディレクトリをキャッシュとして使用するのが最適です(例:$HOME/.cache/pip/
Linuxまたは$HOME/Library/Caches/pip/
OSXで)、例で提案したようにdocker run
コマンド。
この質問にはすでにいくつかの一般的な答えがあることを理解しています。ただし、パッケージマネージャーのファイルをキャッシュする新しい方法があります。 BuildKitがより標準的になるのは、将来的には良い答えになると思います。
Docker 18.09の時点で、 BuildKit の実験的なサポートがあります。 BuildKitは、 外部ボリュームのマウントの実験的サポート をRUN
ステップに含むDockerfileのいくつかの新機能のサポートを追加します。これにより、$HOME/.cache/pip/
などのキャッシュを作成できます。
次のrequirements.txt
ファイルを例として使用します。
Click==7.0
Django==2.2.3
Django-appconf==1.0.3
Django-compressor==2.3
Django-debug-toolbar==2.0
Django-filter==2.2.0
Django-reversion==3.0.4
Django-rq==2.1.0
pytz==2019.1
rcssmin==1.0.6
redis==3.3.4
rjsmin==1.1.0
rq==1.1.0
six==1.12.0
sqlparse==0.3.0
典型的な例Python Dockerfile
は次のようになります。
FROM python:3.7
WORKDIR /usr/src/app
COPY requirements.txt /usr/src/app/
RUN pip install -r requirements.txt
COPY . /usr/src/app
DOCKER_BUILDKIT
環境変数を使用してBuildKitを有効にすると、キャッシュされていないpip
ステップを約65秒で構築できます。
$ DOCKER_BUILDKIT=1 $ time d build -t test .
[+] Building 65.6s (10/10) FINISHED
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 120B 0.0s
=> [internal] load metadata for docker.io/library/python:3.7 0.5s
=> CACHED [1/4] FROM docker.io/library/python:3.7@sha256:6eaf19442c358afc24834a6b17a3728a45c129de7703d8583392a138ecbdb092 0.0s
=> [internal] load build context 0.6s
=> => transferring context: 899.99kB 0.6s
=> CACHED [internal] helper image for file operations 0.0s
=> [2/4] COPY requirements.txt /usr/src/app/ 0.5s
=> [3/4] RUN pip install -r requirements.txt 61.3s
=> [4/4] COPY . /usr/src/app 1.3s
=> exporting to image 1.2s
=> => exporting layers 1.2s
=> => writing image sha256:d66a2720e81530029bf1c2cb98fb3aee0cffc2f4ea2aa2a0760a30fb718d7f83 0.0s
=> => naming to docker.io/library/test 0.0s
次に、実験ヘッダーを追加し、RUN
ステップを変更してPythonパッケージをキャッシュします。
# syntax=docker/dockerfile:experimental
FROM python:3.7
WORKDIR /usr/src/app
COPY requirements.txt /usr/src/app/
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt
COPY . /usr/src/app
さあ、別のビルドを今すぐ実行してください。同じ時間がかかるはずです。ただし、今回はPythonパッケージを新しいキャッシュマウントにキャッシュしています:
$ docker build -t pythontest .
[+] Building 60.3s (14/14) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 120B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> resolve image config for docker.io/docker/dockerfile:experimental 0.5s
=> CACHED docker-image://docker.io/docker/dockerfile:experimental@sha256:9022e911101f01b2854c7a4b2c77f524b998891941da55208e71c0335e6e82c3 0.0s
=> [internal] load .dockerignore 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 120B 0.0s
=> [internal] load metadata for docker.io/library/python:3.7 0.5s
=> CACHED [1/4] FROM docker.io/library/python:3.7@sha256:6eaf19442c358afc24834a6b17a3728a45c129de7703d8583392a138ecbdb092 0.0s
=> [internal] load build context 0.7s
=> => transferring context: 899.99kB 0.6s
=> CACHED [internal] helper image for file operations 0.0s
=> [2/4] COPY requirements.txt /usr/src/app/ 0.6s
=> [3/4] RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt 53.3s
=> [4/4] COPY . /usr/src/app 2.6s
=> exporting to image 1.2s
=> => exporting layers 1.2s
=> => writing image sha256:0b035548712c1c9e1c80d4a86169c5c1f9e94437e124ea09e90aea82f45c2afc 0.0s
=> => naming to docker.io/library/test 0.0s
約60秒。最初のビルドに似ています。
requirements.txt
を少し変更して(2つのパッケージ間に新しい行を追加するなど)、キャッシュを無効にして強制的に再実行します。
$ docker build -t pythontest .
[+] Building 15.9s (14/14) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 120B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> resolve image config for docker.io/docker/dockerfile:experimental 1.1s
=> CACHED docker-image://docker.io/docker/dockerfile:experimental@sha256:9022e911101f01b2854c7a4b2c77f524b998891941da55208e71c0335e6e82c3 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 120B 0.0s
=> [internal] load .dockerignore 0.0s
=> [internal] load metadata for docker.io/library/python:3.7 0.5s
=> CACHED [1/4] FROM docker.io/library/python:3.7@sha256:6eaf19442c358afc24834a6b17a3728a45c129de7703d8583392a138ecbdb092 0.0s
=> CACHED [internal] helper image for file operations 0.0s
=> [internal] load build context 0.7s
=> => transferring context: 899.99kB 0.7s
=> [2/4] COPY requirements.txt /usr/src/app/ 0.6s
=> [3/4] RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt 8.8s
=> [4/4] COPY . /usr/src/app 2.1s
=> exporting to image 1.1s
=> => exporting layers 1.1s
=> => writing image sha256:fc84cd45482a70e8de48bfd6489e5421532c2dd02aaa3e1e49a290a3dfb9df7c 0.0s
=> => naming to docker.io/library/test 0.0s
わずか約16秒!
すべてのPythonパッケージ。これらはパッケージマネージャー(この場合はpip
)によってキャッシュされ、キャッシュボリュームマウントに格納されていません。 pip
が既にダウンロードしたパッケージを再利用できるように、ボリュームマウントが実行ステップに提供されますこれは、Dockerレイヤーキャッシングの外部で発生します 。
ゲインは、requirements.txt
が大きいほど大きくなるはずです。
ノート:
docker system Prune -a
を実行すると削除されます。うまくいけば、これらの機能がビルドのためにDockerに組み込まれ、BuildKitがデフォルトになります。もしそうなったら/私はこの答えを更新しようとします。