pytest
の起動時に失敗するので、原因を把握するのに時間がかかってしまいました。
環境
- Docker
- Docker version 20.10.13, build a224086
- Docker Compose
- docker-compose version 1.29.2, build 5becea4c
- Windows
- Macだと発生しない事象のようです
前提
Docker Composeのボリュームにread_only
属性が設定されている。
原因
pytestが/tmp
ディレクトリに何かしらの書き込みをしようとしています。
read_only
属性がついている場合、書き込み先ディレクトリをvolumes
に設定する必要があります。
volumes
に/tmp
が設定されていないため、書き込みができずにエラーとなっているようです。
対策
volumes
に/tmp
を追加します。
services: api: read_only: true # 前提 volumes: - /tmp # 追加
ソースコード
終わりに
read_only
属性はホスト側に余計な情報を書き込ませないようにするためのもので、コンテナ内のディレクトリについて制限するものではないと思っていました。もし、コンテナ内のディレクトリを制限するものだとしても、/tmp
ディレクトリに関しては常に全権限与えられているものだという思い込みがあったので、調査に時間がかかってしまいました。
しかもなぜかpytest
ではエラーとなるが、pytest -s
では正常に動くという謎挙動をしておりました。-s
は詳細ログを出すようにするためのオプションだと思っていたのですが、標準出力先が違うのかもしれませんね(未検証)
事象自体はpytest
に限らないと思うので、ぜひ同事象に引っかかったら教えていただけると、記事に載せていただこうと考えています。
この記事がお役に立ちましたら、各種SNSでのシェアや、今後も情報発信しますのでフォローよろしくお願いします。
参考情報
発生ログ
$ docker-compose run --entrypoint "poetry run pytest --asyncio-mode=strict" api Creating fastapi-practice_api_run ... done ============================================================ test session starts ============================================================ platform linux -- Python 3.9.12, pytest-7.1.1, pluggy-1.0.0 rootdir: /src plugins: anyio-3.5.0, asyncio-0.18.3 asyncio: mode=strict collected 0 items =========================================================== no tests ran in 0.17s =========================================================== Traceback (most recent call last): File "/src/.venv/lib/python3.9/site-packages/_pytest/main.py", line 268, in wrap_session session.exitstatus = doit(config, session) or 0 File "/src/.venv/lib/python3.9/site-packages/_pytest/main.py", line 321, in _main config.hook.pytest_collection(session=session) File "/src/.venv/lib/python3.9/site-packages/pluggy/_hooks.py", line 265, in __call__ return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult) File "/src/.venv/lib/python3.9/site-packages/pluggy/_manager.py", line 80, in _hookexec return self._inner_hookexec(hook_name, methods, kwargs, firstresult) File "/src/.venv/lib/python3.9/site-packages/pluggy/_callers.py", line 60, in _multicall return outcome.get_result() File "/src/.venv/lib/python3.9/site-packages/pluggy/_result.py", line 60, in get_result raise ex[1].with_traceback(ex[2]) File "/src/.venv/lib/python3.9/site-packages/pluggy/_callers.py", line 39, in _multicall res = hook_impl.function(*args) File "/src/.venv/lib/python3.9/site-packages/_pytest/main.py", line 332, in pytest_collection session.perform_collect() File "/src/.venv/lib/python3.9/site-packages/_pytest/main.py", line 657, in perform_collect self.items.extend(self.genitems(node)) File "/src/.venv/lib/python3.9/site-packages/_pytest/main.py", line 824, in genitems rep = collect_one_node(node) File "/src/.venv/lib/python3.9/site-packages/_pytest/runner.py", line 537, in collect_one_node rep: CollectReport = ihook.pytest_make_collect_report(collector=collector) File "/src/.venv/lib/python3.9/site-packages/pluggy/_hooks.py", line 265, in __call__ return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult) File "/src/.venv/lib/python3.9/site-packages/pluggy/_manager.py", line 80, in _hookexec return self._inner_hookexec(hook_name, methods, kwargs, firstresult) File "/src/.venv/lib/python3.9/site-packages/pluggy/_callers.py", line 55, in _multicall gen.send(outcome) File "/src/.venv/lib/python3.9/site-packages/_pytest/capture.py", line 769, in pytest_make_collect_report out, err = self.read_global_capture() File "/src/.venv/lib/python3.9/site-packages/_pytest/capture.py", line 691, in read_global_capture return self._global_capturing.readouterr() File "/src/.venv/lib/python3.9/site-packages/_pytest/capture.py", line 596, in readouterr out = self.out.snap() if self.out else "" File "/src/.venv/lib/python3.9/site-packages/_pytest/capture.py", line 457, in snap self.tmpfile.truncate() FileNotFoundError: [Errno 2] No such file or directory During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/src/.venv/lib/python3.9/site-packages/_pytest/main.py", line 288, in wrap_session config.notify_exception(excinfo, config.option) File "/src/.venv/lib/python3.9/site-packages/_pytest/config/__init__.py", line 1050, in notify_exception res = self.hook.pytest_internalerror(excrepr=excrepr, excinfo=excinfo) File "/src/.venv/lib/python3.9/site-packages/pluggy/_hooks.py", line 265, in __call__ return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult) File "/src/.venv/lib/python3.9/site-packages/pluggy/_manager.py", line 80, in _hookexec return self._inner_hookexec(hook_name, methods, kwargs, firstresult) File "/src/.venv/lib/python3.9/site-packages/pluggy/_callers.py", line 60, in _multicall return outcome.get_result() File "/src/.venv/lib/python3.9/site-packages/pluggy/_result.py", line 60, in get_result raise ex[1].with_traceback(ex[2]) File "/src/.venv/lib/python3.9/site-packages/pluggy/_callers.py", line 39, in _multicall res = hook_impl.function(*args) File "/src/.venv/lib/python3.9/site-packages/_pytest/capture.py", line 799, in pytest_internalerror self.stop_global_capturing() File "/src/.venv/lib/python3.9/site-packages/_pytest/capture.py", line 666, in stop_global_capturing self._global_capturing.pop_outerr_to_orig() File "/src/.venv/lib/python3.9/site-packages/_pytest/capture.py", line 552, in pop_outerr_to_orig out, err = self.readouterr() File "/src/.venv/lib/python3.9/site-packages/_pytest/capture.py", line 596, in readouterr out = self.out.snap() if self.out else "" File "/src/.venv/lib/python3.9/site-packages/_pytest/capture.py", line 457, in snap self.tmpfile.truncate() FileNotFoundError: [Errno 2] No such file or directory During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/src/.venv/bin/pytest", line 8, in <module> sys.exit(console_main()) File "/src/.venv/lib/python3.9/site-packages/_pytest/config/__init__.py", line 187, in console_main code = main() File "/src/.venv/lib/python3.9/site-packages/_pytest/config/__init__.py", line 164, in main ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main( File "/src/.venv/lib/python3.9/site-packages/pluggy/_hooks.py", line 265, in __call__ return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult) File "/src/.venv/lib/python3.9/site-packages/pluggy/_manager.py", line 80, in _hookexec return self._inner_hookexec(hook_name, methods, kwargs, firstresult) File "/src/.venv/lib/python3.9/site-packages/pluggy/_callers.py", line 60, in _multicall return outcome.get_result() File "/src/.venv/lib/python3.9/site-packages/pluggy/_result.py", line 60, in get_result raise ex[1].with_traceback(ex[2]) File "/src/.venv/lib/python3.9/site-packages/pluggy/_callers.py", line 39, in _multicall res = hook_impl.function(*args) File "/src/.venv/lib/python3.9/site-packages/_pytest/main.py", line 315, in pytest_cmdline_main return wrap_session(config, _main) File "/src/.venv/lib/python3.9/site-packages/_pytest/main.py", line 310, in wrap_session config._ensure_unconfigure() File "/src/.venv/lib/python3.9/site-packages/_pytest/config/__init__.py", line 1004, in _ensure_unconfigure fin() File "/src/.venv/lib/python3.9/site-packages/_pytest/capture.py", line 666, in stop_global_capturing self._global_capturing.pop_outerr_to_orig() File "/src/.venv/lib/python3.9/site-packages/_pytest/capture.py", line 552, in pop_outerr_to_orig out, err = self.readouterr() File "/src/.venv/lib/python3.9/site-packages/_pytest/capture.py", line 596, in readouterr out = self.out.snap() if self.out else "" File "/src/.venv/lib/python3.9/site-packages/_pytest/capture.py", line 457, in snap self.tmpfile.truncate() FileNotFoundError: [Errno 2] No such file or directory ERROR: 1