一般的なDockerの問題をデバッグおよび修正する方法
序章
Dockerを使用すると、アプリケーションとサービスをコンテナーに簡単にラップできるため、どこでも実行できます。 残念ながら、イメージを構築し、アプリに必要なすべてのレイヤーを統合する場合、特にDockerイメージとコンテナーを初めて使用する場合は、問題が発生する可能性があります。 タイプミス、ランタイムライブラリとモジュールの問題、名前の衝突、または他のコンテナとの通信時に問題が発生する可能性があります。
Dockerを初めて使用するユーザーを対象としたこのトラブルシューティングガイドでは、Dockerイメージを構築する際の問題のトラブルシューティング、コンテナーの実行時の名前の衝突の解決、コンテナー間の通信時に発生する問題の修正を行います。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- サーバーまたはローカルマシンにインストールされたDocker。
サーバーにDockerをインストールするには、CentOS 7の場合は、Ubuntu16.04の場合はのハウツーガイドに従うことができます。
Docker Webサイトにアクセスするか、公式のインストールドキュメントに従って、ローカルマシンにDockerをインストールできます。
ステップ1—Dockerfileの問題を解決する
問題が発生する可能性のある最も一般的な場所は、Dockerイメージを Dockerfile
. 飛び込む前に、画像とコンテナの違いを明確にしましょう。
- image は、と呼ばれる構成ファイルを使用して作成する読み取り専用リソースです。
Dockerfile
. これは、 DockerHubまたはプライベートレジストリを介して出荷および共有するものです。 - コンテナは、作成したイメージから作成した読み取りおよび書き込みインスタンスです。
これらの概念の詳細については、チュートリアル Dockerの説明:Dockerfilesを使用したイメージの構築の自動化を参照してください。
あなたが見るとき Dockerfile
、Dockerがイメージを構築するために使用するステップバイステップのプロセスを明確に確認できます。これは、 Dockerfile
プロセスのステップに対応します。 これは通常、特定のステップに到達した場合、前のすべてのステップが正常に完了したことを意味します。
発生する可能性のあるいくつかの問題を調査するための小さなプロジェクトを作成しましょう。 Dockerfile
. 作成する docker_image
ホームディレクトリのディレクトリを使用し、 nano
またはお気に入りのエディタを作成して Dockerfile
そのフォルダに
- mkdir ~/docker_image
- nano ~/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のコマンドに問題があったことを意味します。 この場合、それは私たちの意図的なタイプミスでした。 aapt-get
それ以外の apt-get
. しかし、それはまた、前のステップが正しく実行されたことを意味しました。
を変更します 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ディストリビューションは、テキストエディタを見つけることができませんでした nano
、Debianパッケージリポジトリで利用できることはわかっていますが。 ベースイメージには、リポジトリや利用可能なパッケージのリストなど、キャッシュされたメタデータが付属しています。 データを取得しているライブリポジトリが変更された場合、キャッシュの問題が発生することがあります。
これを修正するには、Dockerfileを変更して、新しいパッケージをインストールする前にソースのクリーンアップと更新を行います。 構成ファイルを再度開きます。
- nano ~/docker_image/Dockerfile
次の強調表示された行をファイルに追加します。aboveインストールするコマンド nano
:
# 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つの新しいステップを追加します。
# 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 ps
実行中のコンテナーの外部にあるDockerホストでのコマンド。
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
. 実行されていませんが、再起動したい場合に備えて引き続き使用できます。 止めましたが、外しませんでした。 The 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
コンテナはバックグラウンドで実行されており、ポートを公開しています 5432
、PostgreSQLデータベースポート:
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
を使用してコンテナ --link
口論。 リンクを作成するには、コンテナの名前を指定し、その後にリンクの名前を指定します。 リンク名を使用して、 postgres_box
Pythonコンテナ内からのコンテナ。
次のコマンドを発行して、Pythonコンテナを起動します。
- docker run --name python_box --link postgres_box:postgres -ti my_image bash
それでは、内部からPostgreSQLに接続してみましょう。 python_box
容器。
以前にインストールしました nano
の内側 python_box
コンテナなので、これを使用して、PostgreSQLへの接続をテストするための簡単なPythonスクリプトを作成しましょう。 のターミナルで python_box
コンテナ、次のコマンドを実行します。
- nano pg_test.py
次に、次のPythonスクリプトをファイルに追加します。
"""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
データベースサーバーを実行しているコンテナ。 これを確認するには、 /etc/hosts
内のファイル python_box
容器:
- 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
次に、接続文字列でホストを指定します。
"""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には --debug
主にDocker開発者を対象としたフラグ。 ただし、Dockerの内部について詳しく知りたい場合は、Dockerコマンドをデバッグモードで実行して、より詳細な出力を試してください。
- docker -D [command] [arguments]
ソフトウェアのコンテナはしばらく前から存在していましたが、Docker自体は3年しか存在しておらず、非常に複雑になる可能性があります。 時間をかけて用語とエコシステムに慣れてください。最初は少し異質だったいくつかの概念が、すぐに意味をなすようになることがわかります。