目次


Kubernetes アプリケーションのデバッグとロギング

Kubernetes クラスターについて理解する

Comments

Kubernetes は、アプリケーションをデプロイ、保守、スケーリングするための一連の基本的なメカニズムを提供し、複数のホストにわたるアプリケーションの一元管理を可能にするオープンソース・システムです。Cloud Native Computing Foundation でホストされているこのオープンソース・プロジェクトを、このチュートリアルでは IBM Cloud Kubernetes Service 上でホストします。

学習の目的

このチュートリアルで対象としているのは、Kubernetes クラスター について理解を深め、Kubernetes アプリケーションをデバッグしてログを取得するスキルを身に付けることを目指している開発者です。

前提条件

このチュートリアルに取り組む前に、次のものを揃えておく必要があります。

所要時間

このチュートリアルの所要時間は約 20 分です。

手順

コンテナーのログ

ポッドを調べてデバッグする

アプリケーションのデプロイメントについて言えば、時には何事もなく順調に進んで、アプリのデプロイメントが作成されたことを通知する「deployment <your-app-name> created」というメッセージが表示されますが、 アプリケーションのデプロイがどうしてもうまく行かない場合はどうすればよいでしょうか?その場合は、情報を収集し、修正方法を計画し、テストを実施するというステップを段階的に踏む必要があります。 情報収集のステップについては、情報を収集するために使用できるツールや手法はさまざまにあります。

  1. ポッドの基本情報を取得するには、次の単純なコマンドを使用できます。
$ kubectl get pods
NAME                         READY     STATUS    RESTARTS   AGE
guestbook-75786d799f-fg72k   1/1       Running   0          7m
  1. 特定のポッドを指定して、上記より遥かに詳細な情報を取得することもできます。
$ kubectl describe pod <your-pod-name>
Name:           guestbook-75786d799f-fg72k
Namespace:      default
Node:           10.47.84.98/10.47.84.98
Start Time:     Sun, 19 Aug 2018 12:56:23 +0300
Labels:         pod-template-hash=3134283559
  run=guestbook
Annotations:    kubernetes.io/psp=ibm-privileged-psp
Status:         Running
...

この出力から、コンテナーとポッドの構成に関する情報 (ラベル、リソース要件など)、コンテナーとポッドのステータス情報 (状態、準備状況、再起動回数、イベントなど) を確認できます。

こうした基本的なコマンドを使用するだけで十分なこともあります。例えば、kubectl describe の出力を調べれば、イメージをプルする際にエラーが発生したこと、その原因が単に情報の欠落であったこと (イメージのプルの場合はシークレットを入力し忘れたなど) がわかる場合があります。あるいは、イメージの最新バージョンが問題の原因だとすれば、前のバージョンに戻すことで問題を解決できます。

けれども出力でエラーが見つからなければ、ログを詳しく調査する必要があります。開発者の間で一般的な知識となっていませんが、イベントは、実際には Kubernetes 内の 1 つのリソース・タイプです。 コマンド kubectl get events を実行すると、他のあらゆるリソースと同様に一連のイベントの概要が表示されます。 注意すべき点として、イベント・リソースは名前空間でグループ化されています。そのため、特定のイベントを取得するとしたら、イベントを取得する対象の名前空間を指定する必要があります。名前空間を空白のままにすると、すべてのイベントが返されることになります。

  1. ポッドで発生したイベントのリストを取得するには、次のコマンドを使用します。
$kubectl get events [--namespace=default]
LASTSEEN   FIRSTSEEN   COUNT     NAME                         KIND         SUBOBJECT                    TYPE      REASON                  SOURCE                  MESSAGE
3m         3m          1         guestbook-75786d799f-r6mxl   Pod                                       Normal    Scheduled               default-scheduler       Successfully assigned guestbook-75786d799f-r6mxl to 10.77.155.84
3m         3m          1         guestbook-75786d799f-r6mxl   Pod                                       Normal    SuccessfulMountVolume   kubelet, 10.77.155.84   MountVolume.SetUp succeeded for volume "default-token-5rlxc"
3m         3m          1         guestbook-75786d799f-r6mxl   Pod          spec.containers{guestbook}   Normal    Pulled                  kubelet, 10.77.155.84   Container image "ibmcom/guestbook:v1" already present on machine
3m         3m          1         guestbook-75786d799f-r6mxl   Pod          spec.containers{guestbook}   Normal    Created                 kubelet, 10.77.155.84   Created container
3m         3m          1         guestbook-75786d799f-r6mxl   Pod          spec.containers{guestbook}   Normal    Started                 kubelet, 10.77.155.84   Started container
3m         3m          1         guestbook-75786d799f-xvpvv   Pod          spec.containers{guestbook}   Normal    Killing                 kubelet, 10.77.155.84   Killing container with id docker://guestbook:Need to kill Pod
3m         3m          1         guestbook-75786d799f         ReplicaSet                                Normal    SuccessfulDelete        replicaset-controller   Deleted pod: guestbook-75786d799f-xvpvv
3m         3m          1         guestbook-75786d799f         ReplicaSet                                Normal    SuccessfulCreate        replicaset-controller   Created pod: guestbook-75786d799f-r6mxl
3m         3m          1         guestbook                    Deployment                                Normal    ScalingReplicaSet       deployment-controller   Scaled down replica set guestbook-75786d799f to 0
3m         3m          1         guestbook                    Deployment                                Normal    ScalingReplicaSet       deployment-controller   Scaled up replica set guestbook-75786d799f to 1

一般的なシナリオの 1 つとして、ポッドを作成して、そのポッドがどのノードでも起動されない場合、イベントを調べることでその問題を検出できます。このようなポッドは「Pending (保留中)」状態になります。リソース不足などによって発生するこの状態は、「Events (イベント)」セクションに示されます。 重要な events パラメーターを見ていきましょう。上記の出力から、イベント・レコードには次のパラメーターが含まれることがわかります。

  • KIND は、イベントの報告対象となっているリソースのタイプ (Pod、ReplicaSet、Deployment など) を示します。
  • TYPEは、イベントのステータスです。現在のところ、ステータスは「Normal (正常)」または「Warning (警告)」のいずれかとして示されますが、将来的に新しいタイプのステータスが追加される可能性もあります。
  • REASON は、状態遷移後のオブジェクトの現在のステータスを示します。
  • SOURCE は、そのイベントを報告したコンポーネントです。
  • MESSAGE は、人間が読んで理解しやすい形式で記述された、イベントの説明です。

上記の出力には示されていませんが、他にも有用なパラメーターがあります。例えば、METADATA は標準的なオブジェクト・メタデータを示します。EVENTTIME はイベントが最初に観測された時刻を示します。ACTION は、オブジェクトに関して実行された、または失敗した特定のアクションを示します。

イベントの詳細については、このリンク先のイベントに関するドキュメントを参照してください。

アプリケーションのログを取得する

クラスター内で何が起こったのかを詳しく理解するには、アプリケーション・ログとシステム・ログが役立ちます。ログを取得するときに特定のポッドを指定すれば、そのポッドに関するログを取得できます。ポッドに複数のコンテナーが含まれている場合は、どのコンテナーのログを取得するかを指定することもできます。

ログを表示する

次の単純なコマンドを実行することで、ログを表示できます。

$ kubectl logs <your-pod-name>
[negroni] listening on :3000
[negroni] 2018-08-19T11:55:39Z | 200 |   332.277Aμs | 173.193.106.55:32412 | GET /
[negroni] 2018-08-19T11:55:39Z | 200 |   140.407Aμs | 173.193.106.55:32412 | GET /style.css
[negroni] 2018-08-19T11:55:39Z | 200 |   123.595Aμs | 173.193.106.55:32412 | GET /script.js
[negroni] 2018-08-19T11:55:39Z | 200 |   87.508Aμs | 173.193.106.55:32412 | GET /lrange/guestbook
[negroni] 2018-08-19T11:55:39Z | 404 |   74.307Aμs | 173.193.106.55:32412 | GET /favicon.ico
[negroni] 2018-08-19T11:57:30Z | 304 |   89.418Aμs | 173.193.106.55:32412 | GET /
[negroni] 2018-08-19T11:57:30Z | 200 |   60.671Aμs | 173.193.106.55:32412 | GET /lrange/guestbook
[negroni] 2018-08-19T12:06:23Z | 304 |   152.557Aμs | 173.193.106.55:32412 | GET /
[negroni] 2018-08-19T12:06:23Z | 200 |   94.091Aμs | 173.193.106.55:32412 | GET /lrange/guestbook

注: ログを出力するには、アプリケーションから stdout/stderr にログを書き出します。logs コマンドには get が含まれていないことにも注意してください。これは、ログはイベントとは異なり、リソースではないことを意味します。

ログをより有効に利用するには、"kubetail」 を使用できます。これは、ログをタイプ別に色分けして出力するオープンソース・プロジェクトです。このオープンソース・プロジェクトを入手するには、https://github.com/johanhaleby/kubetail にアクセスしてください。

以前のログ

--previous フラグを指定することで随時、以前のログを取得できます。ただし、知る必要のあるログ・レベルのタイプには、さらにノード・レベルとクラスター・レベルの 2 つがあることに注意してください。この 2 つにはかなりの違いがあります。その違いについて見ていきましょう。

  • ノード・レベル: コンテナー化されたアプリケーションは、コンテナー・エンジンによって処理されている stdoutstderr に出力を書き込みます。コンテナー・エンジンはこの 2 つの標準入出力ストリームを Kubernetes 内に構成されているロギング・ドライバーにリダイレクトし、JSON 形式のファイルに書き込みます。 JSON ロギング・ドライバーは各行を個別のメッセージとして扱います。ロギング・ドライバーを使用する場合、複数行からなるメッセージは直接サポートされません。したがって、複数行のメッセージはロギング・エージェントまたはそれより高位のレベルで処理する必要があります。 デフォルトでは、コンテナーが再起動すると、kubelet は終了したコンテナーごとにそのログを保持します。ポッドがノードから排除された場合、対応するすべてのコンテナーとそれぞれのログもノードから排除されます。
  • クラスター・レベル: Kubernetes にはクラスター・レベルのロギングに対するネイティブ・ソリューションはありませんが、代替策として考慮できる一般的な方法がいくつかあります。具体的には、次の選択肢があります。
    • すべてのノード上で実行されるノード・レベルのロギング・エージェントを使用する。
    • アプリケーション・ポッド内にロギング専用のサイドカー・コンテナーを組み込む。
    • アプリケーション内から直接バックエンドにログをプッシュする。

以上の手法について詳しくは、このリンク先のガイドを参照してくだし。

実行中のコンテナー内でシェルを使用する

ほとんどの場合、コンテナーのログはポッドのログを意味します。このことは、特にポッドに 1 つのコンテナーしか含まれていない場合に当てはまります。けれどもクラスター上で重大な問題が発生し、kubectl を使用してそのログをポッドから取得できないとしたら、どうにかしてコンテナー内部にアクセスして、コンテナー内の処理を完全に制御するためのログ (デバッグ対象のコンテナーのログ) を取得しなければなりません 。 この場合、kubectl exec を使用することで、コンテナー内で実行されるシェルにアクセスできます。このシェルを使用すれば、問題のあるコンテナー内のどのプロセスが問題になっているかを突き止められるので、比較的手間のかからない方法でコンテナーをデバッグすることができます。

ただし、この方法を適用できるのは、コンテナー内に Shell exec が存在する場合のみです。コンテナーの作成時に Shell exec が組み込まれていないイメージを使用した場合、この exec コマンドを使用することはできません。 Shell exec はある程度のスペースを占めるので、コンテナーが大きくなります。このことから、「コンテナーに組み込む必要があるだろうか?コンテナーを使用する最大の利点はその軽量さにあるのではないか?」という疑問を持つかもしれません。 通常、本番環境ではパフォーマンスを最適化したいものです。したがって、シェルをイメージに組み込む根拠は何もありません。けれどもテスト環境では、シェルにアクセスして実行中のコンテナーをテストできると非常に便利です。

  1. 実行中のコンテナー内でシェルを使用できるようにするには、/bin/bash を使用して新しいポッドを作成します。
$ kubectl create -f https://kubernetes.io/examples/application/shell-demo.yaml
  1. シェルをコンテナーに接続します。
$ kubectl exec -it shell-demo -- /bin/bash
  1. ルート・ディレクトリーをリストアップします。
root@shell-demo:/# ls /
bin   dev  home  lib64  mnt  proc  run   srv  tmp
boot  etc  lib   media  opt  root  sbin  sys  usr

クラスターのネットワーキングの問題

ネットワーキングの問題は最も一般的な問題です。この場合、具体的にどこを調べれば問題を解決できる可能性があるかを示すリストは手に入らないため、クラスター内部の何が問題になっているのかを手探りで模索しなければなりません。 こうした問題の解決に役立つよう、ネットワーク問題が疑われる場合に調査すべき重要なエリアをピックアップしました。 参考資料: Kubernetes でのネットワーキングに関するガインスについては、Kubernetes でのネットワーキング: ネットワーキングの基本概念について学習するラボ を参照してください。

サービスをデバッグする

新しくインストールした Kubernetes でよく発生する問題として、サービスが正常に機能せず、デプロイを実行してサービスを作成しても、何の応答も返ってこないことがあります。このセクションでは、何が機能していないのかを突き止める際に役立ついくつかのコマンドについて説明します。

問題の原因として考えられるのは、ポッド用のサービスを作成するのを忘れていることです。サービスは必要不可欠であるため、サービスが作成されていなければ、ポッドに到達することはできません。その結果、エラーを受け取ります。

  1. すべてのサービスを確認するには、次のような単純なコマンドを使用できます。このコマンドにより、すべてのポッドが一覧表示されます。
$ kubectl get svc
NAME        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
guestbook   172.21.30.218   <nodes>       3000:32412/TCP   45m
  1. 目的のサービスが存在していなければ、次のコマンドを使用してサービスを作成します。
$ kubectl expose deployment <your-deployment-name> --type="NodePort" --port=3000
service "guestbook" exposed

すでにサービスがある場合は、サービスの構成を調べて問題があるかどうかを確認する必要があります。

  1. 作成したサービスに関する情報を取得しましょう。
$ kubectl describe service <your-service-name>
Name:                   guestbook
Namespace:              default
Labels:                 run=guestbook
Annotations:            <none>
Selector:               run=guestbook
Type:                   NodePort
IP:                     172.21.138.209
Port:                   <unset> 3000/TCP
NodePort:               <unset> 31235/TCP
Endpoints:              172.30.87.71:3000
Session Affinity:       None
Events:                 <none>

コンテナーへのアクセスに使用された NodePort が正しいものであるか、そしてエンドポイントが示されていることを確認します。 誤った情報が見つかった場合 (エンドポイントが示されていないなど)、サービスをもう一度作成して、kubectl expose コマンドに何らかの誤りがないかどうかダブルチェックしてください。

  1. 情報を JSON 形式で取得することもできます。
$ kubectl get service <your-service-name> -o json
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"creationTimestamp": "2018-08-19T11:55:12Z",
"labels": {
"run": "guestbook"
},
"name": "guestbook",
"namespace": "default",
"resourceVersion": "1118",
"selfLink": "/api/v1/namespaces/default/services/guestbook",
"uid": "baa2e98d-a3a6-11e8-a994-f20601bb534c"
},
"spec": {
"clusterIP": "172.21.30.218",
"externalTrafficPolicy": "Cluster",
"ports": [
{
"nodePort": 32412,
"port": 3000,
"protocol": "TCP",
"targetPort": 3000
}
],
"selector": {
"run": "guestbook"
},
"sessionAffinity": "None",
"type": "NodePort"
},
"status": {
"loadBalancer": {}
}
}

問題の原因となる可能性がある構成については、常にダブルチェックしてください。例えば、spec.ports がポッドに適切な targetPort になっているか、サービスとポッドが同じプロトコルを使用しているかといった点を確認します。

  1. サービスを検査するには、他にも方法があります。詳細については、ここをクリックしてください。

DNS を確認する

ネットワーク問題の原因が DNS の構成またはエラーであることもあります。 したがって、まずは DNS が正常に機能しているかどうかを調べる必要があります。

  1. get pods コマンドを使用してポッド名を調べます。
$ kubectl get pods
NAME                         READY     STATUS    RESTARTS   AGE
guestbook-75786d799f-brrhf   1/1       Running   0          47m
  1. 次のコマンドを使用して、ポッドの DNS を確認します。
$ kubectl exec -ti <your-pod-name> -- nslookup kubernetes.default
Server:    172.21.0.10
Address 1: 172.21.0.10 kube-dns.kube-system.svc.cluster.local

Name:      kubernetes.default
Address 1: 172.21.0.1 kubernetes.default.svc.cluster.local

"default" 名前空間を使用しない場合は、クラスターの名前空間に応じて他の名前を試してください。ポッドとサービスが異なる名前空間に存在するとしたら、名前空間で修飾した名前を試すこともできます (デフォルト)。ただしその場合は、2 つの名前空間をまたがる名前を使用するようにアプリを調整するか、アプリとサービスを同じ名前空間で実行する必要があります。それでもエラーが発生する場合は、完全修飾名 (例: default.svc.cluster.local) を試してください。 nslookup コマンドが失敗する場合、構成内のチェックを行うか、エラーを見つける必要があります。 名前空間を解決できないことを通知する nslookup: can't resolve 'kubernetes.default' などのエラーは、coredns/kube-dns add-on アドオンまたはこれに関連するサービスに問題がある可能性を示唆します。

完全修飾名ではルックアップに成功する一方、相対名を使用すると失敗するとしたら、/etc/resolv.conf ファイルが正しいものであることを確認する必要があります。

  1. resolv.conf ファイルの内容を表示して、パラメーターに誤りがないかどうかを調べます。
$ kubectl exec <your-pod-name> cat /etc/resolv.conf
nameserver 172.21.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

nameserver の行に正しい DNS サービスが示されていることを確認します。これは --cluster-dns フラグを使用して kubelet に渡されるパラメーターです。search の行には、サービス名を見つけるのに適切なサフィックスが示されていなければなりません。上記の例は、ローカル名前空間 (default.svc.cluster.local) 内のすべての名前空間のサービス (svc.cluster.local) 内でクラスター (cluster.local) を検索します。インストールによっては、さらに他のレコードがある場合もあります。クラスターのサフィックスは --cluster-domain フラグで kubelet に渡されます。options の行で ndots に設定されるドット数は、DNS クライアント・ライブラリーが検索パスとみなせるだけの大きい値でなければなりません。Kubernetes はこれをデフォルトで 5 に設定します。これだけの数のドットが名前に含まれていれば、Kubernetes が生成するすべての DNS 名をカバーできます。

上記のすべての方法を試しても問題を解決できない場合は、kube-proxy を調べる必要があります。

ネットワーク・ポリシー

NetworkPolicy は、ポッド間およびポッドと他のネットワーク・エンドポイントとの間で許可する通信を定義するものです。NetworkPolicy はラベルを使用して、ポッド間のトラフィックを管理します。 ポッドと通信できない場合は、ネットワーク・ポリシーを調べて、そのポッドにリクエストの受信が許可されているかどうかを確認してください。 デフォルトではポッドは隔離されないため、トラフィックを受け入れます。けれども NetworkPolicy で特定のポッドを選択すると、不正な接続を使用した通信はすべて拒否されます。

NetworkPolicy の例を見てください。

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: access-nginx
spec:
  podSelector:
matchLabels:
  run: nginx
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
- podSelector:
matchLabels:
  access: "true"
  egress:
  - to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
  port: 5978

他のあらゆる Kubernetes 構成と同じく、NetworkPolicy には一般情報として kind、apiVersion、metadata の各パラメーターがあります。 上記の例では、spec 内の podSelector で、この NetworkPolicy に含めるポッドを選択しています。この例ではすべての nginx ポッドが含まれることになります。 注: podSelector を空にすると、この NetworkPolicy が同じ名前空間内のすべてのポッドに適用されます。

確認する必要がある重要なパラメーターには、ingress と egres もあります。これらのパラメーターによって、podSelector で指定されているポッドの通信で許可される着信側と受信側のネットワークが決まります。ポッドの通信が許可されてブロックされないようにするには、この 2 つのパラメーターをダブルチェックして、正しいラベル、IP、ポートが挿入されていることを確認してください。

Weave Scope を使用する

Weave Scope は Docker と Kubernetes を対象としたオープンソースの視覚化およびモニタリング・ツールです。このツールではインフラストラクチャー全体だけでなく、上からの視点でアプリを把握できるため、クラウド・プロバイダーにデプロイされているコンテナー化された分散型アプリの問題をリアルタイムで診断することができます。 Weave Cope を Kubernetes クラスター上にインストールするには、このリンク先のぺージで説明している手順に従ってください。 Weave Scope でないとしても、コンテナーの動作を視覚化して、その根拠を簡単に理解できるよう、同様のモニタリング・ツールを使用することを強くお勧めします。

Grafana を使用する

Grafana は、Web アプリケーションとして稼動する、オープンソースの汎用ダッシュボード兼グラフ・コンポーザーです。 Grafana を使用すると、クラスターとポッドの CPU/メモリー/負荷に関するメトリックを取得できます。 IBM Cloud® のすべてのユーザーは、アカウントを使用して Grafana にアクセスできるようになっています。Grafana を使い始めるには、このリンク先のチュートリアルを参照してください。 Grafana を操作して Kubernetes クラスター用のダッシュボードを作成する方法については、このリンク先の IBM Cloud 資料で詳細を確認できます。

まとめ

このチュートリアルで Kubernetes アプリケーションのロギングとデバッグについて基礎知識を学んだ後は、次のドキュメントを参考に他のツールも試してみてください。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Cloud computing
ArticleID=1066298
ArticleTitle=Kubernetes アプリケーションのデバッグとロギング
publish-date=07182019