一般的なDockerの問題をデバッグおよび修正する方法
序章
Dockerを使用すると、アプリケーションとサービスをコンテナーに簡単にラップできるため、どこでも実行できます。 残念ながら、イメージを構築し、アプリに必要なすべてのレイヤーを統合する場合、特にDockerイメージとコンテナーを初めて使用する場合は、問題が発生する可能性があります。 タイプミス、ランタイムライブラリとモジュールの問題、名前の衝突、または他のコンテナとの通信時に問題が発生する可能性があります。
Dockerを初めて使用するユーザーを対象としたこのトラブルシューティングガイドでは、Dockerイメージを構築する際の問題のトラブルシューティング、コンテナーの実行時の名前の衝突の解決、コンテナー間の通信時に発生する問題の修正を行います。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- サーバーまたはローカルマシンにインストールされたDocker。
サーバーにDockerをインストールするには、CentOS 7の場合は、Ubuntu16.04の場合はのハウツーガイドに従うことができます。
Docker Webサイトにアクセスするか、公式のインストールドキュメントに従って、ローカルマシンにDockerをインストールできます。
ステップ1—Dockerfileの問題を解決する
問題が発生する可能性のある最も一般的な場所は、Dockerfile
からDockerイメージを構築している場合です。 飛び込む前に、画像とコンテナの違いを明確にしましょう。
- image は、
Dockerfile
という構成ファイルを使用して作成する読み取り専用リソースです。 これは、 DockerHubまたはプライベートレジストリを介して出荷および共有するものです。 - コンテナは、作成したイメージから作成した読み取りおよび書き込みインスタンスです。
これらの概念の詳細については、チュートリアル Dockerの説明:Dockerfilesを使用したイメージの構築の自動化を参照してください。
Dockerfile
を見ると、Dockerfile
の各行がプロセスのステップに対応しているため、Dockerがイメージのビルドを使用するステップバイステップのプロセスを明確に確認できます。 これは通常、特定のステップに到達した場合、前のすべてのステップが正常に完了したことを意味します。
Dockerfile
で発生する可能性のあるいくつかの問題を調査するための小さなプロジェクトを作成しましょう。 ホームディレクトリにdocker_image
ディレクトリを作成し、nano
またはお気に入りのエディタを使用して、そのフォルダにDockerfile
を作成します。
mkdir ~/docker_image nano ~/docker_image/Dockerfile
この新しいファイルに次のコンテンツを追加します。
〜/ docker_image / Dockerfile
# base image FROM debian:latest # install basic apps RUN aapt-get install -qy nano
このコードには意図的なタイプミスがあります。 見つけられますか? このファイルからイメージを作成して、Dockerが不正なコマンドをどのように処理するかを確認してください。 次のコマンドを使用してイメージを作成します。
docker build -t my_image ~/docker_image
ターミナルに次のメッセージが表示され、エラーが示されます。
OutputStep 2 : RUN aapt-get install -qy nano ---> Running in 085fa10ffcc2 /bin/sh: 1: aapt-get: not found The command '/bin/sh -c aapt-get install -qy nano' returned a non-zero code: 127
最後のエラーメッセージは、ステップ2のコマンドに問題があったことを意味します。 この場合、それは私たちの意図的なタイプミスでした。apt-get
の代わりにaapt-get
があります。 しかし、それはまた、前のステップが正しく実行されたことを意味しました。
Dockerfile
を変更し、修正します。
Dockerfile
# install basic apps RUN apt-get install -qy nano
次に、docker build
コマンドを再度実行します。
docker build -t my_image ~/docker_image
そして今、あなたは次の出力を見るでしょう:
OutputSending build context to Docker daemon 2.048 kB Step 1 : FROM debian:latest ---> ddf73f48a05d Step 2 : RUN apt-get install -qy nano ---> Running in 9679323b942f Reading package lists... Building dependency tree... E: Unable to locate package nano The command '/bin/sh -c apt-get install -qy nano' returned a non-zero code: 100
タイプミスを修正すると、Dockerがベースイメージを再ダウンロードするのではなく、最初のステップをキャッシュしたため、プロセスが少し速く移動しました。 しかし、出力からわかるように、新しいエラーが発生します。
イメージの基盤として使用したDebianディストリビューションは、Debianパッケージリポジトリで利用可能であることがわかっているにもかかわらず、テキストエディタnano
を見つけることができませんでした。 ベースイメージには、リポジトリや利用可能なパッケージのリストなど、キャッシュされたメタデータが付属しています。 データを取得しているライブリポジトリが変更された場合、キャッシュの問題が発生することがあります。
これを修正するには、Dockerfileを変更して、新しいパッケージをインストールする前にソースのクリーンアップと更新を行います。 構成ファイルを再度開きます。
nano ~/docker_image/Dockerfile
次の強調表示された行をファイルに追加します。aboveコマンドでnano
をインストールします。
〜/ docker_image / Dockerfile
# base image FROM debian:latest # clean and update sources RUN apt-get clean && apt-get update # install basic apps RUN apt-get install -qy nano
ファイルを保存して、docker build
コマンドを再度実行します。
docker build -t my_image ~/docker_image
今回は、プロセスが正常に完了します。
OutputSending build context to Docker daemon 2.048 kB Step 1 : FROM debian:latest ---> a24c3183e910 Step 2 : RUN apt-get install -qy nano ---> Running in 2237d254f172 Reading package lists... Building dependency tree... Reading state information... Suggested packages: spell The following NEW packages will be installed: nano ... ---> 64ff1d3d71d6 Removing intermediate container 2237d254f172 Successfully built 64ff1d3d71d6
Python3とPostgreSQLドライバーをイメージに追加するとどうなるか見てみましょう。 Dockerfile
をもう一度開きます。
nano ~/docker_image/Dockerfile
そして、Python3とPythonPostgreSQLドライバーをインストールするための2つの新しいステップを追加します。
〜/ docker_image / Dockerfile
# base image FROM debian:latest # clean and update sources RUN apt-get clean && apt-get update # install basic apps RUN apt-get install -qy nano # install Python and modules RUN apt-get install -qy python3 RUN apt-get install -qy python3-psycopg2
ファイルを保存し、エディターを終了して、イメージを再度ビルドします。
docker build -t my_image ~/docker_image
出力からわかるように、パッケージは正しくインストールされます。 前のステップがキャッシュされたため、プロセスもはるかに迅速に完了します。
OutputSending build context to Docker daemon 2.048 kB Step 1 : FROM debian:latest ---> ddf73f48a05d Step 2 : RUN apt-get clean && apt-get update ---> Using cache ---> 2c5013476fbf Step 3 : RUN apt-get install -qy nano ---> Using cache ---> 4b77ac535cca Step 4 : RUN apt-get install -qy python3 ---> Running in 93f2d795fefc Reading package lists... Building dependency tree... Reading state information... The following extra packages will be installed: krb5-locales libgmp10 libgnutls-deb0-28 libgssapi-krb5-2 libhogweed2 libk5crypto3 libkeyutils1 libkrb5-3 libkrb5support0 libldap-2.4-2 libnettle4 libp11-kit0 libpq5 libsasl2-2 libsasl2-modules libsasl2-modules-db libtasn1-6 Suggested packages: gnutls-bin krb5-doc krb5-user libsasl2-modules-otp libsasl2-modules-ldap libsasl2-modules-sql libsasl2-modules-gssapi-mit libsasl2-modules-gssapi-heimdal python-psycopg2-doc The following NEW packages will be installed: krb5-locales libgmp10 libgnutls-deb0-28 libgssapi-krb5-2 libhogweed2 libk5crypto3 libkeyutils1 libkrb5-3 libkrb5support0 libldap-2.4-2 libnettle4 libp11-kit0 libpq5 libsasl2-2 libsasl2-modules libsasl2-modules-db libtasn1-6 python3-psycopg2 0 upgraded, 18 newly installed, 0 to remove and 0 not upgraded. Need to get 5416 kB of archives. After this operation, 10.4 MB of additional disk space will be used. ... Processing triggers for libc-bin (2.19-18+deb8u6) ... ---> 978e0fa7afa7 Removing intermediate container d7d4376c9f0d Successfully built 978e0fa7afa7
注:Dockerはビルドプロセスをキャッシュするため、ビルドで更新を実行し、Dockerがこの更新をキャッシュし、しばらくするとベースディストリビューションがソースを再度更新して、 Dockerfile
でクリーンアップと更新を行っているにもかかわらず、古いソース。 コンテナ内でのパッケージのインストールまたは更新で問題が発生した場合は、コンテナ内でapt-get clean && apt-get update
を実行してください。
Dockerの出力に細心の注意を払い、タイプミスがどこにあるかを特定し、ビルド時とコンテナー内で更新を実行して、キャッシュされたパッケージリストによって妨げられていないことを確認します。
構文エラーとキャッシュの問題は、Dockerでイメージを構築するときに発生する可能性のある最も一般的な問題です。 次に、これらのイメージからコンテナーを実行するときに発生する可能性のある問題を見てみましょう。
ステップ2—コンテナの名前付けの問題を解決する
より多くのコンテナを起動すると、最終的に名前の衝突に遭遇します。 名前の衝突とは、システムにすでに存在するコンテナと同じ名前のコンテナを作成しようとすることです。 衝突を回避するために、コンテナの命名、名前変更、および削除を適切に処理する方法を調べてみましょう。
前のセクションで作成したイメージからコンテナを起動してみましょう。 このコンテナ内でインタラクティブなbashインタープリターを実行して、テストを行います。 次のコマンドを実行します。
docker run -ti my_image bash
コンテナが起動すると、指示を待っているルートプロンプトが表示されます。
実行中のコンテナができたので、どのような問題が発生する可能性があるかを見てみましょう。
名前を明示的に設定せずに、今行った方法でコンテナーを実行すると、Dockerはコンテナーにランダムな名前を割り当てます。 実行中のコンテナーの外部にあるDockerホストでdocker ps
コマンドを実行すると、実行中のすべてのコンテナーとそれに対応する名前を確認できます。
Dockerホストで新しいターミナルを開き、次のコマンドを実行します。
docker ps
このコマンドは、次の例に示すように、実行中のコンテナーのリストとその名前を出力します。
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 80a0ca58d6ec my_image "bash" 22 seconds ago Up 28 seconds loving_brahmagupta
前の出力の名前loving_brahmagupta
は、前の例でDockerがコンテナーに自動的に割り当てた名前です。 あなたのものは別の名前になります。 Dockerにコンテナに名前を割り当てさせることは、非常に単純なケースでは問題ありませんが、重大な問題を引き起こす可能性があります。 デプロイするときは、コンテナーに一貫した名前を付ける必要があります。これにより、コンテナーを参照して簡単に自動化できます。
コンテナーの名前を指定するには、コンテナーを起動するときに--name
引数を使用するか、実行中のコンテナーの名前をよりわかりやすい名前に変更します。
Dockerホストのターミナルから次のコマンドを実行します。
docker rename your_container_name python_box
次に、コンテナを一覧表示します。
docker ps
出力にpython_box
コンテナが表示され、コンテナの名前が正常に変更されたことを確認できます。
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 80a0ca58d6ec my_image "bash" 24 minutes ago Up 24 minutes python_box
コンテナを閉じるには、実行中のコンテナを含むターミナルのプロンプトでexit
と入力します。
exit
それが不可能な場合は、次のコマンドを使用して、Dockerホスト上の別のターミナルからコンテナーを強制終了できます。
docker kill python_box
この方法でコンテナを強制終了すると、Dockerは強制終了されたばかりのコンテナの名前を返します。
Outputpython_box
python_box
がもう存在しないことを確認するには、実行中のすべてのコンテナーを再度リストします。
docker ps
予想どおり、コンテナはリストされなくなりました。
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
python_box
という名前の別のコンテナを起動できると思うかもしれませんが、試してみるとどうなるか見てみましょう。
今回は--name
引数を使用して、コンテナーの名前を設定します。
docker run --name python_box -ti my_image bash
Outputdocker: Error response from daemon: Conflict. The name "/python_box" is already in use by container 80a0ca58d6ecc80b305463aff2a68c4cbe36f7bda15e680651830fc5f9dda772. You have to remove (or rename) that container to be able to reuse that name.. See 'docker run --help'.
イメージを作成して既存のイメージの名前を再利用すると、すでに見たように、既存のイメージが上書きされます。 コンテナは、既存のコンテナを上書きできないため、もう少し複雑です。
Dockerによると、python_box
は、強制終了したばかりで、docker ps
にリストされていなくても、すでに存在しています。 実行されていませんが、再起動したい場合に備えて引き続き使用できます。 止めましたが、外しませんでした。 docker ps
コマンドは、実行中のコンテナーのみを表示し、すべてのコンテナーは表示しません。
実行中およびその他の方法でDockerコンテナーのallを一覧表示するには、-a
フラグ(--all
のエイリアス)をdocker ps
に渡します。
docker ps -a
これで、python_box
コンテナが出力に表示されます。
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 80a0ca58d6ec my_image "bash" 12 minutes ago Exited (137) 6 minutes ago python_box
コンテナはExited (137)
ステータスで存在します。そのため、同じ名前で新しいコンテナを作成しようとしたときに、名前の問題が発生しました。
コンテナを完全に削除したい場合は、docker rm
コマンドを使用します。 端末で次のコマンドを実行します。
docker rm python_box
もう一度、Dockerは削除されたばかりのコンテナの名前を出力します。
Outputpython_box
警告:コンテナがまだ実行中の場合、このコマンドは失敗し、エラーメッセージが出力されるため、最初に停止または強制終了してください。
前のコンテナを削除したので、python_box
という名前の新しいコンテナを作成しましょう。
docker run --name python_box -ti my_image bash
プロセスが完了し、ルートシェルが再び表示されます。
それでは、将来問題が発生しないように、コンテナを強制終了して削除しましょう。 Dockerホスト上の別のターミナルセッションから、コンテナーを強制終了し、次のコマンドで削除します。
docker kill python_box && docker rm python_box
2つのコマンドをチェーン化したため、出力にはコンテナー名が2回表示されます。 最初の出力はコンテナを強制終了したことを確認し、もう1つの出力はコンテナを削除したことを確認します。
Outputpython_box python_box
名前に問題が発生した場合はdocker ps -a
を念頭に置き、同じ名前で再作成する前に、コンテナーが停止して削除されていることを確認してください。
コンテナに名前を付けると、インフラストラクチャの管理が容易になります。 次に説明するように、名前を使用すると、コンテナー間の通信も簡単になります。
ステップ3—コンテナ通信の問題を解決する
Dockerを使用すると、複数のコンテナーを簡単にインスタンス化できるため、それぞれで異なるサービスや冗長なサービスを実行できます。 サービスに障害が発生したり、サービスが危険にさらされたりした場合は、インフラストラクチャの残りの部分をそのままにして、サービスを新しいサービスに置き換えることができます。 ただし、これらのコンテナを相互に通信させる際に問題が発生する可能性があります。
潜在的な通信の問題を調査できるように、通信する2つのコンテナーを作成しましょう。 既存のイメージを使用してPythonを実行する1つのコンテナーを作成し、PostgreSQLのインスタンスを実行する別のコンテナーを作成します。 そのコンテナには、 DockerHubから入手できる公式のPostgreSQLイメージを使用します。
まず、PostgreSQLコンテナを作成しましょう。 このコンテナには、--name
フラグを使用して名前を付け、他のコンテナとリンクするときに簡単に識別できるようにします。 これをpostgres_box
と呼びます。
以前、コンテナを起動したとき、それはフォアグラウンドで実行され、ターミナルを引き継ぎました。 PostgreSQLデータベースコンテナをバックグラウンドで起動したいのですが、これは--detach
フラグで実行できます。
最後に、bash
を実行する代わりに、postgres
コマンドを実行して、コンテナー内でPostgreSQLデータベースサーバーを起動します。
次のコマンドを実行して、コンテナを起動します。
docker run --name postgres_box --detach postgres
DockerはDockerHubからイメージをダウンロードし、コンテナーを作成します。 次に、バックグラウンドで実行されているコンテナの完全なIDを返します。
OutputUnable to find image 'postgres:latest' locally latest: Pulling from library/postgres 6a5a5368e0c2: Already exists 193f770cec44: Pull complete ... 484ac0d6f901: Pull complete Digest: sha256:924650288891ce2e603c4bbe8491e7fa28d43a3fc792e302222a938ff4e6a349 Status: Downloaded newer image for postgres:latest f6609b9e96cc874be0852e400381db76a19ebfa4bd94fe326477b70b8f0aff65
コンテナを一覧表示して、この新しいコンテナが実行されていることを確認します。
docker ps
出力は、postgres_box
コンテナがバックグラウンドで実行されていることを確認し、PostgreSQLデータベースポートであるポート5432
を公開します。
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7a230b56cd64 postgres_box "/docker-entrypoint.s" Less than a second ago Up 2 seconds 5432/tcp postgres
それでは、Pythonコンテナを起動しましょう。 Pythonコンテナー内で実行されているプログラムが、postgres_box
コンテナー内のサービスを「見る」には、 [を使用して、Pythonコンテナーをpostgres_box
コンテナーに手動でリンクする必要があります。 X201X]引数。 リンクを作成するには、コンテナの名前を指定し、その後にリンクの名前を指定します。 リンク名を使用して、Pythonコンテナ内からpostgres_box
コンテナを参照します。
次のコマンドを発行して、Pythonコンテナを起動します。
docker run --name python_box --link postgres_box:postgres -ti my_image bash
それでは、python_box
コンテナ内からPostgreSQLに接続してみましょう。
以前にnano
をpython_box
コンテナ内にインストールしたので、それを使用してPostgreSQLへの接続をテストするための簡単なPythonスクリプトを作成しましょう。 python_box
コンテナのターミナルで、次のコマンドを実行します。
nano pg_test.py
次に、次のPythonスクリプトをファイルに追加します。
pg_test.py
"""Test PostgreSQL connection.""" import psycopg2 conn = psycopg2.connect(user='postgres') print(conn)
ファイルを保存して、エディターを終了します。 スクリプトからデータベースに接続しようとするとどうなるか見てみましょう。 コンテナでスクリプトを実行します。
python3 pg_test.py
表示される出力は、データベースへの接続に問題があることを示しています。
OutputTraceback (most recent call last): File "pg_test.py", line 5, in <module> conn = psycopg2.connect(database="test", user="postgres", password="secret") File "/usr/lib/python3/dist-packages/psycopg2/__init__.py", line 164, in connect conn = _connect(dsn, connection_factory=connection_factory, async=async) psycopg2.OperationalError: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
postgres_box
コンテナーが実行されていることを確認し、それをpython_box
コンテナーにリンクしたので、どうなりましたか? 接続しようとしたときにデータベースホストを指定したことがないため、Pythonはローカルで実行されているデータベースに接続しようとしますが、サービスがローカルで実行されていないため、別のコンテナーで実行されているかのように機能しません。別のコンピューターにありました。
リンクを作成したときに設定した名前を使用して、リンクされたコンテナにアクセスできます。 この例では、postgres
を使用して、データベースサーバーを実行しているpostgres_box
コンテナーを参照します。 これは、python_box
コンテナ内の/etc/hosts
ファイルを表示することで確認できます。
cat /etc/hosts
使用可能なすべてのホストとその名前およびIPアドレスが表示されます。 postgres
サーバーがはっきりと見えます。
Output127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.2 postgres f6609b9e96cc postgres_box 172.17.0.3 3053f74c8c13
それでは、Pythonスクリプトを変更して、ホスト名を追加しましょう。 ファイルを開きます。
nano pg_test.py
次に、接続文字列でホストを指定します。
/pg_test.py
"""Test PostgreSQL connection.""" import psycopg2 conn = psycopg2.connect(host='postgres', user='postgres') print(conn)
ファイルを保存してから、スクリプトを再実行してください。
python3 pg_test.py
今回は、スクリプトはエラーなしで完了します。
Output<connection object at 0x7f64caec69d8; dsn: 'user=postgres host=7a230b56cd64', closed: 0>
他のコンテナのサービスに接続するときは、コンテナ名を覚えておいてください。アプリケーションのクレデンシャルを編集して、それらのコンテナのリンクされた名前を参照してください。
結論
イメージの構築からコンテナーのネットワークのデプロイまで、Dockerコンテナーを操作するときに発生する可能性のある最も一般的な問題について説明しました。
Dockerには、主にDocker開発者を対象とした--debug
フラグがあります。 ただし、Dockerの内部について詳しく知りたい場合は、Dockerコマンドをデバッグモードで実行して、より詳細な出力を試してください。
docker -D [command] [arguments]
ソフトウェアのコンテナはしばらく前から存在していましたが、Docker自体は3年しか存在しておらず、非常に複雑になる可能性があります。 時間をかけて用語とエコシステムに慣れてください。最初は少し異質だったいくつかの概念が、すぐに意味をなすようになることがわかります。