数時間ほどハマってようやくたどり着いたのでメモ。
やりたいこと
Amazon ECSのタスクでコンテナ実行時に簡単なスクリプトファイルを作成して実行したかったのです。
print('hoge')
if False:
print('no print')
みたいなPythonのファイルを作成して、python hoge.py
するっていう。
インデントが効くか確認するためにif False:
とかしてます。
docker run
コマンドだと
お手元の端末でdocker
コマンドが利用できる前提で。
cat
コマンドでファイル作成
cat
コマンドでヒアドキュメントを利用すると簡単にできます。
ヒアドキュメントについては下記が参考になります。
知ると便利なヒアドキュメント - Qiita
https://qiita.com/kite_999/items/e77fb521fc39454244e7
> docker run -it --rm --entrypoint="sh" \
python:3.7 \
-c "cat <<EOF > hoge.py
# hogeって出力
print('hoge')
if False:
# インデントが効くか
print('no print')
EOF
cat hoge.py;python hoge.py;"
# hogeって出力
print('hoge')
if False:
# インデントが効くか
print('no print')
hoge
なんとなくdocker run
コマンド側のインデントに合わせたくなりますが、そうするとヒアドキュメントのルール「EOF
が単独で現れると終了」から外れてしまうので、後続のコマンドが巻き込まれてしまいます。
> docker run -it --rm --entrypoint="sh" \
python:3.7 \
-c "cat <<EOF > hoge.py
# hogeって出力
print('hoge')
if False:
# インデントが効くか
print('no print')
EOF
cat hoge.py;python hoge.py;"
# 出力なし
cat <<-EOF > hoge.py
と<<
を<<-
に変更して行頭のタブを無視してみましたが、sh -c
で実行しているのが原因なのかダメでした。またエディタを利用しているとタブ→スペース変換されたりするのでムダにハマりそうです。
Pythonの実装でもムダにインデントがあると怒られるので諦めます。
> docker run -it --rm --entrypoint="sh" \
python:3.7 \
-c "cat <<EOF > hoge.py
# hogeって出力
print('hoge')
if False:
# インデントが効くか
print('no print')
EOF
cat hoge.py;python hoge.py;"
# hogeって出力
print('hoge')
if False:
# インデントが効くか
print('no print')
File "hoge.py", line 2
print('hoge')
^
IndentationError: unexpected indent
echo
コマンドでファイル作成
echo
コマンドでも複数行を改行付きで出力できるので、cat
コマンドと同じことが実現できました。
Dockerfileで複数行を改行付きでechoする際にハマったので共有しておきます | ゲンゾウ用ポストイット
https://genzouw.com/entry/2019/04/17/080500
-c
のあと、コンテナ内で実行するコマンドをダブルクォーテーション("
)で括り、echo
コマンドで出力する文字列をエスケープ記号を付与したダブルクォーテーション(\"
) にして、Python実装ではシングルクォーテーション('
)を利用すると説明は長ったらしいですが、多分スッキリします。
こちらもインデントに気をつける必要がありました。
> docker run -it --rm --entrypoint="sh" \
python:3.7 \
-c "echo \"
# hogeって出力
print('hoge')
if False:
# インデントが効くか
print('no print')
\" > hoge.py;cat hoge.py;python hoge.py;"
# hogeって出力
print('hoge')
if False:
# インデントが効くか
print('no print')
hoge
Amazon ECSタスク定義だと
本題ですが、下記のように定義してやると実現できました。
マネジメントコンソールとかで
- イメージ: python:3.7
- エンドポイント: ["sh", "-c"]
- コマンド: ["echo "# hogeって出力\nprint('hoge')\nif False:\n\t# インデントが効くか\n\tprint('no print')" > hoge.py;cat hoge.py;python hoge.py;"]
1行で定義しないとだめなので、改行を\n
、インデントのタブを\t
に置き換える必要があります。(インデントは半角スペースでもOK)
試しに改行やタブをそのままでマネジメントコンソールのテキストボックスにコピペってみましたがダメでした(´・ω・`)
cat
コマンドでヒアドキュメントを利用する方法も試してみましたが、どうにも思った結果が得られず断念しました。
AWS CloudFormationだと
AWS CloudFormationだとYAMLで定義できるのでおすすめです。
AWS::ECS::TaskDefinition
の詳細については下記を参考ください。
AWS::ECS::TaskDefinition - AWS CloudFormation
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-taskdefinition.html
YAML中で改行を含ませる方法は下記を参考にさせてもらいました。
YAMLで値の中に改行を含ませる - 日々此妄想
https://hana-da.hatenadiary.org/entry/20081222/1229930738
Resources:
(略)
ECSTaskDefinitionSample:
Type: AWS::ECS::TaskDefinition
Properties:
Family: "ECSTaskDefinitionSample"
Cpu: 256
Memory: 512
TaskRoleArn: !Ref ECSTaskRole
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
ContainerDefinitions:
- Name: test
Image: python:3.7
EntryPoint:
- sh
- -c
Command:
- |-
echo "
# hogeって出力
print('hoge')
if False:
# インデントが効くか
print('no print')
" > hoge.py;
cat hoge.py;
python hoge.py;
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: /ecs/test/
awslogs-region: !Sub "${AWS::Region}"
awslogs-stream-prefix: hoge
作成したAmazon ESCのタスク定義からタスク実行すると下記のようにログ出力されて思ったとおりに実行されたことがわかります。
aws logs get-log-events
コマンドでいい感じにログを取得する方法は下記が参考になります。
Amazon CloudWatch LogsのログをAWS CLIでいい感じに取得する - Qiita
https://qiita.com/kai_kou/items/60bbe314b74b9eaf7126
> aws logs get-log-events \
--log-group-name <ロググループ名> \
--log-stream-name <ストリーム名> \
--query "events[].[message]" \
--output text
# hogeって出力
print('hoge')
if False:
# インデントが効くか
print('no print')
hoge
まとめ
せっかくのコンテナサービスなんだからDockerイメージ作れって話ではあるのですが、ほんとにちょっとしたファイルを作成したいときに使えるかなと思います。
参考
知ると便利なヒアドキュメント - Qiita
https://qiita.com/kite_999/items/e77fb521fc39454244e7
Dockerfileで複数行を改行付きでechoする際にハマったので共有しておきます | ゲンゾウ用ポストイット
https://genzouw.com/entry/2019/04/17/080500
AWS::ECS::TaskDefinition - AWS CloudFormation
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-taskdefinition.html
YAMLで値の中に改行を含ませる - 日々此妄想
https://hana-da.hatenadiary.org/entry/20081222/1229930738
Amazon CloudWatch LogsのログをAWS CLIでいい感じに取得する - Qiita
https://qiita.com/kai_kou/items/60bbe314b74b9eaf7126