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 -fdocker 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