docker-compose up
やdocker-compose build
してもbuilding <サービス名>
と出たまま先に進まない。ハングしているような感じで固まる。
Docker Desktop の設定(Preferences
)で [Resources
]-[File sharing
] には、該当ディレクトリの親ディレクトリは含まれています。そもそも、さっきまで正常に動いていました。それが急に動かなくなったのです。何もしていないのに。
TL; DR (今北産業)
-
大量のファイルを、裏で
Docker daemon
が読み込んでいる可能性があります。 -
docker-compose
を使わずにdocker build -t test:local .
と Docker でビルドしてみて永遠と転送していたらビンゴです。 -
.dockerignore
で、大量ファイルのあるディレクトリを除外しておき、docker-compose.json
内で別途マウントしましょう。
🐒 docker-compose
と docker compose
の違い
2023/01/24 現在、docker-compose
は docker compose
のように、docker
のサブコマンドとしての利用が推奨されています。元々 docker-compose
は Python 言語による実装だったのですが、docker-compose
v2 と同等の機能を Go 言語で実装したものが compose です。
Windows や macOS などで Docker Desktop を利用している場合はデフォルトで内包されています。Linux の場合はパケージマネージャーで追加インストールするか、$HOME/.docker/cli-plugins
にバイナリを設置する必要があります。
compose
サブコマンドは、動作が速くなっただけでなく、別途 Python のインストールも不要になりました。つまり docker-compose run
は docker compose run
と同等です。しかし、この記事では docker-compose
の記載のままにします。適宜 docker compose
と置き換えてお読みください。
TS; DR (わかれば簡単なことに気づくまでの細かいこと)
さっきまで docker-compose run --rm <name_service>
で動いていた、機械学習の写経用コンテナが起動しなくなりました。「おかしいな」と、docker-compose build --no-cache
とビルドしなおしても同じです。
起動しないと言うより、止まったままの状態が続いたのです。
$ docker-compose build --no-cache
Building sample_service1 ← ここでハングってる
そこで、Ctrl+c
で処理を止め、写経と言えば坊主ということで --verbose
を呼んでみました。
チリン
$ docker-compose build --no-cache
Building sample_service1 ← ここでハングってる
^CERROR: Aborting.
$ docker-compose --verbose build --no-cache
compose.config.config.find: Using configuration files: ./docker-compose.yml
...省略...
compose.service.build: Building sample_service1
compose.cli.verbose_proxy.proxy_callable: docker build <- (path='~/Desktop/Sample', tag='samp
le:local', rm=True, forcerm=False, pull=False, nocache=True, dockerfile=None, cache_from=None
, labels=None, buildargs={}, network_mode=None, target=None, shmsize=None, extra_hosts=None,
container_limits={'memory': None}, gzip=False, isolation=None, platform=None) ← ここで止まる
どうも、上記 compose.cli.verbose_proxy.proxy_callable:
で docker-compose
が docker build
を呼び出した処理で止まったままです。
Docker がイメージを pull
する際、たまにネットワークが重かったり pull
先が重い場合に反応が遅れることはあるのですが、体感的にいつも以上の時間がかかっています。
切り分け(やったこと):
-
docker-compose build --no-cache
→ NG(現象同じ) -
docker-compose down
からのdocker-compose up
→ NG(現象同じ) -
docker-compose stop
からのdocker-compose up
→ NG(現象同じ) -
docker-compose ps
→ NG(起動中コンテナなし) -
docker container prune -f
docker image prune -f
からのdocker-compose build --no-cache
→ NG(現象同じ) -
docker-compose logs
→ NG(Attaching to
が出るだけ) - ホスト OS の再起動 → NG(現象同じ)
-
docker run --rm hello-world:latest
→ OK(起動する) -
docker-compose
の "Hello World!" → OK(起動する)
以上の切り分けにより、docker
や docker-compose
自体は生きているものの「現在の Dockerfile
や docker-compose.yml
に問題がありそう」と判断できそうです。
しかし、それらファイルはいじっていません。となると、別途マウントさせてるスクリプトやイメージなどに原因がありそうです。
そこで、docker-compose
を通さず Docker から直接イメージを 1 つ 1 つビルドしてみました。
$ docker build -t test:local .
Sending build context to Docker daemon xxxMB
すると、なんとなんと!上記の xxxMB
が永遠とカウントアップされていきます。何やら大量のファイルがコンテキストに送られているではありませんか!
「そうかっ!!学習用のデータ、かっ!!」
🐒 コンテキストとは
context
は日本語で「文脈」「文の前後関係」「事情」「背景」「状況」などといった意味があります。しかし、プログラムの世界では「文脈」ではピンとこないケースがあります。
コンテキストは、con-
と text
で構成され、con-
の接頭辞は「一緒に」とか「付いに」などの意味を持ち、text
は 「組み上げる」「編む」「作る」「構成する」の *teks-
から来ています。つまり context
は、何かを「実行」「判断」「作成」する際に添えられた裏付け情報のような意味合いになります。
そのため、Sending build context to ...
とは「(Docker イメージの)ビルドに必要な情報を ... に送信中」という意味になります。
実は、機械学習用に用意した大量のデータ・ボリューム(data
ディレクトリ)をコンテナにマウントさせていたのですが、軽量のデータで動作確認したいと思いディレクトリ名をリネームしたのを失念していました。
元々 data
ディレクトリ内のデータ量が多いため .dockerignore
で除外して、ビルド後にマウントさていました。しかし、data
が data2
にリネームされたことにより、ビルド時にデータ(コンテキスト)として data2
がメモリに読み込まれていたのです。
.dockerignore
に記載済みだった data
同様、問題の data2
を追加していつもどおり動くようになりましたとさ。とほほ
data
data2
docker
と docker compose
の違い
docker
はコンテナを個別に操作するコマンドで、docker compose
(旧docker-compose
) は同じマシン上で仮想ネットワークを作成し、その中で複数のコンテナを操作するツールです。その上位として、同じネットワーク(LAN)内の複数のマシン間で仮想ネットワークを作成し、その中で複数のコンテナを操作するツールに
docker swarm
があります。さらにハイ・レベルな、複数ネットワーク(WAN)の間で仮想ネットワークを作成し、その中で複数コンテナの操作をするツールにkubernetes
などがあります。これらの、複数のコンテナや仮想ネットワークの作成・操作を支援するツールを、オーケストレーション・ツールと呼びます。つまり
docker compose
もオーケストレーション・ツールの 1 つであるため、オーケストレーションの入門としては打ってつけです。
docker
は、コンテナを作成&起動すると明示しない限り「docker
ネットワーク」と呼ばれる仮想ネットワークにコンテナを設置します。つまり、仮想 LAN 内にサーバ(docker のコンテナ)だけが存在するネットワークを作るということです。
この仮想ネットワークは docker network create <ネットワーク名>
で作成することもでき、コンテナを起動する際に --network <ネットワーク名>
オプションを付ると、そのネットワークに参加させることができます。
これは、サーバ間通信が必要なものをだけを特定のネットワークに入れておき、隔離することで余計なセキュリティの心配を減らすことができます。
例えば、Web サーバと DB サーバを同じネットワークに置いておき、Web サーバのポート(例えば 80 番ポート)だけを外部に開放(ポートを公開)する、などです。この場合、外部からは直接 DB サーバにはアクセスできません。
しかし、この方法だとコンテナやネットワークを起動するたびにコマンドを打たないといけないので、シェル・スクリプトなどで一発で起動させたいと思うことでしょう。
そんな時に使うのが docker compose
です。
docker compose
は複数コンテナを起動・操作するためのコマンドです。docker-compose.yml
という YAML 形式の設定ファイルに記載された条件でコンテナを起動してくれます。
docker compose
を使うと docker-compose.yaml
に記載されたコンテナはデフォルトで同じネットワークに設置されます。
そのため、複数コンテナを起動してお互いを連携させたい場合は docker compose
の利用が便利です。詳しくは以下の記事を参照ください。
- 環境変数でデータを渡すことの考察 | Docker で環境変数をホストからコンテナに渡す方法(ホスト OS 側からゲスト OS に渡す方法各種) @ Qiita
参考文献
- dockerでコンテナが立ち上がらないときやってみること @ Qiita
関連文献
-
.dockerignore
が効かない? -
.gitignore
と違うの?- [Git] .gitignoreの仕様詳解 @ Qiita
あわせて読みたい
- [Git] .gitignoreの仕様詳解 @ Qiita
- .dockerignoreが効かない?.gitignoreとは書き方が違うよ! @ Qiita