この記事は、 Docker Advent Calendar 2022 の 23日目の記事だ。
空いていたので埋めちゃうよ。
この記事では、 bash や ash で任意のコードの実行後、ターミナルを終了せずに入力待ちにする方法について紹介する。
特に、 docker run
の実行後に、その環境を維持したまま入力待ちにすることを考える。
例えば、 Windows コマンドプロンプトや PowerShell であれば、 CMD /K ***
オプションや、 -NoExit -Command ***
オプションで実現できるような内容だ。
本来なら、 docker build にてその任意コードの実行後の内容をイメージにするべきだが、 わざわざ build するまでもないとか、 build できない事情などもあるかもしれない。
ということで、 bash の場合と、 alpine などで使われる BusyBox ash それぞれについて、 docker run
実行時に任意コード実行後、ターミナルの入力待ちにする方法を紹介する。
bash の場合、 --rcfile
オプションにて、起動時に実行するコマンドを指定できる。
ただし、 --rcfile
はファイルを指定する必要があるため、 替わりにプロセス置換で実行コードを与えてやる方法をとる。
[email protected]:~$ docker run --rm -it debian:bullseye bash -c "bash --rcfile <(echo 'ls && export '\''FOO=B A R'\'' && MY_TIME=\$(date)')"
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
[email protected]:/# echo $FOO : $MY_TIME
B A R : Thu Dec 22 15:00:00 UTC 2022
[email protected]:/#
プロセス置換はコンテナ内で実行される必要があるため、一旦 bash -c
にてコンテナ内で bash 実行させ、その中で改めて --rcfile
オプションを指定した bash を起動する流れとなる。
実際に実行したいコマンドは、 echo で文字列として書き出す。
上記例では、 ls && export 'FOO=B A R' && MY_TIME=$(date)
と言う文字列を echo させている。
引用符が二重三重になっていて、エスケープが非常に難しくなっているので注意。
alpine 3.15 以降に含まれる BusyBox の ash であれば、意外にもプロセス置換が使える。
しかし、 --rcfile
に相当するオプションは残念ながら無い。
替わりに、 ash には ENV
という環境変数に記載されたファイルを ash 起動時に実行する機能がある。
これを使おう。
[email protected]:~$ docker run --rm -it alpine:3.15 ash -c "ash -c 'export ENV=\$1;ash' -s <(echo 'ls && export '\''FOO=B A R'\'' && MY_TIME=\$(date)')"
bin etc lib mnt proc run srv tmp var
dev home media opt root sbin sys usr
/ # echo $FOO : $MY_TIME
B A R : Thu Dec 22 15:00:00 UTC 2022
/ #
ash
の -c
のコマンドに対して引数を与える -s
オプションを使ってプロセス置換のファイルを与え、 それを $1
経由で ENV
環境変数にセット。 その状態で再度 ash を起動させれば、 bash と同様のことが行える。
ENV 環境変数に直接プロセス置換のファイルを指定せず、わざわざ一旦引数を経由させているのは、 入力を受け付ける ash プロセスが動いている間、 プロセス置換のファイルにアクセス可能にする必要があるためだ。
例えば、 export ENV=<(echo 'command');ash
と実行しても、 ash 実行の段階ではプロセス置換のファイルが閉じられているので、コマンドは実行されない。
起動時に apt パッケージマネージャーのリポジトリを書き換える方法(Ubuntu):
docker run --rm -it ubuntu:22.04 bash -c "bash --rcfile <(echo 'sed -i -E '\''s%^(deb(-src|)\s+)https?://(archive|security)\.ubuntu\.com/ubuntu/%\1http://srv2.ftp.ne.jp/Linux/packages/ubuntu/archive/%'\'' /etc/apt/sources.list && apt update && FooBar=`date -uIs`')"
起動時に apk パッケージマネージャーのリポジトリを書き換える方法(Alpine):
docker run --rm -it alpine:3.15 ash -c "ash -c 'export ENV=\$1;ash' -s <(echo 'sed -i -E '\''s%^https?://dl-cdn\.alpinelinux\.org/alpine/%https://ftp.udx.icscoe.jp/Linux/alpine/%'\'' /etc/apk/repositories && apk update && FooBar=`date -uIs`')"
参考: https://stackoverflow.com/questions/74094552/how-not-to-terminate-after-carried-out-commands-in-bash
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント