ドキュメントに細かいことが書いてなかったのでメモしておく。
digdag のバージョンは v0.9.31
まえおき: digdag タスクの docker 実行
_export
に docker オプションを指定すると各タスクが docker run で実行されるようになる。この機能についての解説。digdag 自体を Docker に入れ込むとかは別の話。
_export:
docker:
image: ubuntu
+task1:
py>: tasks.MyWorkflow.task1
digdag docker オプションのオプション
必須パラメータである image
に加えて以下の2つのオプションが使える
- build: String
- pull_always: Boolean
build
build を指定すると docker build が走る
_export:
docker:
image: ubuntu:latest
build: |
apt install -y git
+task1:
py>: tasks.MyWorkflow.task1
pull_always
pull_always: true
とすると各タスクが実行される度に docker pull を試すようになる。
いまのところ、ワークフロー全体で最初に1度だけ docker pull するような機能はなさそうだ。
_export:
docker:
image: ubuntu:latest
pull_always: true
+task1:
py>: tasks.MyWorkflow.task1
コンテナ内で実行されるのは CommandExecutor なオペレータのみ
コマンドとして実行されるオペレータのみ docker run される。現状では以下の4つのみ
- py>:
- rb>:
- sh>:
- embulk>: (deprecated)
他のオペレータ (echo, s3_wait, gcs_wait など) は java ライブラリとして実装されていることもあり、docker コンテナ内ではなく、docker ホスト上で実行される。docker コンテナに GCP の鍵を登録してあっても、例えば gcs_wait はその鍵を使ってくれないので、この違いを認識しておく必要がある。
コンテナ内のファイルシステムに書いたファイルは消える
タスクそれぞれが docker run されるので、コンテナ内のファイルシステムに書いたファイルは消える。
_export:
docker:
image: ubuntu
+task1:
sh>: touch /tmp/test
+task2:
sh>: ls /tmp/test # <- Not found
そのため &&
でつなげて実行するなどしないといけない。
_export:
docker:
image: ubuntu
+task1:
sh>: |
touch /tmp/test &&
ls /tmp/test
docker run に渡されるオプション
現行のv0.9.31では、タスクごとに以下のような docker run を実行しているようだ。
FYI: digdag 実行時に -l debug
オプションをつけると確認できる。
$ docker run -i --rm -v プロジェクトパス:プロジェクトパス \
-w プロジェクトパス -e 環境変数=値... イメージ名 コマンド
ポイントは以下のあたり
- プロジェクトパスが docker コンテナにマウントされる
- ワーキングディレクトリが Dockerfile の
WORKDIR
から digdag のプロジェクトパスに変更される - ホストの環境変数がコンテナに引き継がれる (
HOME
やUSER
も変更される)
プロジェクトパスは、digdag run の場合は実行しているプロジェクトのパスで、digdag server の場合は /tmp 下のてきとうな tmp ディレクトリにプロジェクトファイルが撒かれて使われる。その tmp ディレクトリはコマンド実行が終わったら消される。
そのため digdag run の時はカレントディレクトリ以下に書いたファイルは docker ホストに永続化できる。digdag server の時は結局消されるので永続化のつもりでは使えない。
また、digdag server が作る tmp ディレクトリを docker コンテナから読み書きできるようにしておく必要がある。docker コンテナ内を root (uid: 0) ユーザにしておくとか、digdag server を動かすユーザの uid と、Dockerfile の USER で指定するユーザの uid を合わせておく必要がある。
3によって、環境変数が上書きされるのは特に注意が必要。Docker 内で HOME
環境変数を使っているような場合(ほとんどそう)にハマるので、Tips としては以下のように HOME
環境変数を設定して元に戻してあげるのが良い。
_export:
HOME: もともとDockerfileで想定していたWORKDIR
docker:
...
所感: これは ... 余計なお世話度が高いような...
digdag secrets で登録した値を docker から参照したい
digdag secrets で渡した値を _env
で環境変数として渡せばなんとかできる。
oO(_env
はタスク毎に設定しないといけないのでかなり面倒
+docker_run:
_env:
secret_gcp_credential: ${secret:gcp.credential}
secret_aws_access_key_id: ${secret:aws.access_key_id}
secret_aws_secret_access_key: ${secret:aws_secret_access_key}
sh>: echo test
FYI: ちなみに digdag secrets --set gcp.credentail=@gcpcredential.json
のようにファイルで渡したものは ${secret:gcp.crecential}
ではファイル内容が文字列として展開される。
Dockerfile では docker イメージに入れ込まないようにして、ENTRYPOINT で起動時に配置するようにすると digdag secrets から値を取れたことになる。
....
COPY docker-entrypoint.sh docker-entrypoint.sh
ENTRYPOINT ["./docker-entrypoint.sh"]
docker-entorypoint.sh
#!/bin/bash
# Add aws credential
mkdir -p .aws
cat > .aws/credentials <<EOF
[default]
aws_access_key_id = ${secret_aws_access_key_id}
aws_secret_access_key = ${secret_aws_secret_access_key}
EOF
# Add gcp credential and activate
mkdir -p .credential
echo "${secret_gcp_credential}" > .credential/gcpcredential.json
gcloud auth activate-service-account xxxxx --key-file .credential/gcpcredential.json --project xxxxx
exec "$@"
(AWSクレデンシャルに関しては、aws cli も aws sdk も環境変数 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY に対応してるのでそちらを使っても良さそう)
SEE ALSO: digdag secrets を global な環境変数にマップする - Qiita
docker pull の前に $(aws ecr get-login) したい
Amazon ECR レジストリ に docker イメージを push している場合、$(aws ecr get-login)
のようにして docker login してからでないと docker pull できない。12時間でログイントークンが expire されるので厄介なやつ。
+docker_login:
sh>: eval $(aws ecr get-login --no-include-email)
+docker_run:
_export:
docker:
image: ubuntu:latest
pull_always: true
+task1:
py>: tasks.MyWorkflow.task1
このように書けば1台構成の場合は、docker login してから、以降のタスクを実行できるので、確実に docker pull できる。
しかし、複数台構成の場合、タスク毎にどのホストで実行されるかが不定なので、docker login していないホストで docker pull && docker run しようとして失敗する可能性がある。
色々調べた結論としては、https://github.com/awslabs/amazon-ecr-credential-helper を使うと、docker login を省いて docker pull できるようになり、digdag 側で頑張らなくても解決できるのでオススメする。
その際 ~/.docker/config.json
には
{"credsStore": "ecr-login"}
よりも
{
"credHelpers": {
"<aws_account_id>.dkr.ecr.<region>.amazonaws.com": "ecr-login"
}
}
のように設定するのをオススメする。前者の場合、ECR 以外の例えば docker hub のイメージを pull する場合も ecr-login を試して ERROR メッセージが表示されてしまう(実際には docker pull は成功するが).
docker run のオプションを設定したい
EDIT: 0.9.37 から docker run のオプションを指定できるようになりました。https://github.com/treasure-data/digdag/pull/1025
以下、古い文書
いまのところ、docker run のオプションを自由に設定する _export: docker:
のオプションはない。
発想の転換で、_export: docker:
を使わず sh>:
で docker run してしまえば自由度は得られる。好きなタイミングで docker pull も docker login もできる。
_export:
docker_image: ubuntu
docker_run: docker run -i --rm -v /tmp:/tmp ${docker_image}
+docker_pull:
sh>: docker pull ${docker_image}
+task1:
sh>: ${docker_run} コマンド
ポイントまとめ
- コンテナ内で実行されるのは CommandExecutor なオペレータ(py, rb, sh) のみ
- コンテナ内でローカルに書いたファイルは揮発する (--volume オプションの設定もできない)
- ホスト側の環境変数でコンテナ側の環境変数が上書きされる
- (今の所)docker のオプションを自由に設定することはできないので、どうしても必要なら
_export: docker:
をやめてsh>: docker run
するしかない...
要望まとめ
- ホスト側の環境変数が全部引き継がれるのはちょっと余計なお世話度が高いような...
- docker run の
--volume
オプションとか色々オプション追加サポートして欲しい。とりあえず EFS マウントしたい。 - docker run の前に確実に docker login するようなオプションもあっても良いかもしれない (その時は
$(aws ecr get-login)
が実行できるようにシェル実行サポートして欲しい)