Dockerでコマンド出力をリダイレクトする方法
1. 概要
出力のリダイレクトはLinuxでの一般的な操作です。 たとえば、コマンドの出力を分析用のファイルにリダイレクトしたい場合があります。 ただし、出力のリダイレクトは、DockerとLinuxでは異なります。
このチュートリアルでは、Dockerでコマンド出力をリダイレクトする方法について説明します。
2. Dockerの前提条件
空のディレクトリに、次の内容のDockerfileを作成しましょう。
FROM alpine:latest
CMD ["cat", "/etc/alpine-release"]
ここでは、DockerコンテナをAlpineLinuxプロジェクトに基づいています。 コンテナ内で、catコマンドを使用して/ etc/alpine-releaseファイルの内容を表示します。
それでは、このDockerfileを作成しましょう。
$ docker build -t dockeroutput .
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM alpine:latest
---> c059bfaa849c
Step 2/2 : CMD ["cat", "/etc/alpine-release"]
---> Running in 900c4a1f30fe
Removing intermediate container 900c4a1f30fe
---> 6e67a72bd2ae
Successfully built 6e67a72bd2ae
Successfully tagged dockeroutput:latest
次に、コンテナを実行します。
$ docker run dockeroutput
3.15.0
Alpine Dockerコンテナの最新バージョンが変更された場合、出力が異なる可能性があります。
3. Dockerコマンドフォーム
Dockerのコマンドには、exec形式とshell形式の2つの形式があります。
exec形式のコマンドは次のようになります。
CMD ["cat", "/etc/alpine-release"]
対照的に、shell形式の同じコマンドは次のとおりです。
CMD cat /etc/alpine-release
これら2つの形式にはいくつかの違いがあります。 たとえば、 shell 形式では、 $HOME環境変数はホームディレクトリを参照します。 ただし、 exec 形式では、 $HOMEには意味がありません。
したがって、リダイレクト出力もこれら2つの形式で異なります。
4. execフォームでスクリプトを実行する
以前は、Dockerfileでexecフォームを使用しました。
CMD ["cat", "/etc/alpine-release"]
ここで、catコマンドの出力をファイルにリダイレクトするとします。
これはできません:
CMD ["cat", "/etc/alpine-release", ">", "output.txt"]
これを行うと、エラーが発生します。
$ docker run dockeroutput
3.15.0
cat: can't open '>': No such file or directory
cat: can't open 'output.txt': No such file or directory
Dockerは、Dockerfile内のコマンドを、catコマンドが3つの入力ファイル/etc / alpine-release 、> 、および[ X169X]output.txt。
そのため、出力の次の行に示されているように、最初の入力ファイルに対してcatが正常に実行されました。
3.15.0
ただし、>およびoutput.txt という名前のファイルがないため、上記のエラーが発生します。
4.1. Dockerfileの変更
exec フォームは、>記号を出力をリダイレクトする特殊文字として認識しません。 代わりに、記号をファイル名として解釈します。
コマンドの出力をexec形式でリダイレクトするには、コマンドをスクリプトでラップする必要があります。
次の内容でcheck_alpine_release.shという名前のスクリプトを作成しましょう。
#!/bin/sh
cat /etc/alpine-release > /home/output.txt
bashスクリプトでは、>signを自由に使用してコマンド出力をリダイレクトできます。
次に、Dockerfileを変更します。
FROM alpine:latest
COPY check_alpine_release.sh .
RUN chmod +x /check_alpine_release.sh
CMD ["/check_alpine_release.sh"]
ここでは、bashスクリプトをホストからコンテナーにコピーしました。 次に、ファイルを実行可能ファイルに設定します。 最後に、bashスクリプトを実行します。 このようにして、Dockerfileの>記号を回避できます。
4.2. コンテナの実行
Dockerfileをビルドした後、コンテナーを実行してみましょう。
$ docker run -v $(pwd):/home dockeroutput
vオプションを使用してコンテナを実行し、現在のディレクトリをコンテナ内のホームディレクトリにマップできるようにします。 このようにして、コマンドからのstdout出力を受け入れる出力ファイルを提供できます。 つまり、コマンド出力をhomeディレクトリ内のoutput.txtファイルにリダイレクトしました。
コンテナを実行しても出力は得られません。 しかし、ディレクトリにoutput.txtがあることがわかります。
ファイルの内容を見てみましょう。
$ cat output.txt
3.15.0
5. シェルフォームを使用する
出力をリダイレクトするためにbashスクリプトを作成する必要はありません。 代わりに、コマンドで>特殊文字を使用して、シェル形式でDockerのコマンドをリダイレクトできます。
5.1. Dockerfileの変更
Dockerfileを書き直して、次の内容になるようにします。
FROM alpine:latest
CMD cat /etc/alpine-release > /home/output.txt
shell フォームを使用して、出力をファイルにリダイレクトするコマンドを実行しました。
5.2. コンテナの実行
これで、Dockerfileをビルドし、vオプションを使用してコンテナーを実行できます。
$ docker run -v $(pwd):/home dockeroutput
同じ結果が得られます。
$ cat output.txt
3.15.0
6. execフォームでシェルを渡す
もう1つのオプションは、exec形式のシェルを使用することです。 この方法を使用して、目的のシェルを選択することもできます。
6.1. Dockerfileの変更
exec 形式でシェルを使用するには、次のようにDockerfileを記述できます。
FROM alpine:latest
CMD ["/bin/sh", "-c", "cat /etc/alpine-release > /home/output.txt"]
シェルをメインコマンドとして使用して、必要な別のコマンドを実行します。 さらに、シェルコマンドの c オプションは、標準入力ではなく、引数文字列からコマンドを読み取ります。
または、別のシェルを使用することもできます。次に例を示します。
CMD ["/bin/bash", "-c", "cat /etc/alpine-release > /home/output.txt"]
コマンドを分離できないことに注意してください:
CMD ["/bin/sh", "-c", "cat", "/etc/alpine-release", ">", "/home/output.txt"]
コマンドを分離すると、呼び出しは次のようになります。
$ /bin/sh -c cat etc/alpine-release > /home/output.txt
シェルはコマンド文字列としてcatのみを読み取り、残りの引数を無視します。 したがって、これは次のコマンド呼び出しと同じです。
$ /bin/sh -c cat
正しいコマンド呼び出しは次のようになります。
$ /bin/sh -c "cat etc/alpine-release > /home/output.txt"
したがって、コマンド文字列を分離しないでください。
6.2. コンテナの実行
これで、Dockerfileをビルドし、vオプションを使用してコンテナーを実行できます。
$ docker run -v $(pwd):/home dockeroutput
同じ結果が得られます。
$ cat output.txt
3.15.0
7. stdoutとstderrの両方をリダイレクトする
コンテナでのコマンドの出力は、stdoutまたはstderrで行うことができます。 stdout出力とstderr出力を2つの別々のファイルにリダイレクトできます。
これを示すために、catコマンドを使用して2つのファイルの内容を表示します。 最初のファイルは/etc / alpine-release で、2番目のファイルはfile_does_not_exist.txtという存在しないファイルです。
cat は、最初のファイルの内容を stdout、に表示し、2番目のファイルの場合はstderrにエラーを表示します。
Dockerfileを書き直してみましょう。
FROM alpine:latest
CMD cat /etc/alpine-release file_does_not_exist.txt > /home/output.txt 2>/home/error.txt
>/home/output.txt部分はstdout出力をファイルにリダイレクトしますが、2>/home/error.txt部分はをリダイレクトします]stderrを別のファイルに出力します。
Dockerfileをビルドして、コンテナーを実行してみましょう。
$ docker run -v $(pwd):/home dockeroutput
これで、output.txtファイルとerror.txtファイルの両方が取得されます。
$ cat output.txt
3.15.0
$ cat error.txt
cat: can't open 'file_does_not_exist.txt': No such file or directory
8. 出力のフィルタリング
デフォルトでは、コンテナからstdout出力とstderr出力を取得します。 ただし、stdoutまたはstderrの両方を聞く必要がない場合にのみ、それらを聞くことを選択できます。
次の内容でDockerfileを作成しましょう。
FROM alpine:latest
CMD cat /etc/alpine-release file_does_not_exist.txt
次に、Dockerfileをビルドし、コンテナーを実行します。
$ docker run dockeroutput
3.15.0
cat: can't open 'file_does_not_exist.txt': No such file or directory
しかし、 stderr 出力のみを取得し、stdout出力を無視したい場合はどうでしょうか。
aオプションを使用してこれを行うことができます。
$ docker run -a stderr dockeroutput
cat: can't open 'file_does_not_exist.txt': No such file or directory
a オプションは、標準入力、標準出力、または標準エラーに接続するために使用されます。
9. 結論
この記事では、Dockerコンテナでコマンドの出力をリダイレクトする方法を学びました。
最初に、exec形式でコマンドを実行するときに出力をリダイレクトするラッパーとしてbashスクリプトを作成しました。 次に、> 記号を使用して、shell形式でコマンドを実行するときに出力をリダイレクトしました。
最後に、コンテナ内のstdoutとstderrの両方をフィルタリングしてリダイレクトする方法も学びました。