概要
どういうことかというとコンテナ上で動作しているバイナリファイルもしくはコマンドがあるとします
そのコマンドは結果を標準出力に吐くとします
標準出力なのでログファイルには残りません
そんな場合にログファイルに出力させかつホストマシン側でも確認できる方法を紹介します
環境
- Mac OS X 10.12.3
- Docker 1.13.1
標準出力するコマンドの作成
適当で OK です
このファイルをコンテナ上で動作させます
- vim cat echo_loop.sh
#!/bin/sh
while :
do
echo `date`
sleep 1
done
Dockerfile の作成
コンテナとして動作させるためイメージを作成します
イメージには上記のコマンドがインストールされるようにします
- Dockerfile
FROM alpine:latest
COPY ./echo_loop.sh /bin
RUN chmod 755 /bin/echo_loop.sh
CMD ["/bin/sh", "-c", "/bin/echo_loop.sh >> /var/log/echo_loop.log 2>&1"]
イメージの作成とコンテナの起動
ビルドしてできたイメージからとりあえずコンテナを起動します
- docker build -t myalpine .
- docker run -d myalpine
でコンテナが起動したら exec して /var/log/echo_loop.log
に標準出力がリダイレクトされているか確認します
ホストマシンでも見えるようにする
コンテナを起動する時にマウントオプション -v
を指定します
- mkdir log
- cd log
- docker run -d -v $(pwd):/var/log/ myalpine
これでホストマシン側にも echo_loop.log が出力されるようになります
おまけ: ローテーションの挙動を確認する
Mac なので newsyslog を使います
- cd etc/newsyslog.d
- sudo vim echo_loop.conf
# logfilename [owner:group] mode count size when flags [/pid_file] [sig_num]
/Users/hawksnowlog/log/echo_loop.log hawksnowlog:staff 644 5 10 * J
一応設定ファイルの説明をすると
- owner:group・・・hawksnowlog:staff
- mode 「644」・・・ローテーション後のファイルの権限を 644 にする
- count 「5」・・・ 5 世代分残す
- size 「10」・・・10KB 以上だったらローテーションする、「*」の場合はサイズを使わない
- when 「*」・・・時間でローテーションしない、「$D0」の場合は毎日 0 時にローテーション
- flag 「J」・・・bz 圧縮する
ポイントってわけではないですが、他のローテーションツールを使う場合でも権限回りは気をつけてください
ローテーション後に root 権限のファイルになるとコンテナから書き込めなくなります
作成したらローテーションしてみます
- sudo newsyslog -f /etc/newsyslog.d/echo_loop.conf
ログを tail などで見ていると Mar 2 13:07:12 host newsyslog[6655]: logfile turned over due to size>1K
というログがでればローテーション成功です
echo_loop.log.0.bz2 という名前のファイルが新しく出来ていると思います
が、ローテーションした echo_loop.log にはログが出力されません
おそらくコンテナ側に kill シグナルを送信しないといけないのが原因だと思います
logrotate の copytruncate なら問題なく出力されると思います (すいません、試せていません)
https://github.com/docker/docker/issues/7333
当然ですが、コンテナを再起動すればログは問題なく出力を再開します
最後に
コンテナ内で動作しているプロセスの標準出力をホスト側で確認する方法を紹介しました
ローテーション回りがまだ解決していませんが logrotate を使えばいけると思います
わざわざマウントしなくても docker にある log drivers を使えばもっと簡単に管理できると思います
log drivers は別途検証したいなと思っています
初コメです。
返信削除「イメージの作成とコンテナの起動」の欄にて、
「コンテナが起動したら exec して」と記載がありますが、実際のexecコマンドの例を教えて頂けませんか?
ド素人なもので、すみません。
docker exec ef26882ca1bb cat /var/log/echo_loop.log
返信削除こんな感じでログがコンテナ内のファイルに出力されているか確認してください
ef26882ca1bb はコンテナID です
追加で質問です。
返信削除こちらのDockerファイルを参考にubuntuを呼び出し、"ls"の結果をリダイレクトでファイルに出力しようとしたのですが、
まず、Dockerイメージをrunする際に"-d"オプションを付けていても瞬時にexitしてしまいますが、永続的に実行させるにはどうしたら
よいでしょうか?また、runの際にループで保持する方法も試したのですが、execの際に"bash"だけだとコマンド待ちになってしまい、
終了できなくなります。何か良い方法がありましたらご教示頂けると幸いです。宜しくお願い致します。
ls を無限ループさせてコンテナが起動し続けるようにしてみてください
返信削除例えばこんな感じのスクリプトが動作するようにしてください
while true; do ls; sleep 1; done
わざわざ返信ありがとうございます。ご教示頂いた方法をやってみましたが、ファイルではなくコンソールへlsの結果が出力されて、リダイレクトが行われませんでした。Dockerfileの内容ですが、
削除FROM ubuntu
COPY ./list.sh /bin
RUN chmod 755 /bin/list.sh
CMD ["/bin/sh", "-c", "/bin/list.sh >> /tmp/ls.txt 2>&1"]
何か問題が、ありますでしょうか?大変お手数ですが、宜しくお願い致します。
Dockerfile は貼っていただいたものです
返信削除vim list.sh
while true; do ls; sleep 1; done
docker build -t myubuntu .
docker run -d --name test myubuntu
docker exec test cat /tmp/ls.txt
でどうでしょうか、こちらが試した感じだと docker logs には特に何も表示されませんでした
わざわざ試験して頂きましてありがとうございます。こちらで実行してみましたが、"/tmp"フォルダに"ls.txt"のファイルが生成されず、コンソールにlsの結果が表示されるだけでした。私の希望は、lsの結果のリダイレクト(ファイル出力)なのです。一体、どこが問題なのでしょうか?ちなみに環境ですが、OS→ubuntu 18.04 docker→ubuntu18.04用dockerイメージ 試験機→Raspberry Pi 3B+ です。何卒宜しくお願い致します。
削除とりあえず exec でコンテナ上にファイルが作成できていることが確認できたら最後はホスト側でマウントしてから確認してください
返信削除docker run -d -v $(pwd):/var/log/ myalpine
の部分です
このコメントは投稿者によって削除されました。
返信削除迅速な返信ありがとうございます。
返信削除docker rm testのあと、docker run -d -v $(pwd):/tmp/ --name test myubuntuで起動し、docker exec test cat /tmp/ls.txtを実行したところ、lsの結果がファイル出力されていました。本当にありがとうございました!
なんと、2回目の実行ではファイルが作成されなくなりました!docker stop testのあと、docker rm testで削除し、再度、docker run -d -v $(pwd):/tmp/ --name test myubuntuで起動し、docker exec test cat /tmp/ls.txtを実行したところ、/tmpフォルダにls.txtができません。2度目の実行では、何か変わるのでしょうか?
削除何度も投稿申し訳ありません。ファイルは作成されていましたが、作成される場所が/tmpフォルダではなく、実行したフォルダに作成されるようですす。また、lsをループしているため、ファイルの内容がlsを複数回実行したのと同じになってしまいます。lsの結果ですので、出力は1回分で良いのですが、多重に出てしまうのは仕方ないのでしょうか?宜しくお願い致します。
返信削除$(pwd) までマウントしているのでカレントにファイルが見えます
返信削除cd /tmp
してから docker コマンドを実行するか
docker run -d -v /tmp:/tmp/ --name test myubuntu
でどうでしょうか
返信ありがとうございます。確かに、カレントのフォルダに生成されるので、/tmpで実行すれば良い訳ですね。ただ、もう1つの課題である「1回だけ実行」は、lsをループしている限り、不可能でしょうか?私自身では、頭の中が無限ループしそうです。宜しくお願い致します。
返信削除自己解決しました!ループ処理を、
返信削除var=0
while :
do
if [ $var = 0 ]; then
ls
var=1
fi
sleep 1
done
として、lsを1回だけ実行するようにしたところ、リダイレクトされたファイルには1回だけの結果が出力されました。
(自分でも努力せにゃいけませんね)
本当にありがとうございました!