事象 (Occurred Event)
AWS ECS Fargate上でPythonバッチを実行した際、以下のエラーにより処理が停止しました。
FileNotFoundError: [Errno 2] No such file or directory: 'RSS.json'
ローカル環境(VSCodeやターミナル)では正常に完走していたコードが、デプロイ後のコンテナ環境でのみ実行に失敗する事態が発生。
問題 (Problem)
Pythonの open() 関数における相対パス指定の解釈が、プロセスの実行場所(カレントディレクトリ)に依存していることが根本的な問題です。
-
ローカル環境: スクリプトが存在するディレクトリ(
app/batch/)まで移動して実行するため、open('RSS.json')の探索が成功する。 -
ECS環境: Dockerfileの
WORKDIR /appからpython app/batch/main.pyを実行。Pythonの「今いる場所(.)」は/appであるが、ファイルは/app/app/batch/RSS.jsonに存在するため、探索位置が 2 階層分 ズレている。
原因 (Cause)
Dockerコンテナ内のファイル配置構造と、実行時のカレントディレクトリの不整合によるものです。
実行プロセスが認識しているカレントディレクトリからの相対パスの「乖離」があったため、標準的な相対パス指定ではファイルへの到達が不可能となっていました。
対策 (Countermeasure)
カレントディレクトリがどこであっても、**実行中のスクリプトファイル自身の場所を起点とした「動的な絶対パス生成」**を実装することで解決します。これにより環境依存を完全に排除します。
修正前のコード(相対パス)
def get_news():
# 実行場所がズレると FileNotFoundError になる
with open('RSS.json') as f:
RSS_list = json.load(f)
修正後のコード(動的絶対パス)
import os
def get_news():
# 1. このスクリプト自身の絶対パスを取得
current_script_path = os.path.abspath(__file__)
# 2. スクリプトがあるディレクトリパスを特定
base_dir = os.path.dirname(current_script_path)
# 3. ディレクトリパスとファイル名を結合して絶対パスを生成
json_path = os.path.join(base_dir, 'RSS.json')
# 生成した絶対パスでファイルを開く(エンコーディングも指定して堅牢性をUP)
with open(json_path, encoding='utf-8') as f:
RSS_list = json.load(f)
結果 (Result)
- エラー発生率: 100% → 0% に改善。
- 環境的可搬性: ローカル、GitHub Actions、ECS Fargateのいずれの環境においても、パスの修正なしで動作することを確認。
- メンテナンスコスト: ディレクトリ階層の変更があった際も、ファイルが「隣り合っている」限り修正は不要となり、パス関連のデバッグ時間を大幅に短縮。
教訓: 「ローカルで動いた」はコンテナ環境での動作を保証しません。Pythonにおける外部ファイル読み込みは、__file__ を起点とした絶対パス指定をデフォルトのプラクティスとすべきです。