Makoto Watanabe
2020-06-13 14:04:30 +09:00
parent 3d6b7b17f6
commit 74c02b2ecb
@@ -4,8 +4,8 @@ title: Serviceのデバッグ
---
{{% capture overview %}}
新規にKubernetesをインストールした環境でかなり頻繁に発生する問題は、`Service`が適切に機能しないというものです。
`Deployment`を実行して`Service`を作成したにもかかわらず、アクセスしようとしても応答がありません。
新規にKubernetesをインストールした環境でかなり頻繁に発生する問題は、Serviceが適切に機能しないというものです。
Deployment(または他のワークロードコントローラー)を通じてPodを実行し、サービスを作成したにもかかわらず、アクセスしようとしても応答がありません。
何が問題になっているのかを理解するのに、このドキュメントがきっと役立つでしょう。
@@ -14,47 +14,20 @@ title: Serviceのデバッグ
{{% capture body %}}
## 規則
このドキュメントでは全体を通して、実行可能なさまざまなコマンドが示されます。
中には`Pod`内で実行する必要があるコマンドもあれば、Kubernetesの`ノード`上で実行する必要があるコマンドや、`kubectl`とクラスターの認証情報がある場所であればどこでも実行できるコマンドもあります。
期待される内容を明確にするために、このドキュメントでは次の規則を使用します。
コマンド"COMMAND"が`Pod`内で実行され、"OUTPUT"を出力すると期待される場合:
```shell
u@pod$ COMMAND
OUTPUT
```
コマンド"COMMAND"が`Node`上で実行され、"OUTPUT"を出力すると期待される場合:
```shell
u@node$ COMMAND
OUTPUT
```
コマンドが"kubectl ARGS"の場合:
```shell
kubectl ARGS
OUTPUT
```
## Pod内でコマンドを実行する
ここでの多くのステップでは、クラスターで実行されている`Pod`が見ているものを確認する必要があります。
これを行う最も簡単な方法は、インタラクティブなalpineの`Pod`を実行することです。
ここでの多くのステップでは、クラスターで実行されているPodが見ているものを確認する必要があります。
これを行う最も簡単な方法は、インタラクティブなalpineのPodを実行することです。
```none
kubectl run -it --rm --restart=Never alpine --image=alpine sh
/ #
```
{{< note >}}
コマンドプロンプトが表示されない場合は、Enterキーを押してみてください。
{{< /note >}}
使用したい実行中の`Pod`が既にある場合は、以下のようにしてその`Pod`内でコマンドを実行できます。
使用したい実行中のPodが既にある場合は、以下のようにしてそのPod内でコマンドを実行できます。
```shell
kubectl exec <POD-NAME> -c <CONTAINER-NAME> -- <COMMAND>
@@ -62,20 +35,21 @@ kubectl exec <POD-NAME> -c <CONTAINER-NAME> -- <COMMAND>
## セットアップ
このドキュメントのウォークスルーのために、いくつかの`Pod`を実行しましょう。
おそらくあなた自身の`Service`をデバッグしているため、あなた自身の詳細に置き換えることもできますし、これに沿って2番目のデータポイントを取得することもできます。
このドキュメントのウォークスルーのために、いくつかのPodを実行しましょう。
おそらくあなた自身のServiceをデバッグしているため、あなた自身の詳細に置き換えることもできますし、これに沿って2番目のデータポイントを取得することもできます。
```shell
kubectl run hostnames --image=k8s.gcr.io/serve_hostname \
--labels=app=hostnames \
--port=9376 \
--replicas=3
--replicas=3
```
```none
deployment.apps/hostnames created
```
`kubectl`コマンドは作成、変更されたリソースのタイプと名前を出力するため、この後のコマンドで使用することもできます。
{{< note >}}
これは、次のYAMLで`Deployment`を開始した場合と同じです。
これは、次のYAMLでDeploymentを開始した場合と同じです。
```yaml
apiVersion: apps/v1
@@ -85,58 +59,100 @@ metadata:
spec:
selector:
matchLabels:
app: hostnames
run: hostnames
replicas: 3
template:
metadata:
labels:
app: hostnames
run: hostnames
spec:
containers:
- name: hostnames
image: k8s.gcr.io/serve_hostname
ports:
- containerPort: 9376
protocol: TCP
```
"run"ラベルは`kubectl run`によって、Deploymentの名前に自動的にセットされます。
{{< /note >}}
`Pod`が実行中であることを確認してください
Podが実行されていることを確認できます
```shell
kubectl get pods -l app=hostnames
kubectl get pods -l run=hostnames
```
```none
NAME READY STATUS RESTARTS AGE
hostnames-632524106-bbpiw 1/1 Running 0 2m
hostnames-632524106-ly40y 1/1 Running 0 2m
hostnames-632524106-tlaok 1/1 Running 0 2m
```
## Serviceは存在するか?
賢明な読者は、`Service`をまだ実際に作成していないことにお気付きかと思いますが、これは意図的です。これは時々忘れられるステップであり、最初に確認すべきことです。
では、存在しない`Service`にアクセスしようとするとどうなるでしょうか?
この`Service`を名前で利用する別の`Pod`があると仮定すると、次のような結果が得られます。
Podが昨日していることも確認できます。
Pod IP アドレスリストを取得し、直接テストできます。
```shell
u@pod$ wget -O- hostnames
kubectl get pods -l run=hostnames \
-o go-template='{{range .items}}{{.status.podIP}}{{"\n"}}{{end}}'
```
```none
10.244.0.5
10.244.0.6
10.244.0.7
```
このウォークスルーに使用されるサンプルコンテナは、ポート9376でHTTPを介して独自のホスト名を提供するだけですが、独自のアプリをデバッグする場合は、Podがリッスンしているポート番号を使用する必要があります。
Pod内から実行します。
```shell
for ep in 10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376; do
wget -qO- $ep
done
```
次のように表示されます。
```
hostnames-0uton
hostnames-bvc05
hostnames-yp2kp
```
この時点で期待通りの応答が得られない場合、Podが正常でないか、想定しているポートでリッスンしていない可能性があります。
なにが起きているかを確認するために`kubectl logs`が役立ちます、Podに直接に入りデバッグする場合は `kubectl exec`が必要になります。
これまでにすべての計画が完了していると想定すると、Serviceが機能しない理由を調査することができます。
## Serviceは存在するか?
賢明な読者は、Serviceをまだ実際に作成していないことにお気付きかと思いますが、これは意図的です。これは時々忘れられるステップであり、最初に確認すべきことです。
存在しないServiceにアクセスしようとするとどうなるでしょうか?
このServiceを名前で利用する別のPodがあると仮定すると、次のような結果が得られます。
```shell
wget -O- hostnames
```
```none
Resolving hostnames (hostnames)... failed: Name or service not known.
wget: unable to resolve host address 'hostnames'
```
そのため、最初に確認するのは、その`Service`が実際に存在するかどうかです。
最初に確認するのは、そのServiceが実際に存在するかどうかです。
```shell
kubectl get svc hostnames
```
```none
No resources found.
Error from server (NotFound): services "hostnames" not found
```
犯人がいましたので、`Service`を作成しましょう。
前と同様に、これはウォークスルー用です。ご自身の`Service`の詳細を使用することもできます。
Serviceを作成しましょう。
前と同様に、これはウォークスルー用です。ご自身のServiceの詳細を使用することもできます。
```shell
kubectl expose deployment hostnames --port=80 --target-port=9376
```
```none
service/hostnames exposed
```
@@ -144,11 +160,16 @@ service/hostnames exposed
```shell
kubectl get svc hostnames
```
```none
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hostnames ClusterIP 10.0.1.175 <none> 80/TCP 5s
```
前と同様に、これは次のようなYAMLで`Service`を開始した場合と同じです
これで、Serviceが存在することがわかりました
{{< note >}}
前と同様に、これは次のようなYAMLでServiceを開始した場合と同じです。
```yaml
apiVersion: v1
@@ -165,35 +186,45 @@ spec:
targetPort: 9376
```
これで、`Service`が存在することが確認できました
構成の全範囲をハイライトするため、ここで作成したServiceはPodとは異なるポート番号を市湯します
多くの実際のServiceでは、これらのポートは同じになる場合があります。
{{< /note >}}
## サービスはDNSによって機能しているか?
## サービスはDNSによって機能しているか?
同じ`Namespace``Pod`から次のコマンドを実行してください
クライアントがサービスを使用する最も一般的な方法の1つは、DNS名を使用することです
同じNamespaceのPodから次のコマンドを実行してください。
```shell
u@pod$ nslookup hostnames
nslookup hostnames
```
```none
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: hostnames
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local
```
これが失敗した場合、おそらく`Pod``Service`が異なる`Namespace`にあるため、ネームスペースで修飾された名前を試してください。
これが失敗した場合、おそらくPodServiceが異なるNamespaceにあるため、ネームスペースで修飾された名前を試してください。(Podの中からもう一度)
```shell
u@pod$ nslookup hostnames.default
nslookup hostnames.default
```
```none
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: hostnames.default
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local
```
これが機能する場合、クロスネームスペース名を使用するようにアプリケーションを調整するか、同じ`Namespace`でアプリと`Service`を実行する必要があります。
これが機能する場合、クロスネームスペース名を使用するようにアプリケーションを調整するか、同じNamespaceでアプリとServiceを実行する必要があります。
これでも失敗する場合は、完全修飾名を試してください。
```shell
u@pod$ nslookup hostnames.default.svc.cluster.local
nslookup hostnames.default.svc.cluster.local
```
```none
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: hostnames.default.svc.cluster.local
@@ -201,18 +232,20 @@ Address 1: 10.0.1.175 hostnames.default.svc.cluster.local
```
ここでのサフィックス"default.svc.cluster.local"に注意してください。
"default"は、操作している`Namespace`です。
"svc"は、これが`Service`であることを示します。
"default"は、操作しているNamespaceです。
"svc"は、これがServiceであることを示します。
"cluster.local"はクラスタードメインであり、あなたのクラスターでは異なる場合があります。
クラスター内の`ノード`からも試すこともできます。
クラスター内のノードからも試すこともできます。
{{< note >}}
10.0.0.10は私のDNS `Service`であり、あなたのクラスターでは異なるかもしれません。
10.0.0.10はクラスターのDNSサービスのIPであり、あなたのクラスターでは異なるかもしれません。
{{< /note >}}
```shell
u@node$ nslookup hostnames.default.svc.cluster.local 10.0.0.10
nslookup hostnames.default.svc.cluster.local 10.0.0.10
```
```none
Server: 10.0.0.10
Address: 10.0.0.10#53
@@ -220,16 +253,22 @@ Name: hostnames.default.svc.cluster.local
Address: 10.0.1.175
```
完全修飾名では検索できるのに、相対名ではできない場合、`/etc/resolv.conf`ファイルが正しいことを確認する必要があります。
完全修飾名では検索できるのに、相対名ではできない場合、Podの`/etc/resolv.conf`ファイルが正しいことを確認する必要があります。
Pod内から実行します。
```shell
u@pod$ cat /etc/resolv.conf
cat /etc/resolv.conf
```
次のように表示されます。
```
nameserver 10.0.0.10
search default.svc.cluster.local svc.cluster.local cluster.local example.com
options ndots:5
```
`nameserver`行はクラスターのDNS `Service`を示さなければなりません。
nameserver行はクラスターのDNS Serviceを示さなければなりません。
これは、`--cluster-dns`フラグで`kubelet`に渡されます。
`search`行には、`Service`名を見つけるための適切なサフィックスを含める必要があります。
@@ -242,14 +281,17 @@ options ndots:5
`options`行では、DNSクライアントライブラリーが検索パスをまったく考慮しないように`ndots`を十分に高く設定する必要があります。
Kubernetesはデフォルトでこれを5に設定します。これは、生成されるすべてのDNS名をカバーするのに十分な大きさです。
### ServiveはDNSに存在するか?
### DNS名で機能するServiceはありますか? {#does-any-service-exist-in-dns}
上記がまだ失敗する場合、DNSルックアップが`Service`に対して機能していません。
上記がまだ失敗する場合、DNSルックアップがServiceに対して機能していません。
一歩離れて、他の何が機能していないかを確認しましょう。
Kubernetesマスターの`Service`は常に機能するはずです。
KubernetesマスターのServiceは常に機能するはずです。
Pod内から実行します。
```shell
u@pod$ nslookup kubernetes.default
nslookup kubernetes.default
```
```none
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
@@ -257,31 +299,34 @@ Name: kubernetes.default
Address 1: 10.0.0.1 kubernetes.default.svc.cluster.local
```
これが失敗した場合、このドキュメントのkube-proxyセクションに移動するか、あるいは、このドキュメントの先頭に戻って最初からやり直し、あなた自身の`Service`をデバッグする代わりにDNSをデバッグする必要があるかもしれません
これが失敗する場合、このドキュメントの [kube-proxy](#is-the-kube-proxy-working)セクションを参照するか、このドキュメントの先頭に戻って最初からやり直してください。ただし、あなた自身のServiceをデバッグするのではなく 、DNSサービスをデバッグします
## ServiceはIPでは機能するか?
DNSが機能することを確認できると仮定すると、次にテストするのは`Service`が機能しているかどうかです。
上述の`kubectl get`で確認できる`Service`IPに、クラスター内のノードからアクセスします。
DNSサービスが正しく動作できると仮定すると、次にテストするのはIPによってServiceが動作しているかです。
上述の`kubectl get`で確認できるIPに、クラスター内のPodからアクセスします。
```shell
u@node$ curl 10.0.1.175:80
hostnames-0uton
u@node$ curl 10.0.1.175:80
hostnames-yp2kp
u@node$ curl 10.0.1.175:80
hostnames-bvc05
for i in $(seq 1 3); do
wget -qO- 10.0.1.175:80
done
```
`Service`が機能している場合は、正しい応答が得られるはずです。
次のように表示されます。
```
hostnames-0uton
hostnames-bvc05
hostnames-yp2kp
```
Serviceが機能している場合は、正しい応答が得られるはずです。
そうでない場合、おかしい可能性のあるものがいくつかあるため、続けましょう。
## Serviceは正しか?
## Serviceは正しく定義されているか?
馬鹿げているように聞こえるかもしれませんが、`Service`が正しく定義され`Pod`のポートとマッチすることを二度、三度と確認すべきです。
`Service`を読み返して確認しましょう。
馬鹿げているように聞こえるかもしれませんが、Serviceが正しく定義されPodのポートとマッチすることを二度、三度と確認すべきです。
Serviceを読み返して確認しましょう。
```shell
kubectl get service hostnames -o json
@@ -297,7 +342,7 @@ kubectl get service hostnames -o json
"resourceVersion": "347189",
"creationTimestamp": "2015-07-07T15:24:29Z",
"labels": {
"app": "hostnames"
"run": "hostnames"
}
},
"spec": {
@@ -311,7 +356,7 @@ kubectl get service hostnames -o json
}
],
"selector": {
"app": "hostnames"
"run": "hostnames"
},
"clusterIP": "10.0.1.175",
"type": "ClusterIP",
@@ -323,98 +368,102 @@ kubectl get service hostnames -o json
}
```
* アクセスしようとしているポートは`spec.ports[]`に定義されていますか?
* `targetPort``Pod`に対して適切ですか(多くの`Pod``Service`とは異なるポートを使用することを選択します)
* アクセスしようとしているServiceポートは`spec.ports[]`のリストのなかに定義されていますか?
* `targetPort`はPodに対して適切ですか(いくつかのPodはServiceとは異なるポートを使用します)?
* `targetPort`を数値で定義しようとしている場合、それは数値(9376)、文字列"9376"のどちらですか?
* `targetPort`を名前で定義しようとしている場合、`Pod`は同じ名前でポートを公開していますか?
* ポートの`protocol``Pod`のものと同じですか?
* `targetPort`を名前で定義しようとしている場合、Podは同じ名前でポートを公開していますか?
* ポートの`protocol`はPodに適切ですか?
## ServiceにEndpointsがあるか?
ここまで来たということは、`Service`は存在し、DNSによって名前解決できることが確認できているでしょう。
ここでは、実行した`Pod``Service`によって実際に選択されていることを確認しましょう。
ここまで来たということは、Serviceは正しく定義され、DNSによって名前解決できることが確認できているでしょう。
ここでは、実行したPodServiceによって実際に選択されていることを確認しましょう。
以前に、`Pod`が実行されていることを確認しました。再確認しましょう。
以前に、Podが実行されていることを確認しました。再確認しましょう。
```shell
kubectl get pods -l app=hostnames
kubectl get pods -l run=hostnames
```
```none
NAME READY STATUS RESTARTS AGE
hostnames-0uton 1/1 Running 0 1h
hostnames-bvc05 1/1 Running 0 1h
hostnames-yp2kp 1/1 Running 0 1h
```
`-l run=hostnames`引数はラベルセレクターで、ちょうど私たちの`Service`に定義されているものと同じです。
"AGE"列は、これらの`Pod`が約1時間前のものであることを示しており、それらが正常に実行され、クラッシュしていないことを意味します。
"AGE"列は、これらのPodが約1時間前のものであることを示しており、それらが正常に実行され、クラッシュしていないことを意味します。
`-l app=hostnames`引数はラベルセレクターで、ちょうど私たちの`Service`に定義されているものと同じです。
Kubernetesシステム内には、すべての`Service`のセレクターを評価し、結果を`Endpoints`オブジェクトに保存するコントロールループがあります
"RESTARTS"列は、これらのポッドが頻繁にクラッシュしたり、再起動されていあいことを示しています。 頻繁に再起動すると、断続的な接続性の問題が発生する可能性があります。
再起動回数が多い場合は、[ポッドをデバッグする](/ja/docs/tasks/debug-application-cluster/debug-pod-replication-controller/#podのデバッグ)を参照してください
Kubernetesシステム内には、すべてのServiceのセレクターを評価し、結果をEndpointsオブジェクトに保存するコントロールループがあります。
```shell
kubectl get endpoints hostnames
NAME ENDPOINTS
hostnames 10.244.0.5:9376,10.244.0.6:9376,10.244.0.7:9376
```
これにより、Endpointsコントローラーが`Service`の正しい`Pod`を見つけていることを確認できます。
`hostnames`行が空白の場合、`Service``spec.selector`フィールドが実際に`Pod``metadata.labels`値を選択していることを確認する必要があります。
よくある間違いは、タイプミスまたは他のエラー、たとえば`Service``run=hostnames`を選択しているのに`Deployment``app=hostnames`を指定していることです。
これにより、EndpointsコントローラーがServiceの正しいPodを見つけていることを確認できます。
`ENDPOINTS`列が`<none>`の場合、Serviceの`spec.selector`フィールドが実際にPodの`metadata.labels`値を選択していることを確認する必要があります。
よくある間違いは、タイプミスまたは他のエラー、たとえばServiceが`app=hostnames`を選択しているのにDeploymentが`run=hostnames`を指定していることです。
## Podは機能しているか?
この時点で、`Service`が存在し、`Pod`を選択していることがわかります。
`Pod`が実際に機能していることを確認しましょう。`Service`メカニズムをバイパスして、`Pod`に直接アクセスすることができます
この時点で、Serviceが存在し、Podを選択していることがわかります。
このウォークスルーの最初に、Pod自体を確認しました
Podが実際に機能していることを確認しましょう。Serviceメカニズムをバイパスして、上記EndpointsにリストされているPodに直接アクセスすることができます。
{{< note >}}
これらのコマンドは、`Service`ポート(80)ではなく、`Pod`ポート(9376)を使用します。
これらのコマンドは、Serviceポート(80)ではなく、Podポート(9376)を使用します。
{{< /note >}}
Pod内から実行します。
```shell
u@pod$ wget -qO- 10.244.0.5:9376
for ep in 10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376; do
wget -qO- $ep
done
```
次のように表示されます。
```
hostnames-0uton
pod $ wget -qO- 10.244.0.6:9376
hostnames-bvc05
u@pod$ wget -qO- 10.244.0.7:9376
hostnames-yp2kp
```
```
`Endpoints`リスト内の各`Pod`は、それぞれの自身のホスト名を返すはずです。
そうならない(または、あなた自身の`Pod`の正しい振る舞いにならない)場合は、そこで何が起こっているのかを調査する必要があります。
`kubectl logs`が役立つかもしれません。あるいは、`kubectl exec`で直接`Pod`にアクセスし、そこでサービスをチェックしましょう。
Endpointsリスト内の各Podは、それぞれの自身のホスト名を返すはずです。
そうならない(または、あなた自身のPodの正しい振る舞いにならない)場合は、そこで何が起こっているのかを調査する必要があります。
もう1つ確認すべきことは、`Pod`がクラッシュしたり、再起動されていないことです。
頻繁に再起動されていると、断続的な接続の問題が発生する可能性があります。
## kube-proxyは機能しているか? {#is-the-kube-proxy-working}
```shell
kubectl get pods -l app=hostnames
NAME READY STATUS RESTARTS AGE
hostnames-632524106-bbpiw 1/1 Running 0 2m
hostnames-632524106-ly40y 1/1 Running 0 2m
hostnames-632524106-tlaok 1/1 Running 0 2m
```
再起動回数が多い場合は、[Podをデバッグする](/ja/docs/tasks/debug-application-cluster/debug-pod-replication-controller/#podのデバッグ)方法の詳細をご覧ください。
## kube-proxyは機能しているか?
ここに到達したのなら、`Service`は実行され、`Endpoints`があり、`Pod`が実際にサービスを提供しています。
この時点で、`Service`のプロキシーメカニズム全体が疑わしいです。
ここに到達したのなら、Serviceは実行され、Endpointsがあり、Podが実際にサービスを提供しています。
この時点で、Serviceのプロキシーメカニズム全体が疑わしいです。
ひとつひとつ確認しましょう。
Serviceのデフォルト実装、およびほとんどのクラスターで使用されるものは、kube-proxyです。
kube-proxyはそれぞれのノードで実行され、サービスの抽象化を提供するための小さなメカニズムセットの1つを構成するプログラムです。
クラスターがkube-proxyを使用しない場合、以下のセクションは適用されず、使用しているServiceの実装を調査する必要があります。
### kube-proxyは実行されているか?
`kube-proxy``ノード`上で実行されていることを確認しましょう。
以下のような結果が得られるはずです。
`kube-proxy`ノード上で実行されていることを確認しましょう。
ノードで実行されていれば、以下のような結果が得られるはずです。
```shell
u@node$ ps auxw | grep kube-proxy
root 4194 0.4 0.1 101864 17696 ? Sl Jul04 25:43 /usr/local/bin/kube-proxy --master=https://kubernetes-master --kubeconfig=/var/lib/kube-proxy/kubeconfig --v=2
ps auxw | grep kube-proxy
```
```none
root 4194 0.4 0.1 101864 17696 ? Sl Jul04 25:43 /usr/local/bin/kube-proxy --master=https://kubernetes-master --kubeconfig=/var/lib/kube-proxy/kubeconfig --v=2
```
次に、マスターとの接続など、明らかな失敗をしていないことを確認します。
これを行うには、ログを確認する必要があります。
ログへのアクセス方法は、`ノード`のOSに依存します。
ログへのアクセス方法は、ノードのOSに依存します。
一部のOSでは/var/log/kube-proxy.logのようなファイルですが、他のOSでは`journalctl`を使用してログにアクセスします。
次のように表示されます。
@@ -431,39 +480,23 @@ I1027 22:14:54.040154 5063 proxier.go:294] Adding new service "kube-system/ku
I1027 22:14:54.040223 5063 proxier.go:294] Adding new service "kube-system/kube-dns:dns-tcp" at 10.0.0.10:53/TCP
```
マスターに接続できないことに関するエラーメッセージが表示された場合、`ノード`の設定とインストール手順をダブルチェックする必要があります。
マスターに接続できないことに関するエラーメッセージが表示された場合、ノードの設定とインストール手順をダブルチェックする必要があります。
`kube-proxy`が正しく実行できない理由の可能性の1つは、必須の`conntrack`バイナリが見つからないことです。
これは、例えばKubernetesをスクラッチからインストールするなど、クラスターのインストール方法に依存して、一部のLinuxシステムで発生する場合があります。
これが該当する場合は、`conntrack`パッケージを手動でインストール(例: Ubuntuでは`sudo apt install conntrack`)する必要があり、その後に再試行する必要があります。
### kube-proxyiptablesルールを書いているか?
Kube-proxyは、いくつかのモードのいずれかで実行できます。 上記のログの`Using iptables Proxier`という行は、kube-proxyが「iptables」モードで実行されていることを示しています。
最も一般的な他のモードは「ipvs」です。 古い「ユーザースペース」モードは、主にこれらに置き換えられました。
`kube-proxy`の主な責務の1つは、`Service`を実装する`iptables`ルールを記述することです。
それらのルールが書かれていることを確認しましょう。
#### Iptables mode
kube-proxyは、"userspace"モード、"iptables"モード、または"ipvs"モードで実行できます。
あなたが"iptables"モードまたは"ipvs"モードを使用していることを願います。
続くケースのいずれかが表示されるはずです。
#### Userspace
iptablesモードでは、ノードに次のようなものが表示されます。
```shell
u@node$ iptables-save | grep hostnames
-A KUBE-PORTALS-CONTAINER -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j REDIRECT --to-ports 48577
-A KUBE-PORTALS-HOST -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j DNAT --to-destination 10.240.115.247:48577
iptables-save | grep hostnames
```
`Service`の各ポート毎(この例では1つ)に2つのルールがあるはずです。
"KUBE-PORTALS-CONTAINER"と"KUBE-PORTALS-HOST"です。
これらが表示されない場合は、`-v`フラグを4に設定して`kube-proxy`を再起動してから、もう一度ログを確認してください。
"userspace"モードを使用する必要がある人ほとんどないため、ここではこれ以上の時間を費やしません。
#### Iptables
```shell
u@node$ iptables-save | grep hostnames
```none
-A KUBE-SEP-57KPRZ3JQVENLNBR -s 10.244.3.6/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-57KPRZ3JQVENLNBR -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.3.6:9376
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -s 10.244.1.7/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
@@ -476,13 +509,18 @@ u@node$ iptables-save | grep hostnames
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -j KUBE-SEP-57KPRZ3JQVENLNBR
```
`KUBE-SERVICES`に1つのルールがあり、`KUBE-SVC-(hash)`のエンドポイント毎に1つまたは2つのルールがあり(`SessionAffinity`に依存)、エンドポイント毎に1つの`KUBE-SEP-(hash)`チェーンがあり、 そしてそれぞれの`KUBE-SEP-(hash)`チェーンにはいくつかのルールがあるはずです。
正確なルールは、あなたの正確な構成(NodePortとLoadBalancerを含む)によって異なります。
各サービスのポートごとに、 `KUBE-SERVICES`に1つのルールと1つの` KUBE-SVC- <hash> `チェーンが必要です。
Podエンドポイントごとに、その `KUBE-SVC- <hash>`に少数のルールがあり、少数のルールが含まれる1つの `KUBE-SEP- <hash>`チェーンがあるはずです。
正確なルールは、正確な構成(NodePortとLoadBalancerを含む)に基づいて異なります。
#### IPVS
#### IPVS mode
「ipvs」モードでは、ノードに次のようなものが表示されます。
```shell
u@node$ ipvsadm -ln
ipvsadm -ln
```
```none
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
...
@@ -493,39 +531,66 @@ TCP 10.0.1.175:80 rr
...
```
各Serviceの各ポートに加えて、NodePort、External IP、およびLoad Balancer IPに対して、kube-proxyは仮想サーバーを作成します。
Pod endpointごとに、対応する実サーバーが作成されます。
この例では, サービスhostnames(`10.0.1.175:80`) は3つのendpoints(`10.244.0.5:9376`,`10.244.0.6:9376`, `10.244.0.7:9376`)を持っています。
IPVSプロキシーは、各Serviceアドレス(Cluster IP、External IP、NodePort IP、Load Balancer IPなど)毎の仮想サーバーと、Serviceのエンドポイントが存在する場合に対応する実サーバーを作成します。
この例では、hostnames Service(`10.0.1.175:80`)は3つのエンドポイント(`10.244.0.5:9376``10.244.0.6:9376``10.244.0.7:9376`)を持ち、上と似た結果が得られるはずです。
### kube-proxyはプロキシしているか?
#### Userspace mode
上記のルールが表示されていると仮定すると、もう一度IPを使用して`Service`へのアクセスを試してください
まれに、「userspace」モードを使用している場合があります
ノードから実行します。
```shell
u@node$ curl 10.0.1.175:80
iptables-save | grep hostnames
```
```none
-A KUBE-PORTALS-CONTAINER -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j REDIRECT --to-ports 48577
-A KUBE-PORTALS-HOST -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j DNAT --to-destination 10.240.115.247:48577
```
サービスの各ポートには2つのルールが必要です(この例では1つだけ)-「KUBE-PORTALS-CONTAINER」と「KUBE-PORTALS-HOST」です。
「userspace」モードを使用する必要はほとんどないので、ここでこれ以上時間を費やすことはありません。
### kube-proxyはプロキシしているか?
上記のいずれかが発生したと想定して、いずれかのノードからIPでサービスにアクセスをしています。
```shell
curl 10.0.1.175:80
```
```none
hostnames-0uton
```
もしこれが失敗し、あなたがuserspaceプロキシーを使用している場合、プロキシーへの直接アクセスを試してみてください。
もしiptablesプロキシーを使用している場合、このセクションはスキップしてください。
上記の`iptables-save`の出力を振り返り、`kube-proxy``Service`に使用しているポート番号を抽出します。
上記の`iptables-save`の出力を振り返り、`kube-proxy`がServiceに使用しているポート番号を抽出します。
上記の例では"48577"です。このポートに接続してください。
```shell
u@node$ curl localhost:48577
curl localhost:48577
```
```none
hostnames-yp2kp
```
もしまだ失敗する場合は、`kube-proxy`ログで次のような特定の行を探してください。
```shell
```none
Setting endpoints for default/hostnames:default to [10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376]
```
これらが表示されない場合は、`-v`フラグを4に設定して`kube-proxy`を再起動してから、再度ログを確認してください。
### PodService IPを介して自分自身にアクセスできない
### エッジケース: PodService IP経由で自身に到達できない。 {#a-pod-fails-to-reach-itself-via-the-service-ip}
これはありそうに聞こえないかもしれませんが、実際には起こり、動作するはずです。
これはネットワークが"hairpin"トラフィック用に適切に設定されていない場合、通常は`kube-proxy``iptables`モードで実行され、Podがブリッジネットワークに接続されている場合に発生します。
`Kubelet``hairpin-mode`[フラグ](/docs/admin/kubelet/)を公開します。
これにより、Serviceのエンドポイントが自身のServiceのVIPにアクセスしようとした場合に、自身への負荷分散を可能にします。
@@ -537,9 +602,10 @@ Setting endpoints for default/hostnames:default to [10.244.0.5:9376 10.244.0.6:9
次のような表示がされるはずです。この例では、`hairpin-mode``promiscuous-bridge`に設定されています。
```shell
u@node$ ps auxw|grep kubelet
ps auxw | grep kubelet
```
```none
root 3392 1.1 0.8 186804 65208 ? Sl 00:51 11:11 /usr/local/bin/kubelet --enable-debugging-handlers=true --config=/etc/kubernetes/manifests --allow-privileged=True --v=4 --cluster-dns=10.0.0.10 --cluster-domain=cluster.local --configure-cbr0=true --cgroup-root=/ --system-cgroups=/system --hairpin-mode=promiscuous-bridge --runtime-cgroups=/docker-daemon --kubelet-cgroups=/kubelet --babysit-daemons=true --max-pods=110 --serialize-image-pulls=false --outofdisk-transition-frequency=0
```
* 実際に使われている`hairpin-mode`を確認します。
@@ -550,7 +616,7 @@ root 3392 1.1 0.8 186804 65208 ? Sl 00:51 11:11 /usr/local/bin/
kubelet.logにキーワード`hairpin`を含むログ行があるかどうかを確認してください。
実際に使われている`hairpin-mode`を示す以下のようなログ行があるはずです。
```shell
```none
I0629 00:51:43.648698 3252 kubelet.go:380] Hairpin mode set to "promiscuous-bridge"
```
@@ -559,6 +625,8 @@ I0629 00:51:43.648698 3252 kubelet.go:380] Hairpin mode set to "promiscuous-b
```shell
for intf in /sys/devices/virtual/net/cbr0/brif/*; do cat $intf/hairpin_mode; done
```
```none
1
1
1
@@ -569,9 +637,10 @@ for intf in /sys/devices/virtual/net/cbr0/brif/*; do cat $intf/hairpin_mode; don
`cbr0`ブリッジが使用され適切に構成されている場合、以下が表示されます。
```shell
u@node$ ifconfig cbr0 |grep PROMISC
ifconfig cbr0 |grep PROMISC
```
```none
UP BROADCAST RUNNING PROMISC MULTICAST MTU:1460 Metric:1
```
* 上記のいずれも解決しない場合、助けを求めてください。
@@ -579,9 +648,9 @@ UP BROADCAST RUNNING PROMISC MULTICAST MTU:1460 Metric:1
## 助けを求める
ここまでたどり着いたということは、とてもおかしなことが起こっています。
`Service`は実行中で、`Endpoints`があり、`Pod`は実際にサービスを提供しています。
DNSは動作していて、`iptables`ルールがインストールされていて、`kube-proxy`も誤動作していないようです。
それでも、あなたの`Service`は機能していません。
Serviceは実行中で、Endpointsがあり、Podは実際にサービスを提供しています。
DNSは動作していて、`kube-proxy`も誤動作していないようです。
それでも、あなたのServiceは機能していません。
おそらく私たちにお知らせ頂いた方がよいでしょう。調査をお手伝いします!
[Slack](/docs/troubleshooting/#slack)または