web-dev-qa-db-ja.com

失敗した `docker build`のファイルシステムを調べるにはどうすればいいですか?

私は開発プロセスのための新しいDockerイメージを構築しようとしています。cpanmname__を使ってさまざまなプロジェクトのベースイメージとしてたくさんのPerlモジュールをインストールします。

Dockerfileの開発中に、一部のモジュールが正しくインストールされなかったため、cpanmname__は失敗コードを返します。

私はもう少しものをインストールするためにaptname__を入手する必要があると確信しています。

私の質問は、ログを調べるために、出力の中で引用されている/.cpanm/workディレクトリをどこで見つけることができるかということです。一般的な場合、失敗したdocker buildコマンドのファイルシステムを調べるにはどうすればいいですか?

朝編集弾丸をかみ、findname__を実行した後、私は発見しました

/var/lib/docker/aufs/diff/3afa404e[...]/.cpanm

これは信頼できるのでしょうか。それとも、必要なものがすべて揃うまで、「ベア」コンテナを作成して手動でものを実行するほうがよいでしょうか。

219
Altreus

DockerがDockerfileからRUNコマンドを正常に実行するたびに、 画像ファイルシステムの新しい層 がコミットされます。便利には、これらのレイヤーIDを新しいコンテナーを開始するためのイメージとして使用できます。

次のDockerfileを取ります。

FROM busybox
RUN echo 'foo' > /tmp/foo.txt
RUN echo 'bar' >> /tmp/foo.txt

そしてそれを構築します。

$ docker build -t so-2622957 .
Sending build context to Docker daemon 47.62 kB
Step 1/3 : FROM busybox
 ---> 00f017a8c2a6
Step 2/3 : RUN echo 'foo' > /tmp/foo.txt
 ---> Running in 4dbd01ebf27f
 ---> 044e1532c690
Removing intermediate container 4dbd01ebf27f
Step 3/3 : RUN echo 'bar' >> /tmp/foo.txt
 ---> Running in 74d81cb9d2b1
 ---> 5bd8172529c1
Removing intermediate container 74d81cb9d2b1
Successfully built 5bd8172529c1

00f017a8c2a6044e1532c690および5bd8172529c1から新しいコンテナーを始めることができます。

$ docker run --rm 00f017a8c2a6 cat /tmp/foo.txt
cat: /tmp/foo.txt: No such file or directory

$ docker run --rm 044e1532c690 cat /tmp/foo.txt
foo

$ docker run --rm 5bd8172529c1 cat /tmp/foo.txt
foo
bar

もちろん、ファイルシステムを調べてコマンドを試すためにシェルを起動することができます。

$ docker run --rm -it 044e1532c690 sh      
/ # ls -l /tmp
total 4
-rw-r--r--    1 root     root             4 Mar  9 19:09 foo.txt
/ # cat /tmp/foo.txt 
foo

Dockerfileコマンドの1つが失敗したとき、あなたがする必要があるのは前の層のidを探しそしてから作成されたコンテナでシェルを実行することですそのID:

docker run --rm -it <id_last_working_layer> bash -il

コンテナに入ったら:

  • 失敗したコマンドを試して、問題を再現してください。
  • それからコマンドを修正してテストします
  • 最後に修正したコマンドでDockerfileを更新します

最後の作業層から作業するのではなく、実際に失敗した実際の層で実験する必要がある場合は、 Drew's answer を参照してください。

299
Thomasleveil

失敗したコマンドの直前の状態を調べたい場合は、トップの答えが役立ちます。

しかし、この質問では、失敗したコンテナー自体の状態を調べる方法を尋ねられます。私の状況では、失敗したコマンドは数時間かかるビルドなので、失敗したコマンドの前に巻き戻して再度実行するのは長い時間がかかり、あまり役に立ちません。

ここでの解決策は失敗したコンテナを見つけることです。

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                          PORTS               NAMES
6934ada98de6        42e0228751b3        "/bin/sh -c './utils/"   24 minutes ago      Exited (1) About a minute ago                       sleepy_bell

画像にコミットします。

$ docker commit 6934ada98de6
sha256:7015687976a478e0e94b60fa496d319cdf4ec847bcd612aecf869a72336e6b83

そしてイメージを実行します(必要ならば、bashを実行してください):

$ docker run -it 7015687976a4 [bash -il]

これで、実際には失敗の原因となったコマンドを実行する前ではなく、失敗したときのビルドの状態を調べています。

162
Drew

Docker RUN行が成功するたびに)(ファイルシステム全体の状態をキャッシュする

知っています:

  • 失敗したRUNコマンドの前の最新の状態を調べるには、Dockerfile(およびそれ以降のすべてのRUNコマンド)でコメントアウトしてから、もう一度docker buildおよびdocker runを実行します。
  • 状態を調べるにはafter失敗したRUNコマンドを、単に|| trueを追加して強制的に成功させます。その後、上記のように処理します(後続のすべてのRUNコマンドをコメントアウトし、docker buildおよびdocker runを実行します)。

多田さん、Dockerの内部やレイヤIDをいじる必要はありません。また、Dockerを使えば、やり直す必要のある作業量が自動的に最小限に抑えられます。

4
DomQ

ビルドステップの失敗をデバッグすることは確かに非常に面倒です。

私が見つけた最良の解決策は、実際の作業を行う各ステップが成功することを確認し、失敗したステップの後にチェックを追加することです。そのようにして、あなたはあなたが調べることができる失敗したステップのアウトプットを含むコミットされたレイヤーを得ます。

# Run DB2 silent installer行の後の例を含むDockerfile。

#
# DB2 10.5 Client Dockerfile (Part 1)
#
# Requires
#   - DB2 10.5 Client for 64bit Linux ibm_data_server_runtime_client_linuxx64_v10.5.tar.gz
#   - Response file for DB2 10.5 Client for 64bit Linux db2rtcl_nr.rsp 
#
#
# Using Ubuntu 14.04 base image as the starting point.
FROM ubuntu:14.04

MAINTAINER David Carew <[email protected]>

# DB2 prereqs (also installing sharutils package as we use the utility uuencode to generate password - all others are required for the DB2 Client) 
RUN dpkg --add-architecture i386 && apt-get update && apt-get install -y sharutils binutils libstdc++6:i386 libpam0g:i386 && ln -s /lib/i386-linux-gnu/libpam.so.0 /lib/libpam.so.0
RUN apt-get install -y libxml2


# Create user db2clnt
# Generate strong random password and allow Sudo to root w/o password
#
RUN  \
   adduser --quiet --disabled-password -Shell /bin/bash -home /home/db2clnt --gecos "DB2 Client" db2clnt && \
   echo db2clnt:`dd if=/dev/urandom bs=16 count=1 2>/dev/null | uuencode -| head -n 2 | grep -v begin | cut -b 2-10` | chgpasswd && \
   adduser db2clnt Sudo && \
   echo '%Sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

# Install DB2
RUN mkdir /install
# Copy DB2 tarball - ADD command will expand it automatically
ADD v10.5fp9_linuxx64_rtcl.tar.gz /install/
# Copy response file
COPY  db2rtcl_nr.rsp /install/
# Run  DB2 silent installer
RUN mkdir /logs
RUN (/install/rtcl/db2setup -t /logs/trace -l /logs/log -u /install/db2rtcl_nr.rsp && touch /install/done) || /bin/true
RUN test -f /install/done || (echo ERROR-------; echo install failed, see files in container /logs directory of the last container layer; echo run docker run '<last image id>' /bin/cat /logs/trace; echo ----------)
RUN test -f /install/done

# Clean up unwanted files
RUN rm -fr /install/rtcl

# Login as db2clnt user
CMD su - db2clnt
2
mikaraento

以下のDockerfileをコメントアウトして問題のある行を含めます。その後、コンテナーを実行してdockerコマンドを手動で実行し、通常の方法でログを調べます。例えば。 Dockerfileが

RUN foo
RUN bar
RUN baz

それは私がするだろうバーで死にかけている

RUN foo
# RUN bar
# RUN baz

それから

$ docker build -t foo .
$ docker run -it foo bash
container# bar
...grep logs...
1
seanmcl