何も考えずにdocker-compose runして無駄なコンテナを生成しまくるのは良くない話

docker-compose up してるときにdocker-compose runしたときや、control+CやCtrl+Cで落としたときにコンテナをうまく破棄できなかったときの対処です。

入社してDockerを覚えてだいぶ慣れてきましたが、定期的にエラーを吐くのに困らされてます。

結論

docker-compose up してるときにテストなどを実行するときは

docker-compose run app rspec

ではなく

docker-compose exec app rspec

の様にdocker-compose exec ○○ を使うようにする。

また、—rmオプションを使って立ち上げたコンテナを使用後に破棄するようにする。

docker-compose run --rm app rspec

docker-compose up してるときにdocker-compose runして無駄なコンテナを作った時は削除する。

control+CやCtrl+Cで落とした時にコンテナが中途半端に残ってしまった時も同じ。

永遠に増やしているとDockerの調子が悪くなる。

runとexecの違い

単体でdocker-compose exec ~ するとエラーが出ます。

これはexecはdocker-compose upですでに立ち上がっているコンテナを使用してコマンドを実行するからです。

これによって新しくコンテナを立ち上げる時間を節約したりすることができます。

逆にrunは新しくコンテナを立ち上げてコマンドを実行します。

(runによって立ち上げられるこのコンテナは、docker-compose upで立ち上げられるコンテナとは別の特殊なコンテナらしい)

つまりexecを実行する前にはdocker-compose upでコンテナが立ち上がってる必要があります。

docker-compose up -d
docker-compose exec app rspec
docker-compose stop # コンテナを止める
# docker-compose down # コンテナを削除(DBなども消える)

runの時はいりません。

docker-compose run app rspec

なぜそうするのか

起きる問題

docker-compose upしてる時に—rmオプションなしでdocker-compose run ○○ すると、画像の様に使用後に使用済みのコンテナが残ってしまいます。

無駄に生成したコンテナ

特殊なコンテナなので、コンテナの名前が違います。

compose upで立ち上げられたコンテナはrailsapp1のような名前ですが、compose runで立ち上げられたコンテナはrailsapprun_xxxxxxxxみたいな名前になります。

こういった無駄なコンテナを大量に作っていると以下のようなエラーが出たり、コンテナがメモリを食いきってしまいます。

$ docker-compose run app rspec
Starting rails_db_1 ... done
Could not find database_cleaner-1.8.5 in any of the sources
Run `bundle install` to install missing gems.
Traceback (most recent call last):
        37: from /usr/local/bundle/bin/rspec:23:in `<main>'
        36: from /usr/local/bundle/bin/rspec:23:in `load'
        35: from /usr/local/bundle/gems/rspec-core-3.10.0/exe/rspec:4:in `<top (required)>'
        34: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:45:in `invoke'
        33: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:71:in `run'
        32: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:86:in `run'
        31: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:102:in `setup'
        30: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/configuration.rb:1613:in `load_spec_files'
        29: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/configuration.rb:1613:in `each'
        28: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/configuration.rb:1615:in `block in load_spec_files'
        27: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/configuration.rb:2112:in `load_file_handling_errors'
        26: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/configuration.rb:2112:in `load'
        25: from /app/spec/models/user_spec.rb:1:in `<top (required)>'
        24: from /usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:72:in `require'
        23: from /usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:72:in `require'
        22: from /app/spec/rails_helper.rb:4:in `<top (required)>'
        21: from /usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
        20: from /usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
        19: from /app/config/environment.rb:2:in `<top (required)>'
        18: from /app/config/environment.rb:2:in `require_relative'
        17: from /app/config/application.rb:1:in `<top (required)>'
        16: from /app/config/application.rb:1:in `require_relative'
        15: from /app/config/boot.rb:3:in `<top (required)>'
        14: from /usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
        13: from /usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
        12: from /usr/local/lib/ruby/2.7.0/bundler/setup.rb:10:in `<top (required)>'
        11: from /usr/local/lib/ruby/2.7.0/bundler/ui/shell.rb:88:in `silence'
        10: from /usr/local/lib/ruby/2.7.0/bundler/ui/shell.rb:136:in `with_level'
         9: from /usr/local/lib/ruby/2.7.0/bundler/setup.rb:10:in `block in <top (required)>'
         8: from /usr/local/lib/ruby/2.7.0/bundler.rb:149:in `setup'
         7: from /usr/local/lib/ruby/2.7.0/bundler/runtime.rb:20:in `setup'
         6: from /usr/local/lib/ruby/2.7.0/bundler/runtime.rb:101:in `block in definition_method'
         5: from /usr/local/lib/ruby/2.7.0/bundler/definition.rb:226:in `requested_specs'
         4: from /usr/local/lib/ruby/2.7.0/bundler/definition.rb:237:in `specs_for'
         3: from /usr/local/lib/ruby/2.7.0/bundler/definition.rb:170:in `specs'
         2: from /usr/local/lib/ruby/2.7.0/bundler/spec_set.rb:80:in `materialize'
         1: from /usr/local/lib/ruby/2.7.0/bundler/spec_set.rb:80:in `map!'
/usr/local/lib/ruby/2.7.0/bundler/spec_set.rb:86:in `block in materialize': Could not find database_cleaner-1.8.5 in any of the sources (Bundler::GemNotFound)
        27: from /usr/local/bundle/bin/rspec:23:in `<main>'
        26: from /usr/local/bundle/bin/rspec:23:in `load'
        25: from /usr/local/bundle/gems/rspec-core-3.10.0/exe/rspec:4:in `<top (required)>'
        24: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:45:in `invoke'
        23: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:71:in `run'
        22: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:86:in `run'
        21: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:102:in `setup'
        20: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/configuration.rb:1613:in `load_spec_files'
        19: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/configuration.rb:1613:in `each'
        18: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/configuration.rb:1615:in `block in load_spec_files'
        17: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/configuration.rb:2112:in `load_file_handling_errors'
        16: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/configuration.rb:2112:in `load'
        15: from /app/spec/models/user_spec.rb:1:in `<top (required)>'
        14: from /usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:72:in `require'
        13: from /usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:72:in `require'
        12: from /app/spec/rails_helper.rb:4:in `<top (required)>'
        11: from /usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
        10: from /usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
         9: from /app/config/environment.rb:2:in `<top (required)>'
         8: from /app/config/environment.rb:2:in `require_relative'
         7: from /app/config/application.rb:1:in `<top (required)>'
         6: from /app/config/application.rb:1:in `require_relative'
         5: from /app/config/boot.rb:3:in `<top (required)>'
         4: from /usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
         3: from /usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
         2: from /usr/local/lib/ruby/2.7.0/bundler/setup.rb:9:in `<top (required)>'
         1: from /usr/local/lib/ruby/2.7.0/bundler/setup.rb:17:in `rescue in <top (required)>'
/usr/local/lib/ruby/2.7.0/bundler/setup.rb:17:in `exit': exit (SystemExit)
        19: from /usr/local/bundle/bin/rspec:23:in `<main>'
        18: from /usr/local/bundle/bin/rspec:23:in `load'
        17: from /usr/local/bundle/gems/rspec-core-3.10.0/exe/rspec:4:in `<top (required)>'
        16: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:45:in `invoke'
        15: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:71:in `run'
        14: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:86:in `run'
        13: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:104:in `setup'
        12: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:104:in `ensure in setup'
        11: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/world.rb:188:in `announce_filters'
        10: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/world.rb:196:in `report_filter_message'
         9: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/reporter.rb:100:in `message'
         8: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/reporter.rb:207:in `notify'
         7: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/reporter.rb:236:in `ensure_listeners_ready'
         6: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/reporter.rb:47:in `block in prepare_default'
         5: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/formatters.rb:127:in `setup_default'
         4: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/formatters.rb:152:in `add'
         3: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/formatters.rb:182:in `find_formatter'
         2: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/formatters.rb:212:in `built_in_formatter'
         1: from /usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
/usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require': cannot load such file -- rspec/core/formatters/progress_formatter (LoadError)
        20: from /usr/local/bundle/bin/rspec:23:in `<main>'
        19: from /usr/local/bundle/bin/rspec:23:in `load'
        18: from /usr/local/bundle/gems/rspec-core-3.10.0/exe/rspec:4:in `<top (required)>'
        17: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:45:in `invoke'
        16: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:71:in `run'
        15: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:86:in `run'
        14: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:104:in `setup'
        13: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/runner.rb:104:in `ensure in setup'
        12: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/world.rb:188:in `announce_filters'
        11: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/world.rb:196:in `report_filter_message'
        10: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/reporter.rb:100:in `message'
         9: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/reporter.rb:207:in `notify'
         8: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/reporter.rb:236:in `ensure_listeners_ready'
         7: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/reporter.rb:47:in `block in prepare_default'
         6: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/formatters.rb:127:in `setup_default'
         5: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/formatters.rb:152:in `add'
         4: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/formatters.rb:182:in `find_formatter'
         3: from /usr/local/bundle/gems/rspec-core-3.10.0/lib/rspec/core/formatters.rb:212:in `built_in_formatter'
         2: from /usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:156:in `require'
         1: from /usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:168:in `rescue in require'
/usr/local/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:168:in `require': cannot load such file -- rspec/core/formatters/progress_formatter (LoadError)

解決策

無駄に生成されたコンテナを削除します。

Doker for desktopを開いて削除できます。

無駄に生成したコンテナを削除する

コマンドからdoker psなどで探した後に削除するのでもいいと思います。

削除できない時はDocker for Desktopを再起動したりすればたいてい何とかなります。

再起動は偉大。