コンテナにファイルをコピーせずスクリプトを実行する

たぶん役に立たない豆知識です。

ssh接続したリモートホストにファイルをコピーせずにシェルスクリプトを実行する方法を知っている方も多いと思います。

ssh $HOSTNAME bash -s <./main.sh

リモートホストで起動したbashに、ローカルホストのmain.shの内容が標準入力経由で渡されて実行されるテクニックになります。 単純にこのテクニックをコンテナでも使おうという話になります。

Dockerコンテナで実行する

オプションについての詳細は省きますが、runでもexecでも-iオプションをつけて実行するだけです。

# run
docker run --rm -i ubuntu:latest bash -s <./main.sh

# exec
docker exec -i $CONTAINER_NAME bash -s <./main.sh

この時気をつけることなんですが、-tオプションをつけないことが重要です。
-tオプションを付与すると、エラーが表示されます。(エラーが表示されているものの実行されていないかどうかは未確認)

$ docker run --rm -it ubuntu:latest bash -s <./main.sh
the input device is not a TTY

こういったテクニックを使えば、ローカルにあるファイルをコピーやマウントせずとも、
標準入力経由でファイルの内容を渡して実行することができます。

例えばRubyスクリプトであれば、以下のように実行することができます。

docker run --rm -i ruby:3 ruby <./main.rb

他にも標準入力から受け取ることができるツールであれば、大体応用できます。(psqlなど)

Kubernetesのコンテナで実行する

さて、Dockerコンテナでもできたのであれば、コマンド体系が似ているKubernetesで動いているコンテナでもできるでしょうか?

答えは可能です。

kubectl exec -i $POD_NAME -- bash -s <./main.sh

kubectlの場合は、-tをつけてもDockerと同様にエラーは表示されるものの、
スクリプト内のechoなどで出力した文字列も表示されているので実行されているようです。

まとめ

たぶん役に立たない「コンテナにファイルをコピーせずスクリプトを実行する」方法について紹介しました。
kubectl execに関しては賛否両論がありそうですが、docker run に関してはファイルをコピーせずとも動作確認が気軽にできるので役立つ時が来るかもしれません。

気が向いたら、また役に立たなそうな豆知識を書くかもしれません。