`--container-id` オプションでログ取得ができなかった問題をシェル実行で解決
--container-id フラグが期待通りにログを出力しなかった問題を、echo コマンドをシェル経由で実行する形に修正しました。これにより、コンテナ ID が正しく xargs に渡り、リアルタイムでログが取得できるようになります。
背景
--container-id が指定されたときにログが全く出力されないという不具合が Issue #1841 で報告されました。kamal app logs --container-id=CONTAINER_ID を実行しても、対象コンテナが稼働中でも停止中でも空結果でした。根本原因は、コンテナ ID を供給する echo がシェルで実行されず、xargs に入力が届かなかったことです。
技術的な変更
container_id_command メソッドにシェルラッパーを導入し、文字列型のコンテナ ID を echo で出力する処理を shell ヘルパーで実行するよう変更しました。
@@ -21,7 +21,7 @@ def follow_logs(host:, container_id: nil, timestamps: true, lines: nil, grep: ni
def container_id_command(container_id)
case container_id
when Array then container_id
- when String, Symbol then "echo #{container_id}"
+ when String, Symbol then shell(["echo #{container_id}"])
else current_running_container_id
end
end
この変更により echo がシェル (sh -c) 上で実行され、出力が xargs に正しく渡ります。
テストコードも同様に期待文字列を更新し、シェルラッパーが反映されたことを検証しています。
@@ -486,9 +486,9 @@ class CliAppTest < CliTestCase
test "logs with follow and container_id" do
SSHKit::Backend::Abstract.any_instance.stubs(:exec)
- .with("ssh -t root@1.1.1.1 -p 22 'echo ID123 | xargs docker logs --timestamps --tail 10 --follow 2>&1'")
+ .with("ssh -t root@1.1.1.1 -p 22 'sh -c '\''echo ID123'\'' | xargs docker logs --timestamps --tail 10 --follow 2>&1'")
- assert_match "echo ID123 | xargs docker logs --timestamps --tail 10 --follow 2>&1", run_command("logs", "--follow", "--container-id", "ID123")
+ assert_match "sh -c '\''echo ID123'\'' | xargs docker logs --timestamps --tail 10 --follow 2>&1", run_command("logs", "--follow", "--container-id", "ID123")
end
同様に test/commands/app_test.rb でもローカルコマンド文字列が sh -c 'echo C137' | xargs … へと更新され、シェル実行が保証されることを確認しています。
設計判断
開発者は新たにメソッドを追加するのではなく、既存の shell ヘルパーを活用する方針を採りました。これにより変更箇所は container_id_command のみで済み、Docker ログ取得ロジックや他のフラグとの互換性を保ったまま機能を補完できます。最小限の差分で目的を達成するこのアプローチは、回帰リスクを低減しつつユーザビリティを向上させます。
まとめ
--container-id オプションが正しく機能し、指定したコンテナのログがリアルタイムで取得できるようになりました。shell ラッパーの導入は既存コードへの影響を最小化し、今後の機能拡張でも同様のパターンで安全にシェルコマンドを組み立てられる基盤を提供します。