Ponz Dev Log

ソース派のシステムエンジニアの開発日記

AWS Batchに渡したCommandがプログラムの引数に渡らない時はDockerfileを見よう

お仕事でも使ってるAWS BatchでCommandに渡した値がプログラム(Javaだとmain関数のargs部分)に渡ってこなくてハマった時の対象方法メモ。 AWSの公式ドキュメントが分かりずらいので、Dockerのドキュメントも参照しながら解決しました。

Commandとコマンドライン引数の関係

そもそもの話。AWS Batchのコンテナプロパティ"Command"はDockerfileに記述されたどの部分にマッピングされるのだろうか? AWS Batchのジョブ定義のパラメータのセクションを見ると以下のように書いてあります。

このパラメータは、Docker Remote API の コンテナを作成する セクションの Cmd にマッピングし、 COMMAND パラメータを docker run にマッピングします。Docker CMD パラメーターの詳細については、https://docs.docker.com/engine/reference/builder/#cmd を参照してください。

🤔???

分かりづらいので噛み砕いて説明します。。。AWS Batchに渡されたジョブ定義のCommandはdocker runの後に続くパラメータとして渡されます。Dockerfile内での記述でどうも引数の渡され方の挙動が変わる らしく、以下のような感じになります。

  • CMDでコマンドを指定した --> ジョブ定義で指定したCommandの1番目が実行可能バイナリ、2番目以降が引数となる
  • ENTRYPOINTでコマンドを指定した --> ジョブ定義で指定したCommandが全てENTRYPOINTのコマンドの引数となる
  • CMDとENTRYPOINTでコマンドを指定した --> ジョブ定義で指定したCommandが全てENTRYPOINTのコマンドの引数となる

3番目のパターンに関してはDockerのドキュメントの方に以下のようなコメントがありました。

If the image also specifies an ENTRYPOINT then the CMD or COMMAND get appended as arguments to the ENTRYPOINT

例えば下のようなDockerfileに対してジョブ定義のコマンドで "hoge fuga"と渡した場合は java -jar /app/application.jar hoge fuga となります。 混乱しないようにするためには、Dockerfile内はENTRYPOINTのみ指定して、ジョブ定義は引数扱いにした方が良いですね。

FROM openjdk:8-alpine
COPY target/scala-2.12/args-logger-1.0.0.jar /app/application.jar
ENTRYPOINT ["java", "-jar", "/app/application.jar"]

今回引っかかったところはDockerfileでCMDを指定したつもりでコマンドを書いていたら実はENTRYPOINTだったから引数が欠けてしまったというオチでした。。。

CommandとParameterの関係

ついでに、ジョブ定義にはCommandとParameterというパラメータがあります。関係性としては、Command内に変数を埋め込んだ場合に実際の値としてParameterの値を入れることになります。値を外から(CloudWatch Eventsで指定した値とか)Parameterとして注入することでアプリ内で動きを変えるといった使い方ができるようです。

DockerfileとCommandとParameterを設定して動かす

実際に動かして確かめます。渡された引数をログ出力するだけのScalaのアプリを使います。 commandパラメータはジョブ定義で以下のように ["Ref::jobType", "Ref::language"] として変数化しました。

f:id:accelerk:20190218002513p:plain

実際に渡したパラメータは下図の通り。

f:id:accelerk:20190218002550p:plain

実際に動かしてみると...

f:id:accelerk:20190218002637p:plain

確かにcommandパラメータにParameterを埋め込んだ値で引数が全て渡っていますね。